90% of the Python developer does not know the application descriptor

Okay, I admit I was heading the party. But knowledge of this article, you are far more likely not to know.

Some time ago, I wrote an article entry-level descriptors, from those article you know how to define descriptors, descriptor and understand how it works.

If there are learning or want to learn Python Python junior partner, to learn the information can go to my micro-channel public number: learn Python circle, background replies: "01", you can take Python learning materials

Usage descriptor normal've seen is the last article mentioned that, I want to say is that only describes one of the most common application protocol identifier, perhaps you do not know, in fact, there are many underlying features of Python implement mechanisms are based 描述符协议, such as we are familiar with @property, @classmethod, @staticmethodand superso on.

These methods decorator, you are definitely very, very familiar, but today is not to talk about their usage, but to talk about is how they achieve these characteristics by pure Python.

First is that propertyit.

With the foundation of the first chapter, we know the basic usage of the property. I cut to the chase here direct, streamlined look from the first chapter of the examples in.

class Student:
    def __init__(self, name):
        self.name = name

    @property
    def math(self):
        return self._math

    @math.setter
    def math(self, value):
        if 0 <= value <= 100:
            self._math = value
        else:
            raise ValueError("Valid value must be in [0, 100]")
复制代码

Does not prevent another brief review of its usage by function property of decoration, as in the example of math will become property of Student instance. While attribute assignment enters math use math.setterlogic block decorative function.

Why is the underlying property descriptor-based protocol it? Click to enter the property through PyCharm source, unfortunately, but a similar pseudo-source document the same, and there is no specific implementation logic.

However, the dummy source from this magic function structures can generally know the implementation logic.

Here I function by mimicking its structure, combined with "descriptor Agreement" to achieve their own class propertycharacteristics.

code show as below:

class TestProperty(object):

    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        self.__doc__ = doc

    def __get__(self, obj, objtype=None):
        print("in __get__")
        if obj is None:
            return self
        if self.fget is None:
            raise AttributeError
        return self.fget(obj)

    def __set__(self, obj, value):
        print("in __set__")
        if self.fset is None:
            raise AttributeError
        self.fset(obj, value)

    def __delete__(self, obj):
        print("in __delete__")
        if self.fdel is None:
            raise AttributeError
        self.fdel(obj)

    def getter(self, fget):
        print("in getter")
        return type(self)(fget, self.fset, self.fdel, self.__doc__)

    def setter(self, fset):
        print("in setter")
        return type(self)(self.fget, fset, self.fdel, self.__doc__)

    def deleter(self, fdel):
        print("in deleter")
        return type(self)(self.fget, self.fset, fdel, self.__doc__)
复制代码

Then the Student class, we also changed accordingly as follows

class Student:
    def __init__(self, name):
        self.name = name

    # 其实只有这里改变
    @TestProperty
    def math(self):
        return self._math

    @math.setter
    def math(self, value):
        if 0 <= value <= 100:
            self._math = value
        else:
            raise ValueError("Valid value must be in [0, 100]")
复制代码

To try to make you wonder a little bit less, I'm here to do just two points:

  1. Use TestPropertyrear trim, mathit is no longer a function, but TestPropertyan instance of class. So the second math function can be used math.setterto decorate, is essentially a call TestProperty.setterto create a new TestPropertysecond instance assigned to math.

  2. The first mathand second mathare two different TestPropertyinstances. But they all belong to the same class descriptor (TestProperty), when for the assignment of math, will enter TestProperty.__set__, when to be a value in math, will enter TestProperty.__get__. A closer look, in fact, the final visit or Student instance _mathproperties.

Having said that, it is still running, a little more intuitive.

# 运行后,会直接打印这一行,这是在实例化 TestProperty 并赋值给第二个math
in setter
>>>
>>> s1.math = 90
in __set__
>>> s1.math
in __get__
90
复制代码

For more understanding of propertythe operating principle of the difficulties of the students, be sure to refer to what I wrote above, just two points. If you have additional questions, you can add micro-channel to discuss with me.

1.17.4 How to achieve staticmethod based descriptor

That said property, here again Laijiangjiang @classmethodand @staticmethodimplementation principle.

I am here to define a class, with two ways to implement static methods.

class Test:
    @staticmethod
    def myfunc():
        print("hello")

# 上下两种写法等价

class Test:
    def myfunc():
        print("hello")
    # 重点:这就是描述符的体现
    myfunc = staticmethod(myfunc)
复制代码

Both versions are equivalent, as if property, like, in fact, is written in two equivalent.

@TestProperty
def math(self):
    return self._math

math = TestProperty(fget=math)
复制代码

Or back to the topic staticmethodhere come.

From the above comments, it can be seen staticmethodin fact equivalent to a class descriptor, and myfuncthe descriptor into a moment. About staticmethodimplementation, you can refer to the code I wrote the following piece, to be understood.

[Picture upload failed ... (image-140b40-1559284719108)]

<figcaption></figcaption>

Calling this method can know, every once invoked, it will have been descriptor class __get__.

>>> Test.myfunc()
in staticmethod __get__
hello
>>> Test().myfunc()
in staticmethod __get__
hello
复制代码

1.17.4 How to achieve classmethod based descriptor

The same classmethodis the same.

class classmethod(object):
    def __init__(self, f):
        self.f = f

    def __get__(self, instance, owner=None):
        print("in classmethod __get__")

        def newfunc(*args):
            return self.f(owner, *args)
        return newfunc

class Test:
    def myfunc(cls):
        print("hello")

    # 重点:这就是描述符的体现
    myfunc = classmethod(myfunc)
复制代码

Verification results are as follows

>>> Test.myfunc()
in classmethod __get__
hello
>>> Test().myfunc()
in classmethod __get__
hello
复制代码

Finished property, staticmethodand classmethodthe relationship between descriptor. I think you should have a deeper understanding of the application descriptor in Python. For the realization of the principle of super, you will be handed over to yourself.

Reproduced in: https: //www.jianshu.com/p/2628e780be77

Guess you like

Origin blog.csdn.net/weixin_33709590/article/details/91241214