2012-05-25 3 views
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 

는 서브 클래스가 오버라이드 (override) preprocess_data 방법을 실행하면, 내가 원하는 다음 작업을 자동으로 수행하십시오. self.data = self.data.copy()

어떻게 수행 할 수 있습니까? 나는 preprocess를 장식 생각하지만 난 self.preprocess_data 뒤에 함수가 Data.preprocess_data 경우 기본 클래스로 장식되어 있습니다 오버라이드 (override) 메소드는 "장식"

답변

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() 

이 테스트를 상속 생각하지 않는다; 그렇지 않으면 데이터를 복사합니다. 물론 이것은 추가 코드가 실제로 실행되도록 클래스에서 _preprocess_data으로 전화해야합니다.

+0

간결하고 작업이 완료됩니다. @ ThiefMaster. 감사합니다. – Bastiano9

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 
+0

Jeethu, 해결책 주셔서 감사합니다. 감사합니다. – Bastiano9

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 그것은 내가 메타 클래스를 사용하는 데 필요한 처음이지만, 여기 완벽한 시나리오는 다음과 같습니다 당신이 당신의 인생을 복잡하게하려면 decoratorsmetaclasses를 사용할 수 있습니다. 클래스가 생성되기 전에 함수 정의를 재정의해야합니다 (__init__ 전). 자, 당신은 그것을 필요로하지 않을 수도 있지만, 더 일반적으로, 당신은 그것을 사용하도록 강요받을 수도 있습니다.

이보다 더 간단한 예 :

if not (self.preprocess_data is Data.preprocess_data): 
    self.data = self.data.copy() 
self.preprocess_data() 
+0

jadkik94, metaclass + decorator 접근에 감사드립니다. 지금 당장은 단순함을 선택하고 @ ThiefMaster의 솔루션을 채택 할 것입니다. 그래도 다른 대안을 알고있는 것이 좋습니다. 감사!!! 또한 나는 당신의 마지막 제안을 좋아합니다. – Bastiano9

+0

언제든지 사용할 수 있기를 바랍니다. 개인적으로 유용한 메타 데이터를 처음 발견했습니다. 훨씬 더 복잡해지면 사용하는 것이 좋습니다. – jadkik94

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 

나는이 데코레이터를 사용하는 것만 큼 화려하지 않지만 아주 쉽게 실제로 발생 팔로우 할 수 있습니다 알고 .

+0

안녕하세요 @ aix, 기본 클래스 Data에서 '__init__'을 보면, 유효성 검사 프로세스에 대한 템플릿을 구현하고 있습니다 (사전 처리, 유효성 검사). 모든 하위 클래스에서이 코드를 호출합니다. 서브 클래스가'preprocess_data'를 구현하면'self.data.copy()'를 원합니다. 그렇지 않으면 나는 복사하지 않기 **합니다. – Bastiano9

관련 문제