2011-04-14 141 views
2

比方说,有一个库函数调用get_pack()返回一个包对象:对象类型转换

class Pack(object): 
    def __init__(self, name, weight): 
     self.name = name 
     self.weight = weight 
     ... 

我想要做的就是这个对象包装成我的对象,是让我们说CommercialPack其中有一些有用的功能:

class CommercialPack(Pack): 
    def get_delivery_price(self, distance): 
     return self.weight * PER_KM_PRICE * distance 
    ... 

然后创建返回CommercialPack,而不是包的功能。在Delphi或Java等其他语言中,您可以即时键入强制转换该对象。所以我想有这样的东西:

def get_commercial_pack(): 
    return CommercialPack(get_pack()) 

然后你有你所有需要的没有麻烦。因为我希望我的CommercialPack对象具有Pack对象所具有的所有属性和功能。我只想把它包装在我的新课堂中。基本上,我不想做这样的事情:

class CommercialPack(object): 
    def __init__(self, pack): 
     self.name = pack.name 
     self.weight = pack.weight 
     ... 

OR

class CommercialPack(object): 
    def __init__(self, pack): 
     self.pack = pack 

就像我说我在找一个优雅的解决方案,而不是,某种类型转换或什么我可以做的在Python中优雅。

非常感谢。

+1

相关:http://stackoverflow.com/questions/5516263/creating-an-object-from-a-base-class-object-in-python/5516330#5516330 – 2011-04-14 13:11:56

+0

@Sven:感谢您的链接。 – pocoa 2011-04-14 13:40:51

回答

2

也许这样的事情

class CommercialPack(object): 
    def __init__(self, pack): 
     self.__dict__.update(pack.__dict__) 

你甚至可以做到这一点,如果你不介意的包装和商业之间的共享状态包

class CommercialPack(object): 
    def __init__(self, pack): 
     self.__dict__ = pack.__dict__ 

在你的例子中应该没问题,因为你没有保留对包对象的任何其他引用。

PER_KM_PRICE = 100 

class Pack(object): 
    def __init__(self, name, weight): 
     self.name = name 
     self.weight = weight 


class CommercialPack(Pack): 
    def __init__(self, pack): 
     self.__dict__ = pack.__dict__ 

    def get_delivery_price(self, distance): 
     return self.weight * PER_KM_PRICE * distance 

def get_pack(): 
    return Pack("pack", 20) 

cp = CommercialPack(get_pack()) 
print cp.get_delivery_price(3) 
+0

谢谢你的回答。 Rumple Stiltskin是第一个回答的人,但我更喜欢这个。我希望Python会有类似commercial_object =(CommercialPack)pack_object的东西。因为有了这个解决方案,你仍然需要编写一些代码。所以,基本上CommercialPack将有两个不同的构造函数,一个带有参数包,另一个带有名称和权重。看起来像这是最好的我可以.. – pocoa 2011-04-14 13:37:24

+1

@pocoa:Python是动态类型,这意味着特别是每个对象包括其类型的信息。使用C或类似语言的类型转换*将内存中某些地址处的数据重新解释为不同类型。这在Python中是不可能的,因为类型与对象的数据一起存储。您可以在某些情况下通过分配'__class__'属性来更改对象的类型,但这被认为是令人困惑和错误的样式。 – 2011-04-14 13:52:29

+0

感谢Sven的解释。但是你可以做str(obj)对吗?我不知道它是如何实现的,但这就是为什么我认为可以用Java/Delphi的方式来完成它。 – pocoa 2011-04-14 14:10:20

4

这是否适合您?

#!/usr/bin/python 
PER_KM_PRICE = 10 

class Pack(object): 
    def __init__(self, name, weight): 
     self.name = name 
     self.weight = weight 

    def test_fn(self): 
     print "test" 

class CommercialPack(Pack): 
    def __init__(self, pack): 
     self.pack = pack 

    def get_delivery_price(self, distance): 
     return self.weight * PER_KM_PRICE * distance 

    def __getattr__(self, attr): 
     return getattr(self.pack,attr) 

您可以使用此类似:

>>> p = Pack(10, 20) 
>>> cp = CommercialPack(p) 
>>> cp.weight 
20 
>>> cp.get_delivery_price(10) 
2000 
>>> cp.test_fn() 
test 
+0

是的,这很好,但是当您需要访问Pack对象所具有的功能时,您仍然需要执行:p.pack.some_function_of_pack_object(),因为您的CommercialPack仍然是一个包对象,所以看起来不太好。 pack.pack ...看起来很奇怪。我真的不确定我是否可以在Python中使用它。 – pocoa 2011-04-14 13:13:36

+0

@pocoa:这是不正确的。如果在pack中有'def test_fn(self):print“test”',你仍然可以把它称为'cp.test_fn()'。尝试一下。 – 2011-04-14 13:16:17

+0

好吧,你说得对,我的错。谢谢你的答案。 – pocoa 2011-04-14 13:31:47

1

注:(以上希望)这是this answer重复附近

所以,你不想复制包的领域的一个无聊的清单,但想增加一点。这里有一个easy way to delegate resolution of unknown names使用__getattr__

class CommercialPack(object): 
    def __init__(self, pack): 
    self.pack = pack 
    self.bar = 10 

class CommercialPack(object): 
    def __init__(self, pack): 
    self.pack = pack 
    self.bar = 10 

    def __getattr__(self, name): 
    return getattr(self.pack, name) # not called for bar! 

现在神品:

>>> p = Pack('I am foo') 
>>> p.foo 
'I am foo' 
>>> cp = CommercialPack(p) 
>>> cp.foo 
'I am foo' 
>>> cp.bar 
10 
>>> _ 

所以,你可以添加方法和任何其他属性CommercialPack和透明地访问那些Pack

请注意,如果您添加的名称已在Pack中存在,则CommercialPack的属性将会影响同名Pack的属性。但是您可以随时通过pack属性访问它。