2009-09-21 1 views
4

멤버 함수에서 클래스의 속성을 정의하고 싶습니다. 다음은이 기능을 사용하는 방법을 보여주는 몇 가지 테스트 코드입니다. 그러나 나는 예상되는 행동을 얻지 못한다.__init__에서 속성을 정의하는 방법

class Basket(object): 

    def __init__(self): 
    # add all the properties 
    for p in self.PropNames(): 
     setattr(self, p, property(lambda : p)) 

    def PropNames(self): 
    # The names of all the properties 
    return ['Apple', 'Pear'] 

    # normal property 
    Air = property(lambda s : "Air") 

if __name__ == "__main__": 
    b = Basket() 
    print b.Air # outputs: "Air" 
    print b.Apple # outputs: <property object at 0x...> 
    print b.Pear # outputs: <property object at 0x...> 

어떻게 작동합니까?

답변

10

개체 (예 : self)가 아닌 클래스의 속성을 설정해야합니다 (예 : self.__class__). 예를 들면 다음과 같습니다 루프에 lamdas를 만들 때 그 가치가 무엇인지에 대한

class Basket(object): 

    def __init__(self): 
    # add all the properties 
    setattr(self.__class__, 'Apple', property(lambda s : 'Apple')) 
    setattr(self.__class__, 'Pear', property(lambda s : 'Pear')) 

    # normal property 
    Air = property(lambda s : "Air") 

if __name__ == "__main__": 
    b = Basket() 
    print b.Air # outputs: "Air" 
    print b.Apple # outputs: "Apple" 
    print b.Pear # outputs: "Pear" 

p의 사용량은, 당신이 기대하는 행동을 제공하지 않습니다. p의 값이 루프를 진행하는 동안 변경되기 때문에 루프에 설정된 두 속성은 모두 동일한 값, 즉 p의 마지막 값을 반환합니다.

3

이 당신이 원하는 것을 수행합니다 ^^

class Basket(object): 
    def __init__(self): 
    # add all the properties 

    def make_prop(name): 
     def getter(self): 
      return "I'm a " + name 
     return property(getter) 

    for p in self.PropNames(): 
     setattr(Basket, p, make_prop(p)) 

    def PropNames(self): 
    # The names of all the properties 
    return ['Apple', 'Pear', 'Bread'] 

    # normal property 
    Air = property(lambda s : "I'm Air") 

if __name__ == "__main__": 
    b = Basket() 
    print b.Air 
    print b.Apple 
    print b.Pear 

그것이 메타 클래스 것 할 수있는 또 다른 방법을 ...하지만 그들은 많은 사람들을 혼란.

나는 지루 해요 때문에 : __init__ 시간에

class WithProperties(type): 
    """ Converts `__props__` names to actual properties """ 
    def __new__(cls, name, bases, attrs): 
     props = set(attrs.get('__props__',())) 
     for base in bases: 
      props |= set(getattr(base, '__props__',())) 

     def make_prop(name): 
      def getter(self): 
       return "I'm a " + name 
      return property(getter) 

     for prop in props: 
      attrs[ prop ] = make_prop(prop) 

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

class Basket(object): 
    __metaclass__ = WithProperties 
    __props__ = ['Apple', 'Pear'] 

    Air = property(lambda s : "I'm Air") 

class OtherBasket(Basket): 
    __props__ = ['Fish', 'Bread'] 

if __name__ == "__main__": 
    b = Basket() 
    print b.Air 
    print b.Apple 
    print b.Pear 

    c = OtherBasket() 
    print c.Air 
    print c.Apple 
    print c.Pear 
    print c.Fish 
    print c.Bread 
+0

을 할 필요는 없습니다

  • PropNamesprop_names. 이것에 대한 메타 핸들은 너무 강력합니다. 왜냐하면 이것은 덜 강력한 수단을 사용하여 수행 할 수 있기 때문입니다. –

  • +0

    업데이트 해 주셔서 감사합니다. 사실 파이썬에서 메타 클래스만큼 깊게 들어간 적이 없었습니다. 어쩌면 이것이 그들에 대한 독서를 시작할 좋은 이유 일 것입니다. – pkit

    1

    왜 당신이 정의하는 속성? 혼란스럽고 영리해서 정말 좋은 이유가 있습니다. Stef가 지적한 루프 문제는 이것이 피해야하는 이유 중 하나 일뿐입니다.

    하위 클래스에있는 속성을 다시 정의해야하는 경우 하위 클래스 __init__에서 del self.<property name>을 수행하거나 하위 클래스에 새 속성을 정의 할 수 있습니다. 또한

    , 어떤 스타일 nitpicks :

    • 들여 쓰기 4 공간이 아니라 2
    • 인용 유형을 혼합하지 마십시오 불필요
    • 사용하는 대신 메소드 이름에 대한 낙타 케이스의 밑줄. PropNames -> 정말 방법 내가 올바른 방법으로 그것이 메타 클래스 것 할 것을 동의
    +0

    주된 이유는 내가 바구니에서 벗어나 PropName을 다시 정의 할 수 있기 때문입니다. 추신 원래 예제 코드는 실제로 4 칸을 들여 썼지 만, SO에 복사했을 때 들여 쓰기가 손실되어 2 칸을 다시 들여 썼다. – pkit

    +0

    @pkit : 서브 클래 싱에 대한 대답을 편집했습니다. –