[英]Redefine Method of an Object
我有一个类,其中一个方法应该只运行一次。 当然,它可以很容易地用人工has_executed = True/False
标志来完成,但为什么要使用它,如果你可以删除方法本身呢? python
是一种鸭式语言,一切都是参考, bla-bla-bla ,会出什么问题?
至少是这样的想法。 我实际上无法做到:
class A:
def b(self):
print("empty")
self.__delattr__('b')
a = A()
a.b()
引发AttributeError: b
。 但是,执行self.__getattribute__('b')
返回<bound method Ab of <__main__.A object at 0x000001CDC6742FD0>>
,这对我来说听起来很愚蠢:为什么method
与attribute
有任何不同,因为python
中的所有内容都只是一个对对象的引用? 为什么我可以__getattribute__
而不是__delattr__
?
重新定义也是如此。 我可以轻松设置任何属性,但方法是禁忌吗?
class A:
def b(self):
print("first")
self.__setattr__('b', lambda self: print(f"second"))
a = A()
a.b()
a.b()
结果为TypeError: <lambda>() missing 1 required positional argument: 'self'
。 这当然意味着,现在python
没有按预期使用点符号。 当然,我们可以完全放弃 lambda 中的self
属性,考虑到我们已经在b
获得了对它的引用。 但这不是设计不正确吗?
我越是试图将python
发挥到极致,我就越沮丧。 考虑到语言的营销方式,一些强加的限制(或看似强加的? )似乎很不自然。 这不应该允许吗? 为什么不起作用?
UPD
好的,考虑一下:
class A:
def __init__(self):
self.variable = 1
def b(self):
print("old")
self.variable += 1
def new_b():
print("new")
self.variable += 15
self.__setattr__('b', new_b)
它会工作并做我们想要的:一旦一种对象覆盖了它的b
定义,其他任何对象都不会重新定义它们的Ab
方法。 ( overlays ,因为到目前为止每个人都说你不能为一个对象重新定义一个方法,而只是将它隐藏在另一个同名属性后面的调用者中,据我所知)。
这个好吗?
它不起作用,因为b
不是属于实例的属性,它属于类。 所以你不能在实例上删除它,因为它不是要删除的。
>>> a = A()
>>> list(a.__dict__)
[]
>>> list(A.__dict__)
['__module__', 'b', '__dict__', '__weakref__', '__doc__']
当ab
被求值时,Python 将看到a
没有名为b
实例属性并回退到该类。 (这有点复杂,因为当回退到类时,它不会简单地返回方法本身,而是绑定到实例a
的方法版本。)
既然不想删除类上的方法,那么要走的路就是替换实例上的方法。 我不知道你为什么试图用__setattr__
来做到这__setattr__
- 没有必要,只需像往常一样分配self.b = ...
。 你的尝试失败的原因是你的 lambda 需要一个名为self
的位置参数,但是当你查找它时,这个参数不会自动绑定到实例,因为它是一个实例属性,而不是一个类属性。
class A:
def b(self):
print('first')
self.b = lambda: print('second')
用法:
>>> a = A()
>>> a.b()
first
>>> a.b()
second
那么在python中你有两种类型的属性
instance/object attribute
是属于一个(且仅一个)对象的变量。 类的每个实例都指向它自己的属性变量。 这些属性在init构造函数中定义。 如果类属性是类描述符的一部分,因此您不能将其从对象属性中删除,例如self.__deleteattr__
或使用__setattr__
添加新属性,因为它会更改类描述符并反映在所有对象上。 这样的操作可能会产生破坏性的影响。
它也非常类似于类变量。 但是,您可以通过覆盖或重新分配来更改行为,如下所示
class A:
def b(self):
print("empty")
A.b = lambda self: print(f"second")
a = A()
a.b()
a.b()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.