Copy it to a fixed width font terminal for a good reading.
This is what I gathered and guessed about Python metaclasses from the following pages:
https://mail.python.org/pipermail/python-3000/2006-December/005030.html
https://www.geeksforgeeks.org/python-metaclasses/
https://realpython.com/python-metaclasses/
https://www.geeksforgeeks.org/metaprogramming-metaclasses-python/
Python is a work in progress and so is my understanding of this programming language.
dynamically create a new class:
'name' = type('name', 'bases', 'dict')
differs from class 'name''bases'
by the fact that the name, bases and attributes of the newly created class are decided at runtime
'name' - the name of the new class, memorized in 'name'. __name__
'bases' - a tuple of the base classes from which the class inherits, memorized in 'name'.__bases__
'dict' - a namespace dictionary containing definitions for the class body, memorized in 'name'.__dict__
metaclasses configure classes when they are created
this is different from inheritance
all classes inherit the class 'object' or its subclasses
all classes are configured by the metaclass 'type' or a subclass of it
(maybe it has to be a direct subclass)
'myclass'.__bases__, 'myclass'.__base__ - show directly inherited classes
'myclass'.__class__, type('myclass') - show the metaclass that configured 'myclass'
>>> type.__bases__
(<class 'object'>,)
>>> type(type)
<class 'type'>
>>> int.__bases__
(<class 'object'>,)
>>> type(int)
<class 'type'>
>>> type(7)
<class 'int'>
objects have a __call__() method
which calls the __new__() and __init__() methods
__new__() creates the new object and returns it
'cls' in __new__() is the new object
__init__() initializes the newly created object passed as a parameter
'self' in __init__() is the new object
these methods can be overridden to configure the newly created object
help(type.__call__), help(object.__call__)
help(type) has a __call__ method, but help(object) does not
metaclasses are a “solution in search of a problem”
examples of metaclass usage
$ cat meta.py
# MyMeta is an instance of type and a subclass of type
# MyClass is an instance of MyMeta and a subclass of object
def prints():
print(' type(MyMeta) =', type(MyMeta), '\n type(MyClass) =', type(MyClass), '\n')
class MyClass:
pass
# dynamic creation (definition) of MyClass, parameters can be decided at runtime
MyClass = type('MyClass', (object,), {})
class MyMeta(type):
def __new__(cls, cls_name, bases, attrib):
print('>> MyMeta.__new__()')
return super(MyMeta, cls).__new__(cls, cls_name, bases, attrib)
# super() arguments are not required
print('\nMyMeta.__bases__ =', MyMeta.__bases__, '\nMyMeta.__class__ =', MyMeta.__class__, '\n')
class MyClass(metaclass = MyMeta):
pass
prints()
MyClass = MyMeta('MyClass', (object, ), {})
prints()
# MyClass = type('MyClass', (object, metaclass = MyMeta,), {})
# invalid syntax ^
# so type() cannot create a class of a MyMeta type
# prints()
# MyClass = MyMeta()
# new() missing 3 required positional arguments: 'cls_name', 'bases', and 'attrib'
# prints()
def new(cls, cls_name, bases, attrib):
print('>> new()')
return super(MyMeta, cls).__new__(cls, cls_name, bases, attrib)
# super() arguments are required
MyMeta = type('MyMeta', (type,), {'__new__' : new})
class MyClass(metaclass = MyMeta):
pass
prints()
$ python meta.py
MyMeta.__bases__ = (<class 'type'>,)
MyMeta.__class__ = <class 'type'>
>> MyMeta.__new__()
type(MyMeta) = <class 'type'>
type(MyClass) = <class '__main__.MyMeta'>
>> MyMeta.__new__()
type(MyMeta) = <class 'type'>
type(MyClass) = <class '__main__.MyMeta'>
>> new()
type(MyMeta) = <class 'type'>
type(MyClass) = <class '__main__.MyMeta'>
$ cat meta.py
class Meta(type):
def __new__(cls, name, bases, dict):
x = super().__new__(cls, name, bases, dict)
x.attr = 100
return x
class Foo(metaclass=Meta):
pass
print('Foo.attr =', Foo.attr)
$ python meta.py
Foo.attr = 100
$ cat meta.py
class Meta(type):
def __init__(cls, name, bases, dict):
cls.attr = 100
class X(metaclass=Meta):
pass
print('X.attr =', X.attr)
$ python meta.py
X.attr = 100
No comments:
Post a Comment