"Inheritance" is not from classes

    image
    In Python, it doesn't really matter what you put in the class definition. It can be strings, numbers, objects, variables. In Python 3, you can even pass named arguments.

    Implementation


    First you need to disappoint: in Python you cannot inherit from classes, i.e. You cannot pass a typeparameter to a class constructor basesthat has nonclasses . However, it’s not specified anywhere what you will include in the class definition.
    There is nothing complicated in the implementation of the code above, for this, you just need to create a metaclass in which nonclasses from will be filtered out bases(which can be used further at your discretion). I think the example will explain everything, copy & run :
    Copy Source | Copy HTML
    1. # coding: utf-8
    2.  
    3. class Metaclass(type):
    4.  
    5.     '''<br/>    Metaclass печатает все объекты, от которых наследует класс<br/>    и которые не являеются классами.<br/>    '''
    6.  
    7.     def __new__(cls, name, bases, dict):
    8.         import inspect
    9.  
    10.         new_bases = []
    11.         for base in bases:
    12.             # отфильтруем классы,
    13.             # остальное просто напечатаем
    14.             if inspect.isclass(base):
    15.                 new_bases.append(base)
    16.             else:
    17.                 print base
    18.  
    19.         return type.__new__(cls, name, tuple(new_bases), dict)
    20.  
    21.  
    22. class Print(object):
    23.  
    24.     __metaclass__ = Metaclass
    25.  
    26.  
    27. class String(Print, 'Programming', 'is', 'all', 'about', 'architecture.', ''):
    28.     pass
    29.  
    30. class Numbers(Print,  0, 1, 2.718, 3.1459, ''):
    31.     pass
    32.  
    33. class More(Print, None, True, 'or', False, ['to be', 'or', 'not to be'], ''):
    34.     pass
    35.  
    36. the_end = 'The end.'
    37. class End(Print, the_end):
    38.     pass

    Using named arguments in class definition in third Python, copy & run :
    Copy Source | Copy HTML
    1. # Python 3+
    2.  
    3. def metaclass(name, bases, dict, private=True):
    4.     print('Private:', private)
    5.     return type(name, bases, dict)
    6.  
    7.  
    8. class MyClass(object, metaclass=metaclass, private=False):
    9.  
    10.     pass


    Practical expediency


    In most cases, this feature is not required at all. Moreover, the code becomes complex and “magical”, which is not at all welcome. However, in some cases, it is indispensable, as are metaclasses in general. In fact, two advantages can be distinguished:
    1. Metaclass Management and
    2. Simplification of the API.

    Management of the construction of classes (and generally metaclasses)

    Passing parameters for the metaclass directly in the class definition. Of course, you can pass the same parameters through the attributes of a regular class, but it clogs the class and does not always look readable. For example, let it be necessary to inherit either a full glass or an empty one (the example is dragged by the ears, I didn’t come up with a simple and understandable one, but I couldn’t get it from the finished code). Copy & run :
    Copy Source | Copy HTML
    1. #coding: utf-8
    2.  
    3. class EmptyGlass: pass
    4. class FullGlass: pass
    5.  
    6.  
    7. class GlassMetaclass(type):
    8.  
    9.     '''<br/>    GlassMetaclass создает либо класс EmptyGlass, либо FullGlass,<br/>    в зависимости от того, было ли указано True или False в определении<br/>    класса.<br/>    '''
    10.  
    11.     empty_glass = EmptyGlass
    12.     full_glass = FullGlass
    13.  
    14.     def __new__(cls, name, bases, dict):
    15.         if bases[-1] is True: # is True, потому что нам надо именно объект True
    16.             # полный бокал
    17.             bases = [cls.full_glass] + list(bases[:-1])
    18.         elif bases[-1] is False:
    19.             # пустой
    20.             bases = [cls.empty_glass] + list(bases[:-1])
    21.  
    22.         return super(GlassMetaclass, cls).__new__(cls, name, tuple(bases), dict)
    23.  
    24.  
    25. class Glass(object):
    26.  
    27.     __metaclass__ = GlassMetaclass
    28.  
    29.  
    30. if __name__ == '__main__':
    31.     class MyGlass(Glass, True): pass # полный стакан
    32.     class YourGlass(Glass, False): pass # пустой стакан
    33.  
    34.     print issubclass(MyGlass, FullGlass) # True
    35.     print issubclass(YourGlass, EmptyGlass) # True 

    API simplification

    Suppose we need to create a tree from classes (not a data structure, but just a hierarchy). Let it be hierarchical regular expressions. In this case, each class needs to pass a string that will be compiled into a regular expression. In the classic form, it will look something like this:
    Copy Source | Copy HTML
    1. class Music(MyRe):
    2.  
    3.     pattern = '/music'
    4.  
    5.     class Artist(MyRe):
    6.  
    7.         pattern = '/artist/\d+'
    8.  
    9.     class Song(MyRe):
    10.  
    11.         pattern = '/song/\d+'
    12.  
    13.     class Album(MyRe):
    14.  
    15.         pattern = '/album/\d+'

    Including strings directly in the class definition allows you to get more beautiful and understandable code:
    Copy Source | Copy HTML
    1. class Music(MyRe, '/music'):
    2.  
    3.     class Artist(MyRe, '/artist/\d+'): pass
    4.     class Song(MyRe, '/song/\d+'): pass
    5.     class Album(MyRe, '/album/\d+'): pass

    Conclusion


    Passing parameters to metaclasses in class definitions, on the one hand, complicates the implementation of the program code, on the other hand, allows you to build a more humane interface and continue to focus on solving problems. In other words, be one step closer to DSL.

    Further Reading on Metaclasses


    1. White papers, Customizing class creation. docs.python.org/3.1/reference/datamodel.html#customizing-class-creation
    2. Unifying types and classes in Python 2.2 #Metaclasses, Guido van Rossum. www.python.org/download/releases/2.2/descrintro/#metaclasses
    3. PEP-3115, Metaclasses in Python 3000. www.python.org/dev/peps/pep-3115
    4. Python Metaclasess: Who? Why? When ?, Mike C. Fletcher at PyCon 2004, presentation. www.vrplumber.com/programming/metaclasses-pycon.pdf

    Also popular now: