【问题标题】:How to un-override __setattr__ method?如何取消覆盖 __setattr__ 方法?
【发布时间】:2012-02-07 18:38:07
【问题描述】:

这个问题的目的是了解python中的内置函数是如何“内置”的。

如果我重写了 setattr 方法,我该如何取回它?例如,我有这样的“工作”类:

class WorkingSetAttr:
    def a(self): return 'a'
    def b(self): return 'b'

和这样的“非工作”类:

class NonWorkingSetAttr: 
    def a(self): return 'a'
    def b(self): return 'b'
    def __setattr__(self,a,b): pass

现在我创建对象 w 和 n,并运行以下命令:

w = WorkingSetAttr()
setattr(w,'a',w.b)
print "w.a = %s, w.b = %s" % (w.a(), w.b())

n = NonWorkingSetAttr()
setattr(n, 'a', n.b)
print "n.a = %s, n.b = %s" % (n.a(), n.b())

输出是:

w.a = b, w.b = b
n.a = a, n.b = b

请注意,n.a 应该打印“b”,但它会打印“a”,因为 setattr 不会更改属性。

问题是:我应该如何修改 object n 使其像 object w 一样工作。请注意,我的意思是对象,而不是类。

【问题讨论】:

  • 修改对象而不修改它们的类(几乎)总是一个坏主意。毕竟,实例意味着是特定类的实例!如果你打破这种关系,你最终会得到一些你不太了解并且无法调试的“事物”。
  • @KevinDTimm Python 内置方法setattr 设置了一个属性,该属性又调用了类对象上的__setattr__
  • __setattr__ 从 setattr 调用。看看它在“w”的情况下是如何工作的(输出从“a”变为“b”)。重点是:如果我只是“破坏”了内置函数,我该如何取回它。
  • 由于您使用的是 Python 2.x,因此您的类都应该继承自 object。 (一方面,这使得如何取消覆盖您的方法变得更加明显:只需将其重置为默认的 __setattr__,它继承自 object。)

标签: python class object dynamic setattr


【解决方案1】:

您可以从类对象中删除自定义__setattr__

>>> n = NonWorkingSetAttr()
>>> setattr(n, 'a', n.b)
>>> print("n.a = %s, n.b = %s" % (n.a(), n.b()))
n.a = a, n.b = b
>>> 
>>> del NonWorkingSetAttr.__setattr__
>>>
>>> setattr(n, 'a', n.b)
>>> print("n.a = %s, n.b = %s" % (n.a(), n.b()))
n.a = b, n.b = b

请注意,这会修改,而不是对象。您(几乎可以肯定)不想修改对象本身,因为您有一个看起来应该是 NonWorkingSetAttr 的对象,但实际上是某种您并不真正了解的动态事物。

如果你不能修改类,你可以只做一个子类,用object's 重写__setattr__

>>> class FixedNonWorkingSetAttr(NonWorkingSetAttr):
...     __setattr__ = object.__setattr__
... 
>>> n = FixedNonWorkingSetAttr()
>>> setattr(n, 'a', n.b)
>>> print("n.a = %s, n.b = %s" % (n.a(), n.b()))
n.a = b, n.b = b
>>> isinstance(n, NonWorkingSetAttr)
True

【讨论】:

  • 如果我错了更正,但是对象=类的实例?在python中对象是动态的?我的意思是它仍然是一个类的实例,即使它有一些额外的东西,对吧?
  • 是的:您可以调整对象。你甚至可以做一些非常麻烦的事情,比如动态修改实例的类。但是你不应该这样做,除非你绝对必须这样做,因为你最终会得到看起来像的对象,它们是某个类的实例,但实际上没有相同的方法。这将使调试陷入困境。
  • 想一想:如果你有一些代码定义了一个类,并实例化了那个类,你期望得到的对象——不管你用它做了多少计算——表现得像该类的一个实例。
  • 我认为选择 python 作为编程语言,你接受所有东西(除了内置的?)都可以随时改变。所以经典的调试不是解决问题的方法。对于您的最后一条评论,我认为这是积极的事情:您不受所写的“规则”的约束(以课程的形式),您有权随时更改规则。例如,当您可以将其字符串化 -> 存储 -> 取消字符串化和更改 -> 执行时,命令模式非常有趣(在 python 中很简单,在 C 中稍微困难一些)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多