将 self.__class__ 设置为其他东西有多危险? [英] How dangerous is setting self.__class__ to something else?

查看:50
本文介绍了将 self.__class__ 设置为其他东西有多危险?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个类,它有许多子类.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆