本帖最后由 ABC23 于 2018-5-20 22:08 编辑
Python的魔法方法变为常规掉调用就是把dunder(好像叫这个,双下划线)去掉,传入参数即可
1. __del__():在删除实例对象时调用;因为比较常用常作为语句出现(似py2.x的print语句)
2. __delattr__():在删除对象的指定属性时调用,如果没有就raise异常;不包括方法
3. __delete__():描述符相关,详见下面的例子
描述符的本质就是封装(隐藏)==> ==> 【从property装饰器到描述符类】这篇文章或许对你有帮助(传送门:http://python.jobbole.com/81899/)
使用描述符就要把它作为类(class)层次对待——虽然访问方式是作为属性的,但是本质还是类,说到底还是语法糖这一点不要忘了。还有就是传递参数默认为3/2个不要少/多了。
class Celsius:
def __init__(self, value=26.0):
self.value = float(value)
def __get__(self, instace, owner):
return self.value
def __set__(self, instance, value):
self.value = float(value)
class Fahrenheit:
def __get__(self, instance, owner):
return instance.cel * 1.8 + 32
def __set__(self, instance, value):
instance.cel = (float(value) - 32) / 1.8
class Temperature:
cel = Celsius()
fah = Fahrenheit()
这是小甲鱼上课时用的一个例子,比较简单。你可以在终端中这样调用
➜ Desktop python3
Python 3.6.0 (v3.6.0:41df79263a11, Dec 22 2016)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from Temperature import *
>>> temp = Temperature()
>>> temp.cel
26.0
>>> temp.fah
78.80000000000001
好。至于__delete__。只要理解了描述符的本质,理解这个应该不是问题。
看我顺手写的一个Demo
class PositionChecker:
def __init__(self, value):
self.value = value
def __get__(self, instance, owner):
return self.value
def __set__(self, instance, value):
if value <=0:
raise ValueError('Positive Only!')
self.value = value
def __delete__(self, instance):
del self.value
class Position:
x = PositionChecker(None)
y = PositionChecker(None)
def __init__(self, x, y):
self.x = x
self.y = y
(对Python比较熟悉的同学看出来了,这个Position类的(x,y)点集构成了『第一象限的点的集合』。)
➜ Desktop python3
Python 3.6.0 (v3.6.0:41df79263a11, Dec 22 2016)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from position import *
>>> p1 = Position(1,2)
>>> p2 = Position(-1,-2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/macbookpro/Desktop/position.py", line 22, in __init__
self.x = x
File "/Users/macbookpro/Desktop/position.py", line 11, in __set__
raise ValueError('Positive Only!')
ValueError: Positive Only!
>>> p1.x = 10
>>> p1.x
10
>>> p1.__dict__
{}
>>> dir(p1)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'x', 'y']
>>> del p1.x
>>> p1.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/macbookpro/Desktop/position.py", line 7, in __get__
return self.value
AttributeError: 'PositionChecker' object has no attribute 'value'
>>> dir(p1)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'x', 'y']
>>> p1.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/macbookpro/Desktop/position.py", line 7, in __get__
return self.value
AttributeError: 'PositionChecker' object has no attribute 'value'
>>> p1.x == None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/macbookpro/Desktop/position.py", line 7, in __get__
return self.value
AttributeError: 'PositionChecker' object has no attribute 'value'
>>> p1.y == None
False
>>> dir(p1)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'x', 'y']
写了这么多,看飘红处的文字。
'PositionChecker' object has no attribute 'value'
它说的是PositionChecker这个类没有value属性(这里就是特指Position的x属性)。
再看蓝色部分。
>>> dir(p1)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'x', 'y']
明明已经del p1.x了(内置实现__delete__(self, instance)),但是在position这个类的实例之dir()的返回值却包括了'x'(🤔?)。(dir返回对象的属性和方法)。
结合红色和蓝色文字,想一想(给你5秒钟🤔?)。
解释:因为__delete__函数删除的是self.value(确实是删除掉了,准确理解就是解引用,这里就是从内存中抹消),这里self表示的是PositionChecker类的实例(而这个实例恰恰和后面的Position类的实例绑定起来了),于是。于是就没啦。就被删除,抹消了。
综上所述,__delete__()方法确实是删掉了这个对应的属性对象(而不是什么置为None)。
貌似说了一堆『废话』,但是希望你能理解,改变——改变的是哪个类的属性;删除——删除的是哪个类的属性……,把思路理清了,也就好了。
另外,为什么直接看不出x被删除的痕迹呢(在dir()返回的列表中还是存在~~~,但是那是假象~~~),个人认为原因在于:绑定,在你的owner类(封装住描述符类的高级类)中,直接把描述符类的实例对象作为属性看待,而这里(重点~)每个在owner类的属性都和描述符类的实例一一对应(一对一的关系)。
好。如果我们想看看某个类的某个属性是否存在,是不是调用dir()函数(返回属性和方法,注意不要用__dict__因为描述符在class层次,不在__init__方法中(也因为此它和类直接挂钩,所以通常将它们的值初始化为None这样最保险)),你可以dir(封装类),返回结果告诉你'x'还在(这是假象🤔!!),你也可以dir(描述符类()),但是你如何能获得与封装类属性一一对应的那个描述符实例对象???(这里不知道你能不能理解🤭🤫🤥。。)。不妨想象一根绳子,你沿着绳子的节点往上爬,首先第一个节点没问题,但是第二个节点却断了联系——而且你没有任何别的方法到达第二个节点。。(还算形象。吧。)
呼呼~~说了大堆,基本上都是说描述符这个__delete__方法了。有点偏离~不知道有没有解决你的问题 :-P(答案是:确实是删掉了,但是要看你研究的哪一个类,虽然在高级类中仍然保存着属性的引用,但是接着往上回溯就断了线索~)