Python Metaprogramming Notes

    As we gain experience in programming in one language, we all develop standard programming techniques for ourselves. The higher our experience, the greater the number, the more versatile the methods of their work. When switching to another language, we try to reproduce them. Sometimes, it happens that some of them are irrelevant or ineffective. Most of the time, new methods unusual for us are taken away from language learning. I would like to point out some features of Python that were not obvious to me at first.

    By and large, in python, all objects are stored in dictionaries. Dictionaries - there is a list of objects that have a key that is unique to the entire dictionary. This property allows you to "get up" with classes and class instances a variety of things. For instance:

    class A(): i=1; s='string'
    print dir(A)

    > ['__doc__', '__module__', 'i', 's']

    class A(): v0=1
    class B(A):
        def __init__(self):
            self.v2 = 3

    print b.v2, b.v1, b.v0

    > 3 2 1

    When Python tried to get v2 everything is clear - it is obtained from the dictionary of instance b. More interestingly, property v1 does not already contain the element b, it contains the dictionary B - the python took it from there. And finally, when searching for element v0, we turn to the dictionary for parent BA and get it out of there. It is clear that if property v0 is defined within b, then its value will be obtained from there without rising to higher levels. In this example, we moved the __init__ function to the limits of class A (we could move the function with any other name, __init__ is provided for illustration purposes). A class declaration is equivalent: Classes in python are instances of metaclasses. This is a surprise, because now you are allowed to define classes on the fly, and not just their instances. > <__ main __. B object at 0x009E7CD0>

    def __init__(self):
        print self

    class A(): pass
    setattr(A, '__init__', __init__)


    > <__main__.A instance at 0x009E9EB8>

    class A():
        def __init__(self):
            print self

    def __init__(self):
        print self

    B = type('B', (), {})
    setattr(B, '__init__', __init__)

    b = B()

    Note that a function is defined only for instances of a class; you cannot call it for class A itself. On the other hand, what prevents us from this opportunity to add. >

    def Omd(obj):
        print obj

    B = type('B', (), {})
    setattr(B, 'c', classmethod(Omd))
    setattr(B, 'o', Omd)

    b = B()
    b.c(), b.o()

    > <__ main __. B object at 0x009E7D50>

    Fun really ?! We identified a function that prints its first argument. Next, we created a class based on a metaclass (you could define it in a standard way class A(type): pass). Next to the class, we added the static function ā€œcā€, under which ours is hidden, and the function ā€œoā€ to call it from an instance of class B. We look at what happens, the first we see that the class is printed, and after it the instance. This is their love.

    Also popular now: