簡體   English   中英

我如何在python中向下轉換

[英]How do I downcast in python

我有兩個類 - 一個繼承自另一個。 我想知道如何轉換(或創建一個新的變量)子類。 我已經搜索了一下,大部分都是“向下傾斜”,這似乎是不受歡迎的,並且有一些稍微狡猾的解決方法,比如設置實例。 上課 - 雖然這似乎不是一個好方法。

例如。 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

你實際上並沒有在Python中“強制轉換”對象。 相反,你通常會轉換它們 - 拿走舊物體,創建一個新物體,扔掉舊物體。 為了實現這一點,新對象的類必須設計為在其__init__方法中獲取舊對象的實例並執行適當的操作(有時,如果類在創建它時可以接受多種對象,則它為此目的將有替代構造函數)。

您確實可以通過將其__class__屬性指向其他類來更改實例的類,但該類可能無法與實例一起正常工作。 此外,這種做法是恕我直言“氣味”,表明你應該采取不同的方法。

在實踐中,您幾乎不需要擔心Python中的類型。 (有明顯的例外:例如,嘗試添加兩個對象。即使在這種情況下,檢查也盡可能廣泛;這里,Python會檢查數字類型,或者可以轉換為數字的類型,而不是一個特定的類型。)因此,對象的實際類是很重要的,只要它具有任何代碼使用它所需的屬性和方法。

這不是一個向下傾斜的問題(恕我直言)。 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)

請參閱以下示例。 另外, 一定要遵守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
    # ...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM