我有两个类 - 一个继承自另一个。我想知道如何转换(或创建一个新的变量)子类。我已经搜索了一下,大部分都是“向下倾斜”,这似乎是不赞成的,并且有一些稍微狡猾的解决方法,如设置实例。类 - 虽然这似乎不是一个很好的方式去。
例如。 http://www.gossamer-threads.com/lists/python/python/871571 http://code.activestate.com/lists/python-list/311043/
子问题 - 真的那么糟糕吗?如果是这样的话?
我在下面简化了代码示例 - 基本上我有一些代码在对x,y数据进行一些分析后创建了一个Peak对象。在这段代码之外我知道数据是'PSD'数据功率谱密度 - 所以它有一些额外的属性。我如何从山顶投降到Psd_Peak?
"""
Two classes
"""
import numpy as np
class Peak(object) :
"""
Object for holding information about a peak
"""
def __init__(self,
index,
xlowerbound = None,
xupperbound = None,
xvalue= None,
yvalue= None
):
self.index = index # peak index is index of x and y value in psd_array
self.xlowerbound = xlowerbound
self.xupperbound = xupperbound
self.xvalue = xvalue
self.yvalue = yvalue
class Psd_Peak(Peak) :
"""
Object for holding information about a peak in psd spectrum
Holds a few other values over and above the Peak object.
"""
def __init__(self,
index,
xlowerbound = None,
xupperbound = None,
xvalue= None,
yvalue= None,
depth = None,
ampest = None
):
super(Psd_Peak, self).__init__(index,
xlowerbound,
xupperbound,
xvalue,
yvalue)
self.depth = depth
self.ampest = ampest
self.depthresidual = None
self.depthrsquared = None
def peakfind(xdata,ydata) :
'''
Does some stuff.... returns a peak.
'''
return Peak(1,
0,
1,
.5,
10)
# Find a peak in the data.
p = peakfind(np.random.rand(10),np.random.rand(10))
# Actually the data i used was PSD -
# so I want to add some more values tot he object
p_psd = ????????????
修改
感谢您的贡献......我担心我感觉很沮丧(geddit?),因为到目前为止的答案似乎表明我花时间将转换器从一种类型编码到另一种类型。我已经提出了一种更自动的方法 - 基本上循环遍历类的属性并将它们相互转移。这对人们有什么影响 - 这是一件合理的事情 - 或者它会给你带来麻烦吗?
def downcast_convert(ancestor, descendent):
"""
automatic downcast conversion.....
(NOTE - not type-safe -
if ancestor isn't a super class of descendent, it may well break)
"""
for name, value in vars(ancestor).iteritems():
#print "setting descendent", name, ": ", value, "ancestor", name
setattr(descendent, name, value)
return descendent
答案 0 :(得分:9)
你实际上并没有在Python中“强制转换”对象。相反,你通常会转换它们 - 拿走旧物体,创建一个新物体,扔掉旧物体。为了实现这一点,必须将新对象的类设计为在其__init__
方法中获取旧对象的实例并执行相应的操作(有时,如果类可以接受多种对象,则创建它,它将有用于此目的的替代构造函数。)
您确实可以通过将其__class__
属性指向其他类来更改实例的类,但该类可能无法与该实例一起正常工作。此外,这种做法是恕我直言“气味”,表明你应该采取不同的方法。
在实践中,您几乎不需要担心Python中的类型。 (有明显的例外:例如,尝试添加两个对象。即使在这种情况下,检查也尽可能广泛;这里,Python会检查数字类型,或者可以转换为数字的类型,而不是一个特定的类型。)因此,对象的实际类是很重要的,只要它具有任何代码使用它所需的属性和方法。
答案 1 :(得分:1)
这不是一个向下倾斜的问题(恕我直言)。 peekfind()创建一个Peak对象 - 它不能向下转换,因为它不是Psd_Peak对象 - 后来你想从它创建一个Psd_Peak对象。在像C ++这样的东西中,您可能依赖于默认的复制构造函数 - 但即使在C ++中也不行,因为您的Psd_Peak类在其构造函数中需要更多参数。在任何情况下,python都没有复制构造函数,所以你最终会得到相当冗长的(fred = fred,jane = jane)东西。
一个好的解决方案可能是创建一个对象工厂并传递你想要peekfind()的Peak对象类型,然后让它为你创建一个对象工厂。
def peak_factory(peak_type, index, *args, **kw):
"""Create Peak objects
peak_type Type of peak object wanted
(you could list types)
index index
(you could list params for the various types)
"""
# optionally sanity check parameters here
# create object of desired type and return
return peak_type(index, *args, **kw)
def peakfind(peak_type, xdata, ydata, **kw) :
# do some stuff...
return peak_factory(peak_type,
1,
0,
1,
.5,
10,
**kw)
# Find a peak in the data.
p = peakfind(Psd_Peak, np.random.rand(10), np.random.rand(10), depth=111, ampest=222)
答案 2 :(得分:0)
请参见以下示例。另外,请务必遵守LSP (Liskov替换原则)
class ToBeCastedObj:
def __init__(self, *args, **kwargs):
pass # whatever you want to state
# original methods
# ...
class CastedObj(ToBeCastedObj):
def __init__(self, *args, **kwargs):
pass # whatever you want to state
@classmethod
def cast(cls, to_be_casted_obj):
casted_obj = cls()
casted_obj.__dict__ = to_be_casted_obj.__dict__
return casted_obj
# new methods you want to add
# ...