2024-03-29 06:24:24 发布
网友
假设我有一个类,它有一些子类。
我可以实例化类。然后我可以将其__class__属性设置为其中一个子类。在一个活动对象上,我有效地将类类型更改为其子类的类型。我可以在它上调用调用那些方法的子类版本的方法。
__class__
那么,这么做有多危险?看起来很奇怪,但是做这样的事是不是有错?尽管可以在运行时更改类型,但这是否是语言中应该完全避免的特性?为什么或者为什么不?
(根据回答,我将发布一个关于我想做什么以及是否有更好的选择的更具体的问题)。
在任意类上,这极不可能工作,而且即使工作也非常脆弱。这基本上与从一个类的方法中提取底层函数对象,并在不是原始类实例的对象上调用它们是一样的。这是否有效取决于内部实现细节,并且是一种非常紧密耦合的形式。
也就是说,将对象的__class__在一组经过特殊设计的类中进行更改,以便以这种方式使用,这是非常好的。我知道你可以这么做很长一段时间,但是我还没有找到一个更好的解决方案没有同时出现在脑海中的技术的用途。所以如果你认为你有一个用例,就去做吧。只需在你的评论/文档中清楚地说明发生了什么。尤其是,这意味着所有相关类的实现都必须尊重它们的不变量/假设等,而不是能够孤立地考虑每个类,所以您需要确保任何处理相关代码的人都知道这一点!
如果您有一个长时间运行的应用程序,并且您需要用同一类的新版本替换某个对象的旧版本而不丢失数据(例如,在某些reload(mymodule)之后并且不重新加载未更改的模块),则分配__class__属性非常有用。另一个例子是如果您实现持久性-类似于pickle.load。
reload(mymodule)
pickle.load
不鼓励使用所有其他用法,特别是如果您可以在启动应用程序之前编写完整的代码。
下面是我能想到的使这件事变得危险的事情的清单,大致顺序是从最坏到最坏:
__init__
__slots__
__new__
同时,在许多情况下,如果你认为这是必要的,还有更好的选择:
作为上一个非常常见的特定情况,只需将所有“变量方法”放入其实例作为“父”的数据成员保存的类中,而不是放入子类中。不要改变self.__class__ = OtherSubclass,只要做self.member = OtherSubclass(self)。如果您真的需要神奇地更改方法,那么自动转发(例如,通过__getattr__)是一个比动态更改类更常见的python习惯用法。
self.__class__ = OtherSubclass
self.member = OtherSubclass(self)
__getattr__
在任意类上,这极不可能工作,而且即使工作也非常脆弱。这基本上与从一个类的方法中提取底层函数对象,并在不是原始类实例的对象上调用它们是一样的。这是否有效取决于内部实现细节,并且是一种非常紧密耦合的形式。
也就是说,将对象的
__class__
在一组经过特殊设计的类中进行更改,以便以这种方式使用,这是非常好的。我知道你可以这么做很长一段时间,但是我还没有找到一个更好的解决方案没有同时出现在脑海中的技术的用途。所以如果你认为你有一个用例,就去做吧。只需在你的评论/文档中清楚地说明发生了什么。尤其是,这意味着所有相关类的实现都必须尊重它们的不变量/假设等,而不是能够孤立地考虑每个类,所以您需要确保任何处理相关代码的人都知道这一点!如果您有一个长时间运行的应用程序,并且您需要用同一类的新版本替换某个对象的旧版本而不丢失数据(例如,在某些
reload(mymodule)
之后并且不重新加载未更改的模块),则分配__class__
属性非常有用。另一个例子是如果您实现持久性-类似于pickle.load
。不鼓励使用所有其他用法,特别是如果您可以在启动应用程序之前编写完整的代码。
下面是我能想到的使这件事变得危险的事情的清单,大致顺序是从最坏到最坏:
__init__
方法,因此您可能不会正确初始化所有实例变量(甚至根本不会)。__slots__
,则所有类都必须具有相同的插槽。(如果你有兼容的但不同的插槽,它可能一开始看起来工作,但做了可怕的事情…)__new__
,事情就不会像您天真地期望的那样工作。同时,在许多情况下,如果你认为这是必要的,还有更好的选择:
__new__
或其他机制挂接构造。作为上一个非常常见的特定情况,只需将所有“变量方法”放入其实例作为“父”的数据成员保存的类中,而不是放入子类中。不要改变
self.__class__ = OtherSubclass
,只要做self.member = OtherSubclass(self)
。如果您真的需要神奇地更改方法,那么自动转发(例如,通过__getattr__
)是一个比动态更改类更常见的python习惯用法。相关问题 更多 >
编程相关推荐