📜 ⬆️ ⬇️

"Inheritance" is not from classes

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

Implementation


First you need to be disappointed: in Python you cannot inherit from classes, i.e. It is impossible to transfer to the class constructor type parameters parameter, in which there are non-classes . However, it is not stipulated anywhere that you will include a class definition.
There is nothing difficult in the implementation of the code above, for this you just need to create a metaclass in which nonclasses from bases will be filtered out (which can be further used at your discretion). I think an example will explain everything, copy & run :
Copy Source | Copy HTML
  1. # coding: utf-8
  2. class Metaclass (type):
  3. '' ' <br/> Metaclass prints all objects from which the class <br/> inherits and which are not classes. <br/> '' '
  4. def __new__ (cls, name, bases, dict):
  5. import inspect
  6. new_bases = []
  7. for base in bases:
  8. # filter classes
  9. # the rest just print
  10. if inspect .isclass (base):
  11. new_bases.append (base)
  12. else :
  13. print base
  14. return type . __new__ (cls, name, tuple (new_bases), dict)
  15. class Print (object):
  16. __metaclass__ = Metaclass
  17. class String ( Print , 'Programming' , 'is' , 'all' , 'about' , 'architecture.' , '' ):
  18. pass
  19. class Numbers ( Print , 0 , 1 , 2. 718 , 3. 1459 , '' ):
  20. pass
  21. class More ( Print , None, True, 'or' , False, [ 'to be' , 'or' , 'not to be' ], '' ):
  22. pass
  23. the_end = 'The end.'
  24. class End ( Print , the_end):
  25. pass

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


Feasibility


In most cases, this feature is not required at all. Moreover, the code becomes complicated and “magical”, which is not at all welcome. However, in some cases, it turns out to be indispensable, just like the metaclasses as a whole. In fact, there are two advantages:
  1. Metaclass management and
  2. Simplify API.

Management of class construction (and generally metaclasses)

Passing parameters to the metaclass directly in the class definition. Of course, you can pass the same parameters through the attributes of a regular class, but this 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 (it’s pulled by the ears, I didn’t think of a simple and clear one, but I couldn’t take it from the finished code). Copy & run :
Copy Source | Copy HTML
  1. #coding: utf-8
  2. class EmptyGlass : pass
  3. class FullGlass : pass
  4. class GlassMetaclass (type):
  5. '' ' <br/> GlassMetaclass creates either the EmptyGlass class or FullGlass, <br/> depending on whether True or False is specified in the <br/> class definition . <br/> '' '
  6. empty_glass = EmptyGlass
  7. full_glass = FullGlass
  8. def __new__ (cls, name, bases, dict):
  9. if bases [- 1 ] is True: # is True, because we need exactly the True object
  10. # full glass
  11. bases = [cls.full_glass] + list (bases [: - 1 ])
  12. elif bases [- 1 ] is False:
  13. # empty
  14. bases = [cls.empty_glass] + list (bases [: - 1 ])
  15. return super ( GlassMetaclass , cls). __new__ (cls, name, tuple (bases), dict)
  16. class Glass (object):
  17. __metaclass__ = GlassMetaclass
  18. if __name__ == '__main__' :
  19. class MyGlass ( Glass , True): pass # full glass
  20. class YourGlass ( Glass , False): pass # empty glass
  21. print issubclass ( MyGlass , FullGlass ) # True
  22. print issubclass ( YourGlass , EmptyGlass ) # True

API Simplification

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

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

Conclusion


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

Additional literature on metaclasses


  1. Official documentation, 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

')

Source: https://habr.com/ru/post/78924/


All Articles