11

私には2つのクラスがあります。1つはもう1つを継承します。サブクラスにキャストする(またはの新しい変数を作成する)方法を知りたいです。私は少し検索しましたが、ほとんどの場合、このような「ダウンキャスト」は眉をひそめているようです。インスタンスの設定など、少し危険な回避策がいくつかあります。クラス-これは良い方法ではないようですが。

例えば。 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 = ????????????

編集

貢献してくれてありがとう....これまでの答えは、あるクラスタイプから別のクラスタイプへのコンバーターのハードコーディングに時間を費やしていることを示唆しているようです。私はこれを行うためのより自動化された方法を考え出しました-基本的にクラスの属性をループし、それらを互いに転送します。これは人々にどのように匂いを嗅ぎますか-それは合理的なことですか-それとも先に問題を引き起こしますか?

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
4

3 に答える 3

10

Pythonで実際にオブジェクトを「キャスト」することはありません。代わりに、通常はそれらを変換します。古いオブジェクトを取得し、新しいオブジェクトを作成し、古いオブジェクトを破棄します。これが機能するためには、新しいオブジェクトのクラスが、そのメソッドで古いオブジェクトのインスタンスを取得__init__し、適切なことを行うように設計されている必要があります(クラスが作成時に複数の種類のオブジェクトを受け入れることができる場合は、その目的のための代替コンストラクターがあります)。

インスタンスの属性を別のクラスにポイントすることでインスタンスのクラスを変更することはできますが、__class__そのクラスはインスタンスで正しく機能しない可能性があります。さらに、この習慣は私見の「匂い」であり、おそらく別のアプローチを取るべきであることを示しています。

実際には、Pythonの型について心配する必要はほとんどありません。(明らかな例外を除いて:たとえば、2つのオブジェクトを追加しようとします。そのような場合でも、チェックは可能な限り広範囲です。ここでは、Pythonは数値タイプ、または数値ではなく数値に変換できるタイプをチェックします。特定のタイプ。)したがって、オブジェクトが使用しているコードが必要とする属性とメソッドを持っている限り、オブジェクトの実際のクラスが何であるかはほとんど問題になりません。

于 2013-03-03T16:19:00.153 に答える
2

次の例を参照してください。また、必ずLSP(Liskov Substitution Principle)に従ってください。

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
    # ...
于 2018-12-10T02:39:28.070 に答える
1

これはダウンキャストの問題ではありません(IMHO)。peekfind()はPeakオブジェクトを作成します(Psd_Peakオブジェクトではないため、ダウンキャストできません)。後で、そこからPsd_Peakオブジェクトを作成します。C ++のようなものでは、デフォルトのコピーコンストラクターに依存する可能性がありますが、Psd_Peakクラスはコンストラクターでより多くのパラメーターを必要とするため、C++でも機能しません。いずれにせよ、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)
于 2013-03-03T19:58:16.067 に答える