• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Object Orientation vs. Functional Programming in Python
 

Object Orientation vs. Functional Programming in Python

on

  • 379 views

Python is a multi-paradigm language meaning it supports different programming styles, Object Orientation and Functional Programming being the major ones. However choice is not always a good thing, if ...

Python is a multi-paradigm language meaning it supports different programming styles, Object Orientation and Functional Programming being the major ones. However choice is not always a good thing, if you are interested in writing modular programs that are easy to maintain and promote code reuse what should you do? This talk discusses modularity in this context looking at Python's support for both paradigms, comparing and contrasting them. We then look at Python techniques and tools that bridge the perceived impedance mismatch between Object Orientation and Functional Programming.

Statistics

Views

Total Views
379
Views on SlideShare
379
Embed Views
0

Actions

Likes
1
Downloads
10
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • - Software Engineer at DemonWare - Online Services for some of the worlds most popular games, as well game online experiences like COD Elite - Python is one of our core technologies. - We're hiring!
  • The sub-title of this talk is writing modular python programs. What do I mean by modularity and why do we want it? I don't want to make too much of a song and dance about it, because I think it is an obvious goal and programming languages have always been trying to help us achieve it. Never the less I think it is useful to at least loosely define it. We want the code we write to be individual components that do one job. That allows us to recombine those bits in different ways to solve new problems. We can build new stuff, making use of what we built before repeating ourselves as little as possible. To achieve this there are some properties our code needs to have. If there is an idea/concern we dealing with we would like that be expressed in as few places as possible ideally one. Conversely if we have a single module/class/method it would be better if it dealt with one concern rather than being cluttered with many different concerns. The diagrams on the screen try to illustrate this point. If each colour represents a particular concern we see that is scattered all over the place, if you were assigned the task of modifying the functionality represented by the yellow bits that would be a pretty annoying, grep helps but we would rather not be in that position in the first place. It is similarly problematic to have modules like we have on the left, in which lots of concerns are tangled together. One has to be aware of all the concerns in the module to change just one of them, or run the risk of inadvertently breaking other stuff that just happens to be near by. If you have ever had to say but I only changed the comments you know what I am talking about. Instead what we want is what we have on the right. Modules that related but separate, with each module dealing with a particular concern. If we can achieve that we can better reuse, re-purpose and extend our code to solve new problems. This is the open-closed principle ( should be open for extension, but closed for modification ). We should only modify a component when it's intrinsic behaviour changes, all other extension ideally should be made from the outside.   I think most modern programming languages provide features that help us achieve that goal. They succeed to varying degrees, we are going to look at some of the ways Python helps us do this.
  • - I am not a classical rhetorician, but I aspire to play one on TV. The structure of classical rhetorical argument requires us to present the thesis, then explore the antithesis, and finally present the synthesis   - We are going take an example based approach, taking a look at a few Python OO and FP features that exemplify the point I am trying to make.   - Some of the examples themselves are taken mostly taken from the Python standard library, not so much the internals buy how we are supposed to use it. This is useful because the standard library (or any library for that matter) necessarily needs to extensible and reusable from the outside without modifying the library itself.
  • Python OO, it is class oriented like most OO languages there are so exceptions that are prototype based a notable one being javascript, but are some others like self. - So OO is packaging state and behaviour generally to achive 3 things: 1. delegation which explicitly or implicitly passing on the responsibility of performing an action to somewhere else. implicit when you lookup an attribute: instance -> class class -> base classes explicit: delegating to another object that we have a reference to or even explicit delegation delegation to the object itself 2. Polymorphism allowing objects to act like other objects depending on the context. 3. Instantiation that is essentially having one blueprint that can be used to create many instances. - That is really all I am going to say about OO in general, I am kind of assuming we are all familiar with the basics of OO in Python.
  • - base class offers "organizing method" which calls "hook methods" - in base class, most hook methods stay abstract - concrete subclasses implement the hooks - client code calls organizing method - A couple of things to note the Chess class does not specialise the winner printing; Data overriding something we cad do in python but not in many other languages   Mention how this structure would be hard to recreate with functions only, the obviousness of what is required is great.
  • The methods on a dict do not necessarily call the methods you would expect. The reason for this is that python needs to protect the internal invariants of collections to prevent crashes. So the internal calling patterns are not obvious. ABC declare these constraints in an obvious way. This is really a variant of the template method design pattern with the sort of checks you would normally get in a staticly typed language. This still of course happens at runtime, but the failure is early, obvious and descriptive. Better still using an abc allows your code to move with the language. Because abc define the minimum set of the methods for each type. All other methods can be implemented in terms of these. You can override more methods to do things more efficiently, but if you don't things will still work.   The abc's really provide structured modularity and extendibility. We can extend them in ways that are sure to be consistent with intention of the base class.
  • This can be thought of a form of the template method design pattern. Except the organising methods come from one or more base classes.   Inheriting from a mixin is not a form of specialization but is rather a means of collecting functionality. A class may inherit most or all of its functionality from one or more mixins through multiple inheritance .   Diamond problem: Python creates a list of a classes using the C3 linearization algorithm. That algorithm enforces two constraints: children precede their parents and if a class inherits from multiple classes, they are kept in the order specified in the tuple of base classes. Thus, the method resolution order is: D, B, C, A
  • No discussion of multiple inheritance is complete without mentioning the "Diamon Problem"   The diamond problem such as it is, is In object-oriented programming languages with multiple inheritance and knowledge organization , the diamond problem is an ambiguity that arises when two classes B and C inherit from A, and class D inherits from both B and C. If a method in D calls a method defined in A (and does not override the method), and B and C have overridden that method differently, then from which class does it inherit: B, or C? A well designed language needs to have a deterministic resolution to this ambiguity. Python creates a list of a classes using the C3 linearization algorithm. That algorithm enforces two constraints: children precede their parents and if a class inherits from multiple classes, they are kept in the order specified in the tuple of base classes. Thus, the method resolution order is: D, B, C, A   Personally I think it is a mistake to rely on this order even it is deterministic. This situation can avoided in most cases just by taking care what you inherit from. Since the main reason for mixins is to get functionality defined in another class if inheritance is causing problems it may be time to consider composition instead.
  • The design patterns literature. talks about preferring composition over inheritance. There is a good reason for this, for one thing inheritance always  expands the interface of the subclass with all of the parents attributes this may not always be what you want, especially if the base class is just a service that you may want to swap out in the in end. Inheritance cannot restrict it can only expand. This is a general mechanism but specific things you may be trying to achieve is to adapt or proxy some object. In all these cases though the general mechanism is the same. It is useful to distinguish between them (as is done in design patterns literature) to help in deciding when to apply the technique. However at the level of abstraction we are working today
  • The design patterns literature. talks about preferring composition over inheritance. There is a good reason for this, for one thing inheritance always  expands the interface of the subclass with all of the parents attributes this may not always be what you want, especially if the base class is just a service that you may want to swap out in the in end. Inheritance cannot restrict it can only expand. This is a general mechanism but specific things you may be trying to achieve is to adapt or proxy some object. In this example say had a lot of code that knows how to deal with file like objects (perhaps it uses context lib closing()This is a way to reuse code in a context that it would not otherwise be usable, by creating a very thin wrapper.
  • python def __getattr__(self, n) magic really make life easy for us, how does this help modularity well we only need to specify what we care about and the whole world making this a lot easier to change
  • python def __getattr__(self, n) magic really make life easy for us, how does this help modularity well we only need to specify what we care about and the whole world making this a lot easier to change
  • - I am not a classical rhetorician, but I aspire to play one on TV. The structure of classical rhetorical argument requires us to present the thesis, then explore the antithesis, and finally present the synthesis   - We are going take an example based approach, taking a look at a few Python OO and FP features that exemplify the point I am trying to make.   - The examples themselves are taken mostly taken from the Python standard library, not so much the internals buy how we are supposed to use it. This is useful because the standard library (or any library for that matter) necessarily needs to extensible and reusable from the outside without modifying the library itself.
  • - In functional programming Functions are the primary means of abstraction. Programs are decomposed into a set of functions, that take some input and produce some output.   - Ideally a function should compute outputs from its inputs and do nothing else. That is takes values and produces new values. No mutable shareable state should be modified as the result of calling a function. Pure functional languages are strict about side effect freeness. (The type systems in such languages are used to control the limited amount of necessary side effects).   - This purity is what gives functional languages some of advantages you sometime here mentioned like provable program correctness. Also since side effects are limited or none existent, functional languages are very useful for concurrent programming.   - Python is not a pure functional language, because the language does permit side effects. Assignment of values to names which is not possible in pure functional languages is commonplace in Python program.    - Rather It is a language the supports functional style programming. The main thing that makes this possible is the fact that the language supports higher order functions (and other callables as we shall see later). That is functions are first class objects. So we can functions that accept other functions as inputs and even return functions as outputs.   - Never the less we can get pretty for with the less draconian functional support we have in python.
  • One of the first examples most people encounter is programming python in a function style is callbacks. Before we take a look at some examples to make it more concrete let briefly discuss the concept of a callback. for: customization (flexibility)    "event-driven" architectures ("actual" events such as in GUI or network programming OR "pseudo" events for structuring of control-flow, a common example being a SAX XML parser.   This style of programming really begs for first class callables. The same effect can be achieved in other languages using interfaces, or functor objects or anonymous classes and so on, just to get around the lack of higher order functions.
  • Mention how simple this is to achieve because we are not encumbered by unnecessary OO infrastructure.   Imagine create a subclass of list with different sorting, or subclasses of the objects you are comparing to implement __eq__ and __lt__, this would result in a combinatorial explosion of different subclasses to do sort by different combinations of fields.
  • The sorted function is a higher order function, it accepts a function as its key argument and uses that key to customise how it does the sorting, that is rather than using the natural order of the class as defined by lt and eq.   Notice how much more flexible this is you can easily switch between sorting mechanisms. More importantly the users of the person class can easily sort this object in ways not envisaged by the creator of the class without having to modify or subclass the class itself. Remember our modularity goals, see how that fits in here? Some creates a class we can customise it behaviour from the outside.
  • why write your own functions when all of pythons operators are available to you as functions itemgetter and attrgetter are examples of higher order functions, they return functions (or callables) as their results.   sorted requires a function that it can call we wrote a simple one for ourselves but this code was basically boilerplate that would have to be repeated. The operators in python can really be viewed as functions, they take operands (arguments) and produce results. There are many operators in Python which would be valuable viewed in this way.    The operator module does just that. The . operator is no execption and we can use it in our previous example. This is a higher order function its result is a function the extracts the field of the specified name from any object passed in. These and many more are available, they really come into their own in combination with what we are going to discuss in the next section.
  • A powerful feature of functional programs is the ability to declare that we would like to do something to a set of objects, what is that something? Well we can pass that as an argument. This simple idea can lead to profound insights. Google MapReduce is inspired by this functional view of the world allow operations to be parallelzed then the result collated later. Since the operations on each object a separate this can be done transparently to the user. The process of iteration itself can be further customised through the use of filter. This may seem like a lot of trouble to go to just to iterate over a bunch of objects, but this pattern comes up so often that it is more than worth it.
  • The idea of looping over a collection of objects and doing a customisable something to them is so fundamental to functional programming in python that there is whole module dedicated to that cause. It contains many useful variations on that theme. cycle() - infinitely cycle through an iterable repeat() - repeats an element a specified number of times chain()    - chains iterators together so they be iterated over as one sequnce groupby() - returns sub-iterators grouped by value of keyfunc(v) tee() - splits one iterator into n product() - cartesian product, equivalent to a nested for-loop
  • Syntactic sugar for higher order functions. No real difference but the way the clearly indicate the intentions make it much much nicer to use higher order functions. I think it is fair to say that most peoples use of higher order functions in python is via decorators. Decorators really cause an explosion of this sort of higher order functions in the wild and of course the standard library has many useful decorators built in. Do not write code like this it is no only a bad caching decorator (that contains a memory leak), it is unnecessary since python 2.7 it is in the standard library.
  • Allows you to define functions in terms of existing ones by freezing some of the arguments and keyword arguments. This avoids repetition of those parameters all over the code. This is another of the problems we discussed at the beginning, scattering the knowledge about a particular concern all over the code. This infact a rather more subtle version, it is not obvious in the heat of to see how having many function call for which a subset of the arguments must always be the same is modularity and maintenance problem. But thinking about it for a moment you can see that it really is.  functools partial allows you to avoid this without having to write trivial wrapper functions which people tend not to do anyway.   You may also here it referred to as currying , but if I call it currying people who really know about functional programming will come and beat me up because apparently currying is something different.
  • - I am not a classical rhetorician, but I aspire to play one on TV. The structure of classical rhetorical argument requires us to present the thesis, then explore the antithesis, and finally present the synthesis   - We are going take an example based approach, taking a look at a few Python OO and FP features that exemplify the point I am trying to make.   - The examples themselves are taken mostly taken from the Python standard library, not so much the internals buy how we are supposed to use it. This is useful because the standard library (or any library for that matter) necessarily needs to extensible and reusable from the outside without modifying the library itself.
  • We have seen how python's oo features allow us to express well the structural relationships between object and better communicate the constraints we want to impose as in the abc example. We have also seen how the functional approach makes it easy to express performing different operations over a given set of objects and how higher order functions allow us to easily customise those operations.   I could end the talk right here and legitimately claim that I have shown what I set to. However the story only gets better from here the OO and functional aspects of python are not separate worlds that are not intended to meet. Quite the contrary in Python the two approaches complement each other nicely. We are now approaching our foreshadowed conclusion that the design of Python takes both the OO and functional view into account. This section contains a selection of examples that demonstrate this multi-paradigm  approach to programming that Python supports and how it allows for really clean solutions.
  • The functional style of programming relies heavily on passing functions around, than applying them to objects later (using itertools or some of the other callback we talked about previously. Functions are descriptors Override binding behaviour Override differently for A.x and a.x Unbound methods know their class but not their instance Ideal for use in functional scenarios where the target object is specified directly.
  • Using the property higher order function to bring new functionality in an OO context. Avoids the unnecessary getter setter desease in Java other languages. C# does infact have properties because it is designed by Anders so has influence from Delphi The decorators are just sugar for the property higher order function.
  • property and inheritance there is an unintentional pun there.   Property results in early binding. The property has a handle to the specific function object passed into it when it was created. It cannot know about the methods in the derived class. We talked about python helping smooth the impedance mismatch between OO and FP well this is a case where the abstraction leaks a bit. Luckily the fix is not that complicated. A layer of indirection solved every problem in computer science. I do not think that is quite true it solves many problems though and this is one of them.
  • Do not scatter dependencies on specific classed throughout your  code this makes it harder to change implementations down the line    I know what you thinking I can use grep,    but if you now need to do some checking and perhaps initialise the object a little differently based on some previously on unforeseen factors this is now going to be much more of a pain. Invert the dependency, use a factory instead. Of course we all do this every time we are instantiating a class right. Modularity again we want to be able to change things in future without too much pain.
  • What I really mean is that python classes are callables. Python classes are callables, like functions and methods Indistinguishable from other callables to the caller, for the most part of course via introspection you can tell the difference but in typical cases they are the same Allow us to postpone the creation of a factory until it actually needed. this is similar to how property
  • One of the reasons python is so suitable for programming in a functional style is that there are several different types of callables, which are mostly inter changeable. Notice how the documentation for what I have been calling higher order functions, in the operator module such as itemgetter attrgetter and method caller say they return callables not functions. If they are not functions what else could they be? Class based callables can be handy if you want a callable that has internal state that is uses when called.
  • - I am not a classical rhetorician, but I aspire to play one on TV. The structure of classical rhetorical argument requires us to present the thesis, then explore the antithesis, and finally present the synthesis   - We are going take an example based approach, taking a look at a few Python OO and FP features that exemplify the point I am trying to make.   - The examples themselves are taken mostly taken from the Python standard library, not so much the internals buy how we are supposed to use it. This is useful because the standard library (or any library for that matter) necessarily needs to extensible and reusable from the outside without modifying the library itself.

Object Orientation vs. Functional Programming in Python Object Orientation vs. Functional Programming in Python Presentation Transcript

  • Object Orientation vs. Functional Programming Writing Modular Python Programs Twitter: @insmallportions www.insmallportions.com
  • About Me
  • Modularity
  • Roadmap
    • Thesis
    • Object Orientation is a proven way of creating models in software that represent the problem domain in a useful manner. There are many patterns that show how to achieve the modularity goal in different contexts.
    • Antithesis
    • Functional Programming is a long standing approach to defining processes in terms of others at different levels of abstraction. Higher order functions make the idiomatic ways to perform certain tasks fall out naturally.
    Synthesis Python has good support for both styles of programming and for good reason. Depending on the situation one or the other maybe more appropriate. Moreover in Python these tools do not only exist but they complement each other.
  • Object Orientation
      • Class Oriented
    •  
      • The Three Pillars of OO are:
      • Delegation
      • Polymorphism
      • Instantiation
  • Template Method class Game(object):     PLAYERS = 2     def initialize_game(self):         raise NotImplementedError()     def make_play(self, player):         raise NotImplementedError()     def end_of_game(self):         raise NotImplementedError()     def print_winner(self):         print self.current     def play_game (self, players=PLAYERS):         self.initialize_game()         self.current = 0         while not self.end_of_game():             self.make_play(self.current)             self.current = (self.current + 1)                 % players         self.print_winner() class Monopoly(Game):     PLAYERS = 4     def initialize_game(self):         pass # Monopoly code here     def make_play(self, player):         pass # Monopoly code here     def end_of_game(self):         pass # Monopoly code here     def print_winner(self):         pass # Monopoly code here class Chess(Game):     def initialize_game(self):         pass # Chess code here     def make_play(self, player):         pass # Chess code here     def end_of_game(self):         pass # Chess code here
  • Abstract Base Classes >>> class MyDict(dict): ...   def __getitem__(self, key): ...       return 101 ... >>> d = MyDict() >>> d['x'] 101 >>> d.get('x', 202) 202 >>>  >>> from collections import Mapping >>> class >>> from collections import Mapping >>> class MyMapping(Mapping): ...     def __getitem__(self, key): ...         return 101 ... >>> m = MyMapping() Traceback (most recent call last):   File &quot;<stdin>&quot;, line 1, in <module> TypeError: Can't instantiate abstract class MyMapping with abstract methods __iter__, __len__
  • Mixins class XMPPClient(object):     def connect(self):         pass # XMPP code     def disconnect(self):         pass # XMPP code     def send(self, player):         pass # XMPP code     def terminate(self, player):         raise NotImplementedError()         def mainain_presence(self):         self.connect()         while not self.terminate():             yield         self.disconnect() class OnlineChess(Game,                 XMPPClient):     def initialize_game(self):         pass # Chess code here     ...     def end_of_game(self):         pass # Chess code here     def terminate(self, player):         return self.end_of_game()
  • Mixins (Multiple Inheritance) class A(object):     pass class B(A):     def method1(self):         pass class C(A):     def method1(self):         pass   class D(B, C):     pass
  • Wrapping/Composition
      • Prefer Composition over Inheritance
      • Use a class's functionality but not its API
      • Expose only limited part of an object
    •  
      • Typical uses:
        • Adapt
        • Proxy
        • Decorate
  • Wrapping/Composition class Eprom(object):     def read(self):         pass # Eprom code     def write(self, data):         pass # Eprom code     def complete(self):         pass # Eprom code class FileLikeEprom(object):     def __init__(self, eprom):         self._eprom = eprom     def read(self):         return self._eprom.read()     def write(self, data):         self._eprom.write(data)     def close(self):         self._eprom.complete() class SafeEprom(object):     def __init__(self, eprom):         self._eprom = eprom     def read(self):         return self._eprom.read()     def write(self, data):         if data.safe():             self._eprom.write(data)     def close(self):         self._eprom.complete()
  • Wrapping/Composition (Tricks) class FileLikeEprom(object):     def __init__(self, eprom):         self._eprom = eprom     def __getattr__(self, a):         if a == 'close':             return self.close         else:             return getattr(self._eprom, a)     def close(self):         self._eprom.complete()
      • Don't Repeat Yourself
      • Avoid boilerplate
      • Use __getattr__ to return computed attributes
  • Mixins Again class SafeAndFileLike(FileLikeEprom, SafeEprom):     def __init__(self, *args, **kwargs):         return super(SafeAndFileLike, self).__init__(*args, **kwargs)
  • Roadmap
    • Thesis
    • Object Orientation is a proven way of creating models in software that represent the problem domain in a useful manner. There are many patterns that show how to achieve the modularity goal in different contexts.
    • Antithesis
    • Functional Programming is a long standing approach to defining processes in terms of others at different levels of abstraction. Higher order functions make the idiomatic ways to perform certain tasks fall out naturally.
    Synthesis Python good support for both styles of programming and for good reason. Depending on the situation one or the other maybe more appropriate. Moreover in Python these tools do not only exist but they complement each other.
  • Functional Programming
      • Functions take input and produce output, without any side effects.
      • Pure functional languages are strict about side effect freeness.
      • Python is not a pure functional language.
      • Functions may be internally imperative, but appear purely functional in their behaviour.
  • Callbacks
      • The Hollywood principle
      • Role reversal, library code calls your code
      • Library code accepts a callable and invokes it when appropriate
    •  
      • The main uses:
        • Customisation
        • Event Handling
  • sorted() sans Callbacks
    • >>> people = [Person('John', 'Smith'), ...     Person('Mary', 'Doe'), ...     Person('Lucy', 'Pearl'),] >>> for p in sorted(people): ...     print p ... Mary Doe Lucy Pearl John Smith >>>
    class Person(object):     def __init__(self, f, s):         self.f = f         self.s = s     def __str__(self):         return '%s %s' % (self.f, self.s)     def __eq__(self, other):         return self.s == other.s     def __lt__(self, other):         return self.s < other.s
  • sorted() with Callbacks
    • >>> for p in sorted(people, key=first_name): ...     print p ... John Smith Lucy Pearl Mary Doe >>> for p in sorted(people, key=surname_name): ...     print p ... Mary Doe Lucy Pearl John Smith >>>
    class Person(object):     def __init__(self, f, s):         self.f = f         self.s = s     def __str__(self):         return '%s %s' % (self.f, self.s)   first_name = lambda p: p.f surname = lambda p: p.s
  • operator module from operator import attrgetter   class Person(object):     def __init__(self, f, s):         self.f = f         self.s = s     def __str__(self):         return '%s %s' % (self.f, self.s)   first_name = attrgetter('f') surname = attrgetter('s')
      • attrgetter
      • itemgetter
      • add
      • mul
      • pow
      • ...
  • Operations on aggregates
      • sum
      • filter
      • map
      • reduce
    >>> def square(x): ...         return x ** 2 ... >>> l = [1, 2, 3, 4, 5] >>> sum(map(square, l)) 55 >>> def square(x): ...        return x ** 2 ... >>> def odd(x): ...        return x % 2 ... >>> l = [1, 2, 3, 4, 5] >>> sum(map(square, filter(odd, l))) 35
  • itertools module
      • cycle()
      • repeat()
      • chain()
      • tee()
      • product()
      • ...
  • Decorators
    • def cache(fn, c=None):
    •     if c is None: c = {}     def cached(*args):         if args in c:             return c[args]         result = fn(*args)         c[args] = result         return result     return cached def adder(x, y):     return x + y
    •  
    • adder = cache(adder)
    def cache(fn, c=None):     if c is None: c = {}     def cached(*args):         if args in c:             return c[args]         result = fn(*args)         c[args] = result         return result     return cached @cache def adder(x, y):     return x + y Do not write code like this, use: functools.lru_cache
  • Partial function evaluation
    • >>> from functools import partial >>> >>> def power(base, exp=1): ...         return base ** exp ... >>> square = partial(power, exp=2) >>> cube = partial(power, exp=3) >>> >>> l = [1, 2, 3, 4, 5] >>> sum(map(square, l)) 55 >>> print sum(map(cube, l)) 225
  • Roadmap
    • Thesis
    • Object Orientation is a proven way of creating models in software that represent the problem domain in a useful manner. There are many patterns that show how to achieve the modularity goal in different contexts.
    • Antithesis
    • Functional Programming is a long standing approach to defining processes in terms of others at different levels of abstraction. Higher order functions make the idiomatic ways to perform certain tasks fall out naturally.
    Synthesis Python good support for both styles of programming and for good reason. Depending on the situation one or the other maybe more appropriate. Moreover in Python these tools do not only exist but they complement each other.
  • Best of Both Worlds
  • Unbound methods
      • Functions are descriptors
      • Override binding behaviour
      • Override differently for A.x and a.x
      • Unbound methods know their class but not their instance
      • Ideal for use in a functional style
    >>> food = ['Spam', 'ham', 'Cheese', 'eggs'] >>> sorted(food) ['Cheese', 'Spam', 'eggs', 'ham'] >>> sorted(food, key=str.lower) ['Cheese', 'eggs', 'ham', 'Spam'] >>>   >>> sorted(food, key='ham'.lower) Traceback (most recent call last):   File &quot;<stdin>&quot;, line 1, in <module> TypeError: lower() takes no arguments (1 given)
  • Computed fields (property) class Person(object):     def __init__(self, f, s):         self.f = f         self.s = s     @property     def fullname(self):         return '%s %s' % (self.f,              self.s)   >>> p = Person('John', 'Smith') >>> p.fullname 'John Smith' class Person(object):     def __init__(self, f, s):         self.f = f         self._s = s     @property     def s(self):         return self._s.upper()      @s.setter     def s(self, value):         self._s = value   >>> p = Person('Jane', 'Doe') >>> p.s 'DOE' property([ fget [, fset [, fdel [, doc ]]]])
  • property and inheritance class Person(object):     def __init__(self, t, f, s):         ...         def full(self):         return '%s %s' % (self.f,self.s)     fullname = property(full) class Customer(Person):     def full(self):         return '%s. %s %s' %                     (self.t, self.f, self.s)     >>> c = Customer('Mr', 'John', 'Smith') >>> c.fullname 'John Smith' class Person(object):      def __init__(self, t, f, s):         ...     def full(self):        return '%s %s' % (self.f, self.s)     def _full(self):         return self.full()     fullname = property(_full)   class Customer(Person):     def full(self):         return '%s. %s %s' %                        (self.t, self.f, self.s)   >>> c.fullname 'Mr John Smith'
  • Dependency Inversion class Employee(object):     def __init__(self, f, s):         self.f = f         self.s = s     def register(self):         pass # Register me def register(emps):     for f, s in emps:         emp = Employee(f, s)         emp.register() >>> emps = [('John', 'Smith'), ('Mary', 'Doe')] >>>register(emps) def employee_fact(f, s):     return Employee(f, s) def register(emps, fact):     for f, s in emps:         emp = fact(f, s)         emp.register() >>> emps = [('John', 'Smith'), ('Mary', 'Doe')] >>>register(emps, employee_fact)
  • Python classes are factories class Employee(object):     def __init__(self, f, s):         self.f = f         self.s = s     def register(self):         pass # Register me def register(emps, fact):     for f, s in emps:         emp = fact(f, s)         emp.register() >>> emps = [('John', 'Smith'), ('Mary', 'Doe')] >>>register(emps, Employee)
      • Python classes are callables
      • Indistinguishable from other callables to the caller
      • Allow us to postpone the creation of a factory until it actually needed
  • Many types of callables
      • Functions
      • Unbound methods
      • Bound methods
      • Classes
      • Any object that has a __call__ method is a callable
      • Testable using the callable built-in function
    •  
    • >>> callable(str) True >>> callable('Spam') False >>> 
    class Callable(object):     def __init__(self, m):         self.message = m     def __call__(self):         print self.message class NotCallable(object):     def call(self):         print &quot;You Rang?&quot; >>> c = Callable('You Rang') >>> c() You Rang >>> n = NotCallable() >>> n() Traceback (most recent call last):   File &quot;<stdin>&quot;, line 1, in <module> TypeError: 'NotCallable' object is not callable
  • Roadmap
    • Thesis
    • Object Orientation is a proven way of creating models in software that represent the problem domain in a useful manner. There are many patterns that show how to achieve the modularity goal in different contexts.
    • Antithesis
    • Functional Programming is a long standing approach to defining processes in terms of others at different levels of abstraction. Higher order functions make the idiomatic ways to perform certain tasks fall out naturally.
    Synthesis Python good support for both styles of programming and for good reason. Depending on the situation one or the other maybe more appropriate. Moreover in Python these tools do not only exist but they complement each other nicely.
  • We hire superheroes!
      • www.demonware.net/jobs/
    •  
      • Development & Operations Positions
    •  
      • Come talk to us