将自我.__ class__设置为其他东西有多危险?

imm*_*imm 28 python python-2.x

假设我有一个类,它有一个数字子类.

我可以实例化这个类.然后我可以将其__class__属性设置为其中一个子类.我已经在类活动对象上有效地将类类型更改为其子类的类型.我可以调用它上面的方法来调用子类的那些方法的版本.

这样做有多危险?这看起来很奇怪,但做这样的事情是不对的吗?尽管能够在运行时更改类型,这是否应该完全避免使用该语言的功能?为什么或者为什么不?

(根据回复,我会发布一个更具体的问题,关于我想做什么,以及是否有更好的选择).

aba*_*ert 22

这里列出了我能想到的一些事情,这些事情使得这种事情变得危险,从最坏到最不好的粗略顺序:

  • 阅读或调试代码的人可能会感到困惑.
  • 您将无法获得正确的__init__方法,因此您可能无法正确初始化所有实例变量(甚至根本没有).
  • 2.x和3.x之间的差异足够大,以至于移植可能会很痛苦.
  • 有一些边缘情况有类方法,手工编码描述符,方法解析顺序的钩子等,它们在经典类和新风格类之间是不同的(同样,在2.x和3.x之间).
  • 如果使用__slots__,所有类必须具有相同的插槽.(如果你有兼容但不同的插槽,它可能看起来首先工作,但做了可怕的事......)
  • 新样式类中的特殊方法定义可能不会更改.(事实上​​,这将适用于所有当前的Python实现,但它没有记录工作,所以...)
  • 如果你使用__new__,事情将不会像你天真的预期那样发挥作用.
  • 如果类具有不同的元类,事情将变得更加混乱.

同时,在许多情况下,您认为这是必要的,有更好的选择:

  • 使用工厂动态创建相应类的实例,而不是创建基本实例,然后将其重新组合为派生实例.
  • 使用__new__或其他机制钩住建筑.
  • 重新设计事物,这样你就有了一个带有一些数据驱动行为的类,而不是滥用继承.

作为最后一个最常见的特定情况,只需将所有"变量方法"放入其实例作为"父"的数据成员而不是子类的类中.而不是改变self.__class__ = OtherSubclass,只是做self.member = OtherSubclass(self).如果你真的需要神奇地改变方法,那么自动转发(例如,通过__getattr__)是一种比在飞行中改变类更常见和更加疯狂的习语.


hyn*_*cer 15

__class__如果您有很长时间运行应用程序并且需要在不丢失数据的情况下用同一类的较新版本替换某个对象的旧版本,则分配该属性非常有用,例如,在reload(mymodule)没有重新加载未更改的模块之后.其他示例是如果您实现持久性 - 类似于pickle.load.

不鼓励使用所有其他用法,特别是如果您可以在启动应用程序之前编写完整的代码.

  • +1用于合理用于分配`__class__`.至少这应该让某人不敢问:"但如果这太糟糕了,为什么Python会让我这么做呢?" (6认同)

Ben*_*Ben 6

在任意类上,这极不可能起作用,而且即使起作用也非常脆弱。这与从一个类的方法中提取底层函数对象,并在不是原始类实例的对象上调用它们基本上是一样的。这是否有效取决于内部实现细节,并且是一种非常紧密的耦合形式。

也就是说,在专门设计用于这种方式的__class__一组类中更改对象可能是完全没问题的。我很早就知道你可以这样做,但我还没有找到这种技术的用途,同时想到更好的解决方案。因此,如果您认为自己有一个用例,那就去做吧。只需在您的评论/文档中明确发生了什么即可。特别是,这意味着所涉及的所有类的实现必须尊重它们的所有不变量/假设/等,而不是能够孤立地考虑每个类,因此您需要确保任何从事以下任何一项工作的人所涉及的代码知道这一点!