Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Meta-programming in Python

Meta-programming in Python

A lightning talk I did for the Amsterdam Python Meetup group about meta-programming in Python.

Daniël Franke

August 08, 2013
Tweet

Other Decks in Technology

Transcript

  1. What? • Objects are instances of classes • Classes are

    Objects as well • What are Classes instances of?
  2. type: Creating the creators In [1]: Spam = type('Spam', (object,),

    {'canned': True}) In [2]: type(Spam) Out[2]: type
  3. type: Creating the creators In [1]: Spam = type('Spam', (object,),

    {'canned': True}) In [2]: type(Spam) Out[2]: type In [3]: canned_spam = Spam() In [4]: type(canned_spam) Out[4]: __main__.Spam
  4. type: Creating the creators In [1]: Spam = type('Spam', (object,),

    {'canned': True}) In [2]: type(Spam) Out[2]: type In [3]: canned_spam = Spam() In [4]: type(canned_spam) Out[4]: __main__.Spam In [5]: canned_spam.canned Out[5]: True In [6]: Spam.canned Out[6]: True
  5. A simple metaclass In [1]: class ismeta(type): ...: def __new__(metaclass,

    name, bases, cls_dict): ...: cls_dict['canned'] = ‘Metacan’ ...: return type.__new__(metaclass, name, bases, cls_dict) ...:
  6. A simple metaclass In [1]: class ismeta(type): ...: def __new__(metaclass,

    name, bases, cls_dict): ...: cls_dict['canned'] = ‘Metacan’ ...: return type.__new__(metaclass, name, bases, cls_dict) ...: In [2]: class Spam(object): ...: __metaclass__ = ismeta ...: pass ...:
  7. A simple metaclass In [1]: class ismeta(type): ...: def __new__(metaclass,

    name, bases, cls_dict): ...: cls_dict['canned'] = ‘Metacan’ ...: return type.__new__(metaclass, name, bases, cls_dict) ...: In [2]: class Spam(object): ...: __metaclass__ = ismeta ...: pass ...: In [3]: Spam.canned Out[3]: 'Metacan'
  8. Reading class properties In [1]: class ismeta(type): ...: def __new__(metaclass,

    name, bases, cls_dict): ...: for key, value in cls_dict.items(): ...: print('{}: {}'.format(key, value)) ...: return type.__new__(metaclass, name, bases, cls_dict) ...:
  9. Reading class properties In [1]: class ismeta(type): ...: def __new__(metaclass,

    name, bases, cls_dict): ...: for key, value in cls_dict.items(): ...: print('{}: {}'.format(key, value)) ...: return type.__new__(metaclass, name, bases, cls_dict) ...: In [2]: class Spam(object): ...: __metaclass__ = ismeta ...: def hello(self): ...: print('Hello byte') ...:
  10. Reading class properties In [1]: class ismeta(type): ...: def __new__(metaclass,

    name, bases, cls_dict): ...: for key, value in cls_dict.items(): ...: print('{}: {}'.format(key, value)) ...: return type.__new__(metaclass, name, bases, cls_dict) ...: In [2]: class Spam(object): ...: __metaclass__ = ismeta ...: def hello(self): ...: print('Hello byte') ...: __module__: __main__ __metaclass__: <class '__main__.ismeta'> hello: <function hello at 0x2acf140>
  11. Adding methods via the metaclass In [1]: def hello(self): ...:

    print('Hello byte!') ...: In [2]: class ismeta(type): ...: def __new__(metaclass, name, bases, cls_dict): ...: cls_dict['hi'] = hello ...: return type.__new__(metaclass, name, bases, cls_dict) ...:
  12. Adding methods via the metaclass In [1]: def hello(self): ...:

    print('Hello byte!') ...: In [2]: class ismeta(type): ...: def __new__(metaclass, name, bases, cls_dict): ...: cls_dict['hi'] = hello ...: return type.__new__(metaclass, name, bases, cls_dict) ...: In [3]: class Spam(object): ...: __metaclass__ = ismeta ...: pass ...:
  13. Adding methods via the metaclass In [1]: def hello(self): ...:

    print('Hello byte!') ...: In [2]: class ismeta(type): ...: def __new__(metaclass, name, bases, cls_dict): ...: cls_dict['hi'] = hello ...: return type.__new__(metaclass, name, bases, cls_dict) ...: In [3]: class Spam(object): ...: __metaclass__ = ismeta ...: pass ...: In [4]: Spam().hi() Hello byte!
  14. A “practical” example In [1]: spam_types = {} In [2]:

    class ismeta(type): ...: def __new__(metaclass, name, bases, cls_dict): ...: new_class = type.__new__(metaclass, name, ...: bases, cls_dict) ...: if not attr_dict.get('abstract', False): ...: spam_types[name] = new_class ...: return new_class In [3]: class Spam(object): ...: __metaclass__ = ismeta ...: abstract = True In [4]: class CannedSpam(Spam): ...: pass
  15. A “practical” example In [5]: class EmailSpam(Spam): ...: pass ...:

    In [6]: spam_types Out[6]: {'CannedSpam': __main__.CannedSpam, 'EmailSpam': __main__. EmailSpam}