创建对象后更改对象的类型(Python中的类型转换) [英] Change type of an object after its creation (typecasting in Python)
问题描述
在我的项目中,生成类型为 CubicObject
的对象 obj
.在运行时,应允许GUI设置将 obj
的类型更改为 Tofu
或 Box
(并返回),具体取决于用户的类型想要做什么以及他认为最能代表该对象的是什么.然后,用户应受益于在相应类中实现的特定算法.我正在寻找这种行为的一个很好的实现.我玩过下面的代码,该代码更改了 __ class __
属性,但是我确信这是不好的风格.
In my project, I generate an object obj
of type CubicObject
. At runtime, a GUI setting should be allowed to change the type of obj
to Tofu
or Box
(and back), depending on what the user wants to do and what (s)he thinks the object is best represented by. Then the user should benefit from specific algorithms implemented in the corresponding classes. I am looking for a nice implementation of this behaviour. I have played with the code below, which changes the __class__
attribute, but I am sure that this is bad style.
class CubicObject(object):
name = 'Baseclass'
def __init__(self, sidelength):
self.sidelength = sidelength
class Tofu(CubicObject):
name = 'Class A'
def eat(self):
print("I've eaten a volume of %s. " % (self.sidelength**3))
class Box(CubicObject):
name = 'Class B'
def paint(self):
print("I painted a surface of %s. " % (self.sidelength**2 * 6))
# user only knows the object is vaguely cubic
obj = CubicObject(sidelength=1.0)
# user thinks the object is a Box
obj.__class__ = Box
obj.paint()
# user changes mind and thinks its a piece of Tofu
obj.__class__ = Tofu
obj.eat()
obj.paint() # generates an error as it should, since we cannot paint Tofu
我的两个问题是:
- 类
A
的什么样的属性被转移到对象'obj'当我更改其__ class __
属性时?所谓的功能
以及更新了哪些属性,或者obj如何进行其他操作将其名称更改为A吗? - 还有哪些更清洁的方式可以实现我想要的行为?如果必要时,我可以销毁对象
obj
并重新创建一个对象,但在这种情况下,我想以通用方式(例如obj = RoundObject(subclasstype ='Tofu')
,因为代码).
- What kind properties of class
A
are transferred to the object 'obj' when I change its__class__
attribute? What functions are called
and what attributes are updated, or how else does it happen that obj changes its name to the one of A? - What other, cleaner ways exist to implement the behaviour I want? If
necessary, I could destroy the object
obj
and recreate another one, but in this case I would like to do so in a generic manner (likeobj = RoundObject(subclasstype='Tofu')
because of other parts of the code).
潜在的问题是,我允许用户在 CubicObject
的子类中实现自己的功能,并且应该能够在程序运行时在这些子类之间进行切换.
The underlying problem is that I allow the user to implement own functions in subclasses of CubicObject
and that one should be able to switch between these subclasses while the program is running.
推荐答案
将类A的哪种属性传递给对象'obj'当我更改其 class 属性时?所谓的功能是什么更新了哪些属性,或者obj如何进行其他操作将其名称更改为A吗?
What kind properties of class A are transferred to the object 'obj' when I change its class attribute? What functions are called and what attributes are updated, or how else does it happen that obj changes its name to the one of A?
所有实例分配的属性都将保留-即,Python对象通常具有 __ dict __
属性,其中记录了所有实例属性-将保留.并且对象的类实际上更改为分配的类.(Python运行时禁止为具有不同内存布局的对象分配 __ class __
).也就是说:新类上的所有方法和类属性都可用于该实例,而先前类的方法或类属性均不存在,就好像该对象是在此新类中创建的一样.分配不会触发任何副作用(例如:没有调用特殊方法)所以-对于您正在做的事情,它有效".
All instance assigned attributes are kept - that is, Python objects normally have a __dict__
attribute where all instance attributes are recorded - that is kept. And the object's class effectively changes to the one assigned. (Python runtime forbids __class__
assignment for objects which have a different memory layout). That is: all methods and class attributes on the new class are available for the instance, and none of the methods or class attributes of the previous class are there, as if the object had been created in this new class.
No side effects are triggered by the assignment (as in: no special method is called)
So - for what you are making, it "works".
还有什么更清洁的方式可以实现我想要的行为?如果必要时,我可以销毁对象obj并重新创建一个对象,但在这种情况下,我想以一种通用的方式进行操作(例如obj =RoundObject(subclasstype ='Tofu'),因为代码的其他部分.
What other, cleaner ways exist to implement the behaviour I want? If necessary, I could destroy the object obj and recreate another one, but in this case I would like to do so in a generic manner (like obj = RoundObject(subclasstype='Tofu') because of other parts of the code).
是的,正如您已经指出的那样,这不是最好的处理方式.您可能拥有的类层次结构具有所需的不同方法,这些方法将您的对象作为属性-并根据您正在执行的操作在此外部层次结构中创建一个新对象-并保持其核心对象的属性不变.这就是适配器模式.
Yes, as you've noted, this not is the best way of doing things. What you could have is a class hierarchy with the distinct methods you need, that get your object as an attribute - and depending on what you are doing, you create a new object os this outer hierarchy - and keep your core object with its attributes unchanged. This is known as the 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
,它使您可以使用适配器模式编写庞大而复杂的系统.因此,您可以拥有数百种不同类型的对象-您可以将它们标记为具有立方"接口,只要它们具有 side_length
属性即可.然后,您会拥有数十个类,它们使用 side_length
属性执行多维数据集"操作- zope.interface
工具将允许您将以下数十个类中的任何一个用于任何具有Cubic接口的对象,只需通过将原始对象作为参数传递给所需方法的接口即可.
You can roll it on your own, manual classes, or use a well known and tested library that implements features to automate parts of the process. One such library is zope.interface
, that allows you to write huge and complex systems using the adapter pattern. So you can have hundreds of different types of objects - you can mark them as having the interface "Cubic" as long as they have a side_length
attribute. And then you cna have tens of classes that do "Cube" things with the side_length
attribute - the zope.interface
facilities will allow you to use any of these tens of classes with any of the objects that have the Cubic interface by simply calling the interface for the desired method passing the original object as a parameter.
但是 zope.interfaces
可能有点难掌握,因为在使用了近二十年后,根据需要编写的文档不多(有时,人们诉诸于使用XML文件来声明接口)和适配器-只需跳过任何处理XML的文档即可),因此对于较小的项目,您可以按上述方法手动滚动.
But zope.interfaces
may be a little hard to grasp, due to poor documentation done as needed over nearly two decades of use (and at some point, people resorted to use XML files to declare interfaces and adapters - just skip any docs that deal with XML), so for smaller projects, you can just roll it manually as above.
我当前的实现已经使用了一个委托对象,但是不切实际,因为它隐藏了API中所有有趣的功能我想在该委托对象中提供的内容(我通常会重复委托对象的所有功能,但这很容易混淆人们).
My current implementation already uses a delegate object, but it is impractical because it hides all the interesting functions in the API that I want to provide in that delegate object (I usually duplicate all functions of the delegate object, but that understandably confuses people).
由于您的实际使用示例很大,因此确实可以学习和使用 zope.interface
-但如果要允许访问,则是完全接口/注册表/适配器系统的另一种解决方法豆腐上的几种 Cube
方法中的一种,而其他方法则是在魔术 __ getattr __
Python之上的 BaseMethods
类上实现的允许您以透明的方式检索所引用对象上的方法和属性的方法,而无需重新编写:
Since your real-use example is big, that s a case to indeed learn and use zope.interface
- but another workaround to a fully interface/registry/adapter system, if you want to permit access of several Cube
methods on Tofu
and others is to implement on the BaseMethods
class I have above the magic __getattr__
Python method that would allow you to retrieve methods and attributes on the referred object in a transparent way, with no re-write needed:
class BaseMethods(object):
def __init__(self, related):
self.related = related
def __getattr__(self, attr):
return getattr(self.related, attr)
这篇关于创建对象后更改对象的类型(Python中的类型转换)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!