如果我创建一个对象:
class eggs(object):
""" This wasn't needed """
def __setattr__(self, name, value):
print name, value
如果我这样做,我能理解:
class eggs(object):
""" This wasn't needed """
def __setattr__(self, name, value):
print name, value
if __name__ == "__main__":
foo = eggs()
foo.bar = 5
print foo
我明白了:
bar 5
<__main__.eggs object at 0x8f8bb0c>
然而,当我这样做时:
if __name__ == "__main__":
foo = eggs()
foo = 5
print foo
我明白了:
5
我的问题是&#34;魔法&#34;调用foo = 5
时调用方法?
例如我这样做:
class eggs(object):
""" This wasn't needed """
def __init__(self):
self.bacon = False
def __setattr__(self, name, value):
if not name == "bacon":
raise Exception("No way Hosay")
if value not in [True, False]:
raise Exception("It wasn't supposed to be like this")
super(eggs, self).__setattr__(name, value)
print "Variable became {0}".format(value)
if __name__ == "__main__":
foo = eggs()
foo.bacon = True
foo.bacon = 5 > 4
foo.bacon = True or False
# ETC
返回:
Variable became False
Variable became True
Variable became True
Variable became True
我想在没有培根的情况下这样做。
答案 0 :(得分:2)
你误解了变量在python中的工作方式 - 它们只是对象的引用,而重新分配只是用另一个引用覆盖引用。
作为一种简化的解释,假设变量赋值的工作方式与分配字典成员相似。如果我们调用该字典variables
,我们可以重写
foo = 5
作为
variables["foo"] = 5
现在,您希望variables["foo"]
的当前值(如果它存在)通知分配,这意味着前一个语句将变得类似于以下内容:
variables["foo"].__somemethod__() #call magic method to notify reassignment
variables["foo"] = 5 # set new value
虽然您实际上可以使用dict
子类实现此确切行为,但这并不是CPython中的变量赋值实现的方式。变量引用的对象不会以任何方式通知variables["foo"]
不再引用它的事实。所有发生的事情是先前引用的对象(如果有的话)的引用计数减1。
正如Stick的回答所示,有一个__del__
方法在对象被垃圾收集时被调用,这可能或者可能不足以满足您的实际用例。但是当这被调用时实际上取决于gc,因此它可以表现出一些时髦的行为;见例如this answer讨论一些怪癖。此外,在python3.4之前,甚至不能保证在调用__del__
时任何引用的对象仍然存在,现在已经修复了这个问题:http://legacy.python.org/dev/peps/pep-0442/。
如果您确实需要通知被覆盖的引用(并且我怀疑没有更好的方法来解决您的实际问题),请考虑使用子类或monkeypatched dict
对于您要跟踪的所有参考。您需要覆盖__setattr__
方法以执行覆盖引用时要执行的操作。
答案 1 :(得分:1)
如果你想变得奇怪,你可以覆盖__del__
,但这通常是一整套蠕虫。
>>> class A(object):
... def __del__(self):
... print "oh noooo!"
...
>>> Stick = A()
>>> Stick = 5
oh noooo!
>>> Stick
5
>>>
编辑:听起来你想知道什么时候创建或删除对象?
也许只是一个装饰者就够了?
>>> def talk(func):
... def inner(*args, **kwargs):
... print "I'm doing things!"
... return func(*args, **kwargs)
... return inner
...
>>> class A(object):
... @talk
... def __init__(self):
... pass
... @talk
... def __del__(self):
... pass
...
>>> Stick = A()
I'm doing things!
>>> del Stick
I'm doing things!
>>> Stick
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'Stick' is not defined
>>>
这适用于实例化和删除,以及变量的重新分配。
当然 - 如果在调用__init__
和__del__
时需要不同的方法,则需要使用不同的装饰器。只需将您的“实际工作”放在嵌套函数中即可。
def wrapper(func):
def inner(*args, **kwargs):
#your code here!
#your code here as well!
return func(*args, **kwargs)
return inner
对于使用__del__
进行捣乱时,只是对goofballs和诸如此类的东西持怀疑态度,但我认为这是一种相对理智的方式。
答案 2 :(得分:0)
你应该看看Descriptors,它们是你想要的最接近的东西