metaprogramming in python

  roberto bampi @ trenta3dev

things that make me happy

( things I'm going to talk about)

  •  objects in python (introduction to oop)
  •  new style classes
  •  getattr, setattr, hasattr
  •  classes as objects
  •  __init__ and __new__
  •  metaclasses


(things I'm not going to talk about)

  •   old style classes

oop: Object oriented python

Python is (also) an object oriented language

    class Foobar(object):
       def __init__(self, baz):
          self.baz = baz 

But, unlike other languages,


in python is a object

let's talk about new style classes

Known to python programmers as

"the way classes should always have worked"

(they did not)

New style classes always have object

at the top of their inheritance chain

        >>> class Foo(object): pass
        >>> Foo.__mro__
        (Foo, object)


python is a dynamic language

    >>> class Foobar(object):
    >>> myobj = Foobar()
    >>> myobj.my_custom_var = 123
    >>> myobj.my_custom_var
    >>> Foobar.my_custom_var
    AttributeError: type object 'Foobar' has no attribute 'my_custom_var'

we can not be sure of what members

an instance will have at any given time

tools to deal with dynamism

  • getattr(obj, name, [default])
  • hasattr(obj, name)
  • setattr(obj, name, value)

        >>> class Foobar(object):
               def __init__(self):
                  self.i_exist = 'i really do'
        >>> foo_inst = Foobar()
        >>> hashattr(foo_inst, 'i_exist')
        >>> getattr(foo_inst, 'i_exist')
        'i really do'
        >>> hasattr(foo_inst, 'i_do_not_exist')
        >>> getattr(foo_inst, 'i_do_not_exist', 'i am the default')
        'i am the default'
        >>> setattr(foo_inst, 'i_do_not_exist', 'i exist now')
        >>> getattr(foo_inst, 'i_do_not_exist')
        'i exist now'

CLasses as objects

in python classes are also objects

        >>> int.__class__
you can think of them as blueprints
used to build concrete instances that can then be used

let's find out how this works !

__NEW__ and __init__

whenever we want to build an instance

of an object two things happen:

  •   a new object of the desired type is created: __new__
  •   the new object can then be initialized: __init__

    creation of an instance

        >>> class MyClass(object):
               def __new__(cls):
                  print "in __new__"
                  return super(MyClass, cls).__new__(cls)
               def __init__(self):
                  print "in __init__"
         = 123
        >>> myinstance = MyClass()
        in __new__
        in __init__


    since classes are `just objects`

    metaclasses are the way to customize

    their creation

    the base metaclass is type 

    type's type is type

    what does a metaclass do anyway

    a metaclass can be any class that

    inherits from type

       class MyMeta(type):
          def __new__(cls, name, parents, dct):
             # this method has the responsability to
             # create and return a new instance of type
             # the only way to do so is to call type itself (or any subclass)
             print "A new class named " + name + " is going to be created"
             return super(MyMeta, cls).__new__(cls, name, parents, dct)

    and overrides either __new__ or __init__

    to provide custom behavior

    How it is used

    a custom metaclass can be explicitly

    set on the class itself like so

        class MyClass(object):
           __metaclass__ = MyMeta

    The lookup order for a metaclass is as follows:

    on the class

    in the parents

    in the package

    use with care

    Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don’t (the people who actually need them know with certainty that they need them, and don’t need an explanation about why).

    – Tim Peters


    That's all folks !

    and thank you for listening to me.