将 self.__class__ 设置为其他东西有多危险? [英] How dangerous is setting self.__class__ to something else?
问题描述
假设我有一个类,它有许多子类.
Say I have a class, which has a number of subclasses.
我可以实例化这个类.然后我可以将它的 __class__
属性设置为子类之一.我已经有效地将类类型更改为其子类的类型,在活动对象上.我可以调用它的方法来调用这些方法的子类版本.
I can instantiate the class. I can then set its __class__
attribute to one of the subclasses. I have effectively changed the class type to the type of its subclass, on a live object. I can call methods on it which invoke the subclass's version of those methods.
那么,这样做有多危险?看起来很奇怪,但是做这样的事情是错误吗?尽管能够在运行时更改类型,但这是应该完全避免的语言特性吗?为什么或为什么不?
So, how dangerous is doing this? It seems weird, but is it wrong to do such a thing? Despite the ability to change type at run-time, is this a feature of the language that should completely be avoided? Why or why not?
(根据回复,我会发布一个更具体的问题,说明我想做什么,以及是否有更好的选择.
(Depending on responses, I'll post a more-specific question about what I would like to do, and if there are better alternatives).
推荐答案
以下是我能想到的导致这种危险的事情的列表,按从最坏到最坏的粗略顺序排列:
Here's a list of things I can think of that make this dangerous, in rough order from worst to least bad:
- 阅读或调试您的代码的人可能会感到困惑.
- 您不会获得正确的
__init__
方法,因此您可能不会正确初始化所有实例变量(甚至根本没有初始化). - 2.x 和 3.x 之间的差异足够大,移植可能会很痛苦.
- 在类方法、手工编码的描述符、方法解析顺序的挂钩等方面存在一些边缘情况,并且它们在经典类和新型类之间(同样,在 2.x 和 3.x 之间)有所不同.x).
- 如果您使用
__slots__
,则所有类都必须具有相同的插槽.(如果你有兼容但不同的插槽,它可能一开始看起来可以工作,但会做一些可怕的事情......) - 新式类中的特殊方法定义可能不会改变.(事实上,这在实践中适用于所有当前的 Python 实现,但它没有记录可以工作,所以......)
- 如果您使用
__new__
,事情将不会按照您天真预期的方式进行. - 如果类有不同的元类,事情会变得更加混乱.
- It's likely to be confusing to someone reading or debugging your code.
- You won't have gotten the right
__init__
method, so you probably won't have all of the instance variables initialized properly (or even at all). - The differences between 2.x and 3.x are significant enough that it may be painful to port.
- There are some edge cases with classmethods, hand-coded descriptors, hooks to the method resolution order, etc., and they're different between classic and new-style classes (and, again, between 2.x and 3.x).
- If you use
__slots__
, all of the classes must have identical slots. (And if you have the compatible but different slots, it may appear to work at first but do horrible things…) - Special method definitions in new-style classes may not change. (In fact, this will work in practice with all current Python implementations, but it's not documented to work, so…)
- If you use
__new__
, things will not work the way you naively expected. - If the classes have different metaclasses, things will get even more confusing.
同时,在许多您认为这是必要的情况下,还有更好的选择:
Meanwhile, in many cases where you'd think this is necessary, there are better options:
- 使用工厂动态创建适当类的实例,而不是创建基实例,然后将其转换为派生实例.
- 使用
__new__
或其他机制来钩住构造. - 重新设计事物,让您拥有一个具有某些数据驱动行为的类,而不是滥用继承.
- Use a factory to create an instance of the appropriate class dynamically, instead of creating a base instance and then munging it into a derived one.
- Use
__new__
or other mechanisms to hook the construction. - Redesign things so you have a single class with some data-driven behavior, instead of abusing inheritance.
作为最后一个最常见的特定情况,只需将所有变量方法"放入类中,这些类的实例作为父类"的数据成员保存,而不是放入子类中.与其改变self.__class__ = OtherSubclass
,不如做self.member = OtherSubclass(self)
.如果你真的需要方法来神奇地改变,自动转发(例如,通过 __getattr__
)是一种比动态改变类更常见的 Python 习惯用法.
As a very most common specific case of the last one, just put all of the "variable methods" into classes whose instances are kept as a data member of the "parent", rather than into subclasses. Instead of changing self.__class__ = OtherSubclass
, just do self.member = OtherSubclass(self)
. If you really need methods to magically change, automatic forwarding (e.g., via __getattr__
) is a much more common and pythonic idiom than changing classes on the fly.
这篇关于将 self.__class__ 设置为其他东西有多危险?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!