2011-05-03 3 views
2

약간의 유효성 검사 API를 작성하고 클래스 '__init__ 메서드의 각 필드에 대한 제약 조건을 초기화하고 있습니다. 그러나이 설정은 기본적으로 클래스에 대해 한 번만 수행 할 수 있습니다.Python에서 상속되었지만 공유 (정적) 클래스 멤버

class Demo(Validatable): 

    def __init__(self): 
     Validatable.__init__(self) 
     self.count = 11 

     # could be done at class level 
     self.constrain_field("count", Max(9), Even()) 

그러나 문제는, 각 필드의 제약이 어딘가에 저장해야하고 그 상속 클래스 Validatable의 일부인 할 수있는 데이터 구조 것이다. 따라서 파생 된 모든 클래스가 동일한 데이터 구조를 공유하게됩니다. 제약 조건이 클래스 수준에서 설정되면 어떤 일이 발생하지 않아야합니다!

class Demo(Validatable): 

    # doesn't work! 
    Validatable.constrain_field("count", Max(9), Even()) 

    def __init__(self): 
     self.count = 11 

데이터 구조를 상속 제약에 대한 데이터 구조를 공유하지 않고 파생 클래스에 클래스 수준에서 초기화 할 가능성이 있습니까?

+0

'constraint_field()'는 클래스 메소드 또는 정적 메소드입니까? 어떻게 정의됩니까? – brandizzi

+0

지금은 일반적인 (인스턴스) 메소드이지만 변경하고 싶습니다. 본질적으로이 방법은 필드 이름을 키로하고 제약 조건 목록을 값으로 사용하여 사전에 제약 조건을 추가합니다. – deamon

답변

2

이 질문에는 두 부분이 있습니다.

  1. 방법 대신 상속 Validatable 클래스의, 한 세트의 서브 클래스 레벨에서 Validatable 데이터 구조의 값을한다;
  2. constrain_field 메서드를 정의하면 인스턴스를 만들 때마다 대신 클래스 초기화시 한 번 호출 할 수 있습니다. (1) Validatable 클래스의 초기화가 __class__ 속성을 사용하여 클래스 인스턴스를 액세스 할 수에 대하여

.

class Validatable(object): 
    def __init__(self): 
     self.__class__.fieldName = "value for " + self.__class__.__name__ 

class Demo(Validatable): 
    def __init__(self): 
     super(Demo, self).__init__() 

class Demo2(Validatable): 
    def __init__(self): 
     super(Demo2, self).__init__() 

d = Demo() 
d2 = Demo2() 
print "Demo.fieldName = " + Demo.fieldName 
print "Demo2.fieldName = " + Demo2.fieldName 

이 번호 인쇄 : 예를 들어

Demo.fieldName = value for Demo 
Demo2.fieldName = value for Demo2 

constrain_field 방법은 필요한 데이터 구조를 설정하기가 불려 인스턴스의 __class__ 속성을 사용하여 정의 될 수있다.

불행히도 이것은 모두 데이터 구조를 설정하기 전에 클래스의 인스턴스를 생성해야하며 인스턴스가 생성 될 때마다 constrain_field 메서드가 호출되어야한다는 것을 의미합니다. 분명히 질문의 파트 (2) 인 클래스 초기화시이를 수행하는 것이 바람직합니다.

(2) 부분을 해결하려면 파이썬 decorators을 사용하는 것이 좋습니다.

def Max(maxValue): 
    def checkMax(value): 
     return value <= maxValue 
    checkMax.__doc__ = "Value must be less than or equal to " + str(maxValue) 
    return checkMax 

def Even(): 
    def checkEven(value): 
     "Value must be even" 
     return value%2 == 0 
    return checkEven 

def constrain_field(*constraints): 
    def constraint_decorator(setter): 
     def checkConstraints(self, value): 
      ok = True 
      for c in constraints: 
       if not c(value): 
        ok = False 
        print "Constraint breached: " + c.__doc__ 
      if ok: 
       setter(self, value) 
     return checkConstraints 
    return constraint_decorator 

class Demo(object): 
    def __init__(self): 
     self._count = 2 

    @property 
    def count(self): 
     return self._count 

    @count.setter 
    @constrain_field(Max(9), Even()) 
    def count(self, value): 
     self._count = value 

d = Demo() 
print "Setting to 8" 
d.count = 8 
print "Setting to 9" 
d.count = 9 
print "Setting to 10" 
d.count = 10 
print "Count is now " + str(d.count) 

그것은 인쇄 : constrain_field라는 사용자 지정 장식 기능 (실내 장식으로 사용) 파이썬 property 기능을 결합하여 다음과 같은 코드를 고려,

Setting to 8 
Setting to 9 
Constraint breached: Value must be even 
Setting to 10 
Constraint breached: Value must be less than or equal to 9 
Count is now 8 

을 이런 식으로 장식을 사용하는 모든 초기화는 클래스 정의 중에 한 번 수행됩니다.