重新定义对象的方法
Redefine Method of an Object
我有一个 class,其中一个方法应该只 运行 一次。当然,它可以很容易地用人为的 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')
returns <bound method A.b of <__main__.A object at 0x000001CDC6742FD0>>
,这对我来说听起来很愚蠢:为什么 method
与 attribute
有任何不同,因为 [=14= 中的所有内容] 只是对对象的引用?为什么我可以__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
没有按预期使用点符号。当然,考虑到我们已经在 b
中获得了对它的引用,我们可以完全放弃 lambda 中的 self
属性。但这不是设计不正确吗?
我越想 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)
它会工作并做我们想做的事情:none 其他对象将重新定义它们的 A.b
方法,一旦一种对象类型 overlays 它的 b
定义。 (overlays,因为到目前为止每个人都说你不能为一个对象重新定义一个方法,而只是将它从调用者隐藏在另一个同名属性后面,据我所知明白)。
这样好吗?
它不起作用,因为 b
不是属于实例的属性,它属于 class。所以你不能在实例上删除它,因为它不在那里被删除。
>>> a = A()
>>> list(a.__dict__)
[]
>>> list(A.__dict__)
['__module__', 'b', '__dict__', '__weakref__', '__doc__']
当 a.b
被求值时,Python 会发现 a
没有名为 b
的实例属性,然后回退到 class。 (它有点复杂,因为当回退到 class 时,它不会简单地 return 方法本身,而是绑定到实例 a
的方法版本。)
由于您不想删除 class 上的方法,因此方法是替换实例上的方法。我不知道您为什么尝试使用 __setattr__
来执行此操作 - 没有必要,只需照常分配 self.b = ...
即可。您尝试失败的原因是因为您的 lambda 需要一个名为 self
的位置参数,但是这个参数 不会 在您查找时自动绑定到实例,因为它是实例属性,而不是 class 属性。
class A:
def b(self):
print('first')
self.b = lambda: print('second')
用法:
>>> a = A()
>>> a.b()
first
>>> a.b()
second
那么在 python 你有 2 种类型的属性
- 一个class属性是一个属于某个class的变量,而不是一个特定的对象。此 class 的每个实例共享相同的变量。这些属性通常在 init 构造函数
之外定义
instance/object attribute
是属于一个(且仅一个)对象的变量。 class 的每个实例都指向它自己的属性变量。这些属性在 init 构造函数中定义。
在 class 属性的情况下,它是 class 描述符的一部分,因此您不能从 self.__deleteattr__
之类的对象属性中删除它,也不能使用 [=13= 添加新属性] 因为它改变了 class 描述符并反映在所有对象上。这样的操作可能会产生毁灭性的影响。
它也非常类似于 class 变量。但是,您可以通过覆盖或重新分配来更改行为,如下所示
class A:
def b(self):
print("empty")
A.b = lambda self: print(f"second")
a = A()
a.b()
a.b()
我有一个 class,其中一个方法应该只 运行 一次。当然,它可以很容易地用人为的 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')
returns <bound method A.b of <__main__.A object at 0x000001CDC6742FD0>>
,这对我来说听起来很愚蠢:为什么 method
与 attribute
有任何不同,因为 [=14= 中的所有内容] 只是对对象的引用?为什么我可以__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
没有按预期使用点符号。当然,考虑到我们已经在 b
中获得了对它的引用,我们可以完全放弃 lambda 中的 self
属性。但这不是设计不正确吗?
我越想 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)
它会工作并做我们想做的事情:none 其他对象将重新定义它们的 A.b
方法,一旦一种对象类型 overlays 它的 b
定义。 (overlays,因为到目前为止每个人都说你不能为一个对象重新定义一个方法,而只是将它从调用者隐藏在另一个同名属性后面,据我所知明白)。
这样好吗?
它不起作用,因为 b
不是属于实例的属性,它属于 class。所以你不能在实例上删除它,因为它不在那里被删除。
>>> a = A()
>>> list(a.__dict__)
[]
>>> list(A.__dict__)
['__module__', 'b', '__dict__', '__weakref__', '__doc__']
当 a.b
被求值时,Python 会发现 a
没有名为 b
的实例属性,然后回退到 class。 (它有点复杂,因为当回退到 class 时,它不会简单地 return 方法本身,而是绑定到实例 a
的方法版本。)
由于您不想删除 class 上的方法,因此方法是替换实例上的方法。我不知道您为什么尝试使用 __setattr__
来执行此操作 - 没有必要,只需照常分配 self.b = ...
即可。您尝试失败的原因是因为您的 lambda 需要一个名为 self
的位置参数,但是这个参数 不会 在您查找时自动绑定到实例,因为它是实例属性,而不是 class 属性。
class A:
def b(self):
print('first')
self.b = lambda: print('second')
用法:
>>> a = A()
>>> a.b()
first
>>> a.b()
second
那么在 python 你有 2 种类型的属性
- 一个class属性是一个属于某个class的变量,而不是一个特定的对象。此 class 的每个实例共享相同的变量。这些属性通常在 init 构造函数 之外定义
instance/object attribute
是属于一个(且仅一个)对象的变量。 class 的每个实例都指向它自己的属性变量。这些属性在 init 构造函数中定义。
在 class 属性的情况下,它是 class 描述符的一部分,因此您不能从 self.__deleteattr__
之类的对象属性中删除它,也不能使用 [=13= 添加新属性] 因为它改变了 class 描述符并反映在所有对象上。这样的操作可能会产生毁灭性的影响。
它也非常类似于 class 变量。但是,您可以通过覆盖或重新分配来更改行为,如下所示
class A:
def b(self):
print("empty")
A.b = lambda self: print(f"second")
a = A()
a.b()
a.b()