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
, @staticmethod
and super
so 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 property
it.
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.setter
logic 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 property
characteristics.
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:
Use
TestProperty
rear trim,math
it is no longer a function, butTestProperty
an instance of class. So the second math function can be usedmath.setter
to decorate, is essentially a callTestProperty.setter
to create a newTestProperty
second instance assigned tomath
.The first
math
and secondmath
are two differentTestProperty
instances. But they all belong to the same class descriptor (TestProperty), when for the assignment of math, will enterTestProperty.__set__
, when to be a value in math, will enterTestProperty.__get__
. A closer look, in fact, the final visit or Student instance_math
properties.
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 property
the 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 @classmethod
and @staticmethod
implementation 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 staticmethod
here come.
From the above comments, it can be seen staticmethod
in fact equivalent to a class descriptor, and myfunc
the descriptor into a moment. About staticmethod
implementation, 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 classmethod
is 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
, staticmethod
and classmethod
the 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