Object type casting in Python (design suggestion)
Let's say there is a library f开发者_开发问答unction called get_pack() which returns a Pack object:
class Pack(object):
def __init__(self, name, weight):
self.name = name
self.weight = weight
...
What I want to do is to wrap this object into my object which is let's say CommercialPack which has a couple of useful functions:
class CommercialPack(Pack):
def get_delivery_price(self, distance):
return self.weight * PER_KM_PRICE * distance
...
And then create a function which returns CommercialPack instead of Pack. In some other languages like Delphi or Java, you can type cast that object on the fly. So I want to have something like:
def get_commercial_pack():
return CommercialPack(get_pack())
and then you have all you need with no hassle. Because I would like my CommercialPack object to have all the properties and functions that Pack object has. I just want to wrap it inside my new class. Basically I don't want to do something like this:
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
I'm looking for an elegant solution instead like I said, some kind of type casting or whatever I can do elegantly in Python.
Thanks very much.
Will this work for you?
#!/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)
You can use this like:
>>> p = Pack(10, 20)
>>> cp = CommercialPack(p)
>>> cp.weight
20
>>> cp.get_delivery_price(10)
2000
>>> cp.test_fn()
test
Perhaps something like this
class CommercialPack(object):
def __init__(self, pack):
self.__dict__.update(pack.__dict__)
You can even do this if you don't mind sharing state between the pack and the commercial pack
class CommercialPack(object):
def __init__(self, pack):
self.__dict__ = pack.__dict__
It should be ok in your example since you aren't keeping any other references to the pack object
eg.
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)
Note: this is a duplicate of this answer nearby (hopefully above.)
So you don't want to copy a boring list of Pack's fields, but want to add a bit. There's an easy way to delegate resolution of unknown names using __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!
Now the magic works:
>>> p = Pack('I am foo')
>>> p.foo
'I am foo'
>>> cp = CommercialPack(p)
>>> cp.foo
'I am foo'
>>> cp.bar
10
>>> _
So you can add methods and any other attributes to CommercialPack
and transparently access those of Pack
.
Please note that if you add a name that is already present in Pack
, CommercialPack
's attribute will shadow the same-named Pack
's attribute. But you can always access it via the pack
attribute.
精彩评论