2

私は次のことを達成しようとしています:

class Data(object):
    def __init__(self, data):
        self.data = data
        self.valid = False
        #Analyze and validate data
        self.preprocess_data()
        self.validate_data()

    def preprocess_data():
        pass

    def validate_data():
        #process data

class MyData(Data):
    def __init__():
        super(MyData,self).__init__(data)

    def preprocess_data(self):
        #preprocess it

サブクラスがオーバーライドされた preprocess_dataメソッドを実行するときに、次の操作を自動的に実行したい: self.data = self.data.copy()

どうすればこれを行うことができますか(もしあれば)?装飾も考えpreprocessましたが、基本クラスで装飾されているオーバーライドされたメソッドが「装飾」を継承するとは思いません

4

4 に答える 4

2
class Data(object):
    def __init__(self, data):
        self.data = data
        self.valid = False
        #Analyze and validate data
        self._preprocess_data()
        self.validate_data()
    def _preprocess_data(self):
        if self.preprocess_data.im_func != Data.preprocess_data.im_func:
            self.data = self.data.copy()
        return self.preprocess_data()

これは、背後にある関数self.preprocess_dataData.preprocess_data;であるかどうかをテストします。そうでない場合は、データをコピーします。もちろん、これには_preprocess_dataクラスを呼び出す必要があるため、追加のコードが実際に実行されます。

于 2012-05-25T06:52:40.210 に答える
1

これは、デコレータと単純なメタクラスで簡単に解決できます。これは少しハックですが、まさにあなたが求めたとおりに動作します。

import functools

class DataMeta(type):
    def __new__(cls, name, bases, dictn):
        fn = dictn.get('preprocess_data')
        if fn:
            if getattr(fn, '_original', False) is False:
                @functools.wraps(fn)
                def wrapper(self, *args, **kwargs):
                    self.data = self.data.copy()
                    return fn(self, *args, **kwargs)
                dictn['preprocess_data'] = wrapper
        return type.__new__(cls, name, bases, dictn)

def base_method(fn):
    fn._original = True
    return fn

class Data(object):
    __metaclass__ = DataMeta

    def __init__(self, data):
        self.data = data
        self.valid = False
        #Analyze and validate data
        self.preprocess_data()
        self.validate_data()

    @base_method
    def preprocess_data(self):
        print "Original preprocess_data called"

    def validate_data(self):
        pass

class MyData(Data):
    def __init__(self, data):
        super(MyData, self).__init__(data)

    def preprocess_data(self):
        print "Overridden preprocess_data called"

class MyData1(Data):
    def __init__(self, data):
        super(MyData1, self).__init__(data)

class Dummy(object):
    def copy(self):
        print 'Copying data'

md = MyData(Dummy()) # Prints 'Copying data'
md1 = MyData1(Dummy()) # Doesn't print it, since MyData1 doesn't override preprocess_data
于 2012-05-25T07:48:41.983 に答える
1

@ThiefMaster のやり方に投票します。生活を複雑にしたい場合は、デコレータでメタクラスを使用できます。

from functools import wraps

class PreprocessMetaclass(type): 
    def __new__(cls, name, bases, dct):

        try:
            if Data in bases and "preprocess_data" in dct:
                f = dct["preprocess_data"]
                @wraps(f)
                def preprocess_data(self, *args, **kwargs):
                    self.data = self.data.copy()
                    return f(self, *args, **kwargs)

                attrs = dct.copy()
                attrs["preprocess_data"] = preprocess_data
        except NameError as e:
            # This is if Data itself is being created, just leave it as it is.
            # Raises an NameError, because Data does not exist yet in "if Data in bases"
            attrs = dct

        return super(PreprocessMetaclass, cls).__new__(cls, name, bases, attrs)


class Data(object):
    # This here works if the subclasses don't specify
    # their own metaclass that isn't a subclass of the above.
    __metaclass__ = PreprocessMetaclass

    def __init__(self, data):
        self.data = data
        self.valid = False
        #Analyze and validate data
        self.preprocess_data()
        self.validate_data()

    def preprocess_data(self):
        self.data["newkey"] = 3

    def validate_data(self):
        print "This is the result: self.data =", self.data

class MyData(Data):
    def __init__(self, data):
        super(MyData,self).__init__(data)

    def preprocess_data(self):
        """The docs of the subclass"""
        self.data["newkey"] = 4

if __name__ == "__main__":
    dct1, dct2 = {"data": 1}, {"mydata": 2}

    print "Create Data"
    d = Data(dct1)

    print "Create MyData"
    md = MyData(dct2)

    print "The original dict of Data (changed):", dct1
    print "The original dict of MyData (unchanged):", dct2

    # If you do that, you will see that the docstring is still there,
    # but the arguments are no longer the same.
    # If that is needed (you don't have arguments, but the subclass might have)
    # then just enter the same arguments as the subclass's function
    # help(MyData)

PSメタクラスを使用する必要があったのはこれが初めてですが、ここでは完璧なシナリオです。クラスが作成される前 ( の前__init__) に、関数定義をオーバーライドする必要があります。今は必要ないかもしれませんが、より一般的には、それを使わざるを得ないかもしれません。

さらに簡単な例:

if not (self.preprocess_data is Data.preprocess_data):
    self.data = self.data.copy()
self.preprocess_data()
于 2012-05-25T07:51:46.217 に答える
0

簡単にどうですか:

class Data(object):

    # Part of user API
    def preprocess_data():
        self.data = self.data.copy()
        self.preprocess_data_impl()

    # Part of internal API    
    def preprocess_data_impl():
        pass

class MyData(Data):

    def preprocess_data_impl():
        # Do stuff

これはデコレータを使用するほど魅力的ではないことはわかっていますが、実際に何が起こるかを非常に簡単に追跡できます。

于 2012-05-25T08:02:14.997 に答える