A 类的哪些属性被传递给对象 'obj'
当我改变它的时候class属性?调用了什么函数以及
更新了哪些属性,或者 obj 是如何发生的
将其名称更改为 A 之一?
所有实例分配的属性都会被保留 - 也就是说,Python 对象通常有一个__dict__
记录所有实例属性的属性 - 被保留。并且对象的类有效地更改为分配的类。 (Python 运行时禁止__class__
具有不同内存布局的对象的分配)。也就是说:新类上的所有方法和类属性都可用于该实例,并且前一个类的方法或类属性都不存在,就好像该对象是在这个新类中创建的一样。
赋值不会触发任何副作用(如:不调用特殊方法)
因此,对于你正在制作的东西来说,它是“有效的”。
还有哪些其他更干净的方法可以实现我想要的行为?如果
必要时,我可以销毁对象 obj 并重新创建另一个对象,
但在这种情况下,我想以通用方式执行此操作(例如 obj =
RoundObject(subclasstype='Tofu') 因为代码的其他部分)。
是的,正如您所指出的,这不是最好的做事方式。
你可以拥有一个类层次结构,其中包含你需要的不同方法,这些方法将你的对象作为属性 - 并且根据你在做什么,你在这个外部层次结构中创建一个新对象 - 并保持你的核心对象及其属性不变。这被称为适配器模式 https://en.wikipedia.org/wiki/Adapter_pattern.
class CubicObject(object):
name = 'Baseclass'
def __init__(self, sidelength):
self.sidelength = sidelength
class BaseMethods(object):
def __init__(self, related):
self.related = related
class Tofu(BaseMethods):
name = 'Class A'
def eat(self):
print("I've eaten a volume of %s. " % (self.related.sidelength**3))
class Box(BaseMethods):
name = 'Class B'
def paint(self):
print("I painted a surface of %s. " % (self.related.sidelength**2 * 6))
# user only knows the object is vaguely cubic
obj = CubicObject(sidelength=1.0)
# user thinks the object is a Box
box = Box(obj)
box.paint()
# user changes mind and thinks its a piece of Tofu
tofu = Tofu(obj)
tofu.eat()
# or simply:
Tofu(obj).eat()
您可以在自己的手动类上滚动它,或者使用众所周知且经过测试的库来实现部分流程自动化的功能。一个这样的库是zope.interface https://docs.zope.org/zope.interface/,这允许您使用适配器模式编写庞大而复杂的系统。因此,您可以拥有数百种不同类型的对象 - 您可以将它们标记为具有“Cubic”接口,只要它们具有side_length
属性。然后你可以有数十个类用以下方法做“立方体”的事情side_length
属性 - 的zope.interface
设施将允许您将这数十个类中的任何一个与具有 Cubic 接口的任何对象一起使用,只需调用所需方法的接口并将原始对象作为参数传递即可。
But zope.interfaces
可能有点难以掌握,因为在近二十年的使用中,根据需要完成的文档很差(并且在某些时候,人们诉诸使用 XML 文件来声明接口和适配器 - 只需跳过任何处理 XML 的文档),所以对于较小的项目,您可以像上面那样手动滚动它。
我当前的实现已经使用了委托对象,但它是
不切实际,因为它隐藏了 API 中所有有趣的功能
我想在该委托对象中提供(我通常复制
委托对象的所有功能,但这可以理解地令人困惑
人们)。
由于您的实际使用示例很大,因此确实是学习和使用的案例zope.interface
- 但是如果您想允许多个用户访问,则可以使用完整的接口/注册表/适配器系统的另一种解决方法Cube
上的方法Tofu
和其他的是实施BaseMethods
我有高于魔法的课程__getattr__
Python 方法允许您以透明的方式检索引用对象的方法和属性,无需重写:
class BaseMethods(object):
def __init__(self, related):
self.related = related
def __getattr__(self, attr):
return getattr(self.related, attr)