답변:
이것을 시도하십시오 : 파이썬 속성
샘플 코드는 다음과 같습니다.
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
print("getter of x called")
return self._x
@x.setter
def x(self, value):
print("setter of x called")
self._x = value
@x.deleter
def x(self):
print("deleter of x called")
del self._x
c = C()
c.x = 'foo' # setter called
foo = c.x # getter called
del c.x # deleter called
._x
. 속성이 아니라 일반 속성 인 참조는 property
줄 바꿈을 무시합니다 . 를 통해서만 참조 .x
하십시오 property
.
게터와 세터를 사용하는 파이썬적인 방법은 무엇입니까?
은 "파이썬"방법은 없다 "게터"와 "세터"를 사용하지만, 문제는 보여 같은 일반 속성을 사용하고, del
삭제하는 (그러나 이름은 무죄 ... 내장 명령을 보호하기 위해 변경) :
value = 'something'
obj.attribute = value
value = obj.attribute
del obj.attribute
나중에 설정을 수정하고 가져 property
오려면 데코레이터 를 사용하여 사용자 코드를 변경하지 않고도 변경할 수 있습니다 .
class Obj:
"""property demo"""
#
@property # first decorate the getter method
def attribute(self): # This getter method name is *the* name
return self._attribute
#
@attribute.setter # the property decorates with `.setter` now
def attribute(self, value): # name, e.g. "attribute", is the same
self._attribute = value # the "value" name isn't special
#
@attribute.deleter # decorate with `.deleter`
def attribute(self): # again, the method name is the same
del self._attribute
(각 데코레이터 사용법은 이전 속성 객체를 복사하고 업데이트하므로 각 세트, 가져 오기 및 삭제 기능 / 방법에 대해 동일한 이름을 사용해야합니다.
위의 내용을 정의한 후 코드의 원래 설정, 가져 오기 및 삭제는 동일합니다.
obj = Obj()
obj.attribute = value
the_value = obj.attribute
del obj.attribute
이것을 피해야합니다 :
def set_property(property,value): def get_property(property):
첫째, 속성이 (보통 self
) 으로 설정된 인스턴스에 대한 인수를 제공하지 않기 때문에 위와 같이 작동하지 않습니다 .
class Obj:
def set_property(self, property, value): # don't do this
...
def get_property(self, property): # don't do this either
...
둘째, 이것은 두 가지 특별한 방법 __setattr__
과 목적을 복제합니다 __getattr__
.
셋째, 우리는 또한이 setattr
와 getattr
내장 기능.
setattr(object, 'property_name', value)
getattr(object, 'property_name', default_value) # default is optional
@property
장식은 getter 및 setter를 만드는 것입니다.
예를 들어 설정 동작을 수정하여 설정중인 값을 제한 할 수 있습니다.
class Protective(object):
@property
def protected_value(self):
return self._protected_value
@protected_value.setter
def protected_value(self, value):
if acceptable(value): # e.g. type or range check
self._protected_value = value
일반적으로 우리는 사용을 피하고 property
직접 속성을 사용하려고 합니다.
이것은 파이썬 사용자가 기대하는 것입니다. 가장 놀랍게도 규칙에 따라 반대되는 이유가 없다면 사용자에게 기대하는 것을 제공해야합니다.
예를 들어, 객체의 protected 속성이 0에서 100 사이의 정수 여야하고 사용자에게 올바른 사용법을 알려주는 적절한 메시지와 함께 삭제를 방지해야한다고 가정 해보십시오.
class Protective(object):
"""protected property demo"""
#
def __init__(self, start_protected_value=0):
self.protected_value = start_protected_value
#
@property
def protected_value(self):
return self._protected_value
#
@protected_value.setter
def protected_value(self, value):
if value != int(value):
raise TypeError("protected_value must be an integer")
if 0 <= value <= 100:
self._protected_value = int(value)
else:
raise ValueError("protected_value must be " +
"between 0 and 100 inclusive")
#
@protected_value.deleter
def protected_value(self):
raise AttributeError("do not delete, protected_value can be set to 0")
(주는 __init__
를 의미 self.protected_value
하지만, 등록 방법을 참조하십시오 self._protected_value
.이 때문에 즉__init__
사용을 보장 공개 API를 통해 속성은 "보호"이다.)
그리고 사용법 :
>>> p1 = Protective(3)
>>> p1.protected_value
3
>>> p1 = Protective(5.0)
>>> p1.protected_value
5
>>> p2 = Protective(-5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __init__
File "<stdin>", line 15, in protected_value
ValueError: protectected_value must be between 0 and 100 inclusive
>>> p1.protected_value = 7.3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 17, in protected_value
TypeError: protected_value must be an integer
>>> p1.protected_value = 101
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 15, in protected_value
ValueError: protectected_value must be between 0 and 100 inclusive
>>> del p1.protected_value
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 18, in protected_value
AttributeError: do not delete, protected_value can be set to 0
예 그들은 할 . .setter
그리고 .deleter
원래 재산의 복사본을 만든다. 이를 통해 서브 클래스는 부모의 동작을 변경하지 않고 동작을 올바르게 수정할 수 있습니다.
class Obj:
"""property demo"""
#
@property
def get_only(self):
return self._attribute
#
@get_only.setter
def get_or_set(self, value):
self._attribute = value
#
@get_or_set.deleter
def get_set_or_delete(self):
del self._attribute
이제 이것이 작동하려면 해당 이름을 사용해야합니다.
obj = Obj()
# obj.get_only = 'value' # would error
obj.get_or_set = 'value'
obj.get_set_or_delete = 'new value'
the_value = obj.get_only
del obj.get_set_or_delete
# del obj.get_or_set # would error
이것이 어디에 유용한 지 잘 모르겠지만 유스 케이스는 get, set 및 / 또는 delete-only 속성을 원하는 경우입니다. 이름이 같은 의미 적으로 동일한 속성을 고수하는 것이 가장 좋습니다.
간단한 속성으로 시작하십시오.
나중에 설정, 가져 오기 및 삭제와 관련된 기능이 필요한 경우 속성 데코레이터를 사용하여 추가 할 수 있습니다.
피 기능은 이름 set_...
과 get_...
의 어떤 속성에 대한 것을 -.
__init__
메소드는 참조 self.protected_value
하지만 getter 및 setter는 참조합니다 self._protected_value
. 어떻게 작동하는지 설명해 주시겠습니까? 코드를 테스트했으며 그대로 작동하므로 오타가 아닙니다.
__init__
이지 않습니까?
self.protected_value = start_protected_value
실제로 setter 함수를 호출 한다는 것을 몰랐습니다 . 나는 그것이 임무라고 생각했다.
사용 @property
하고 @attribute.setter
당신이 "파이썬"방법을 사용하는 것이 아니라 도움뿐만 아니라 속성의 유효성을 확인하는 두 개체를 만드는 동안이를 변경할 때.
class Person(object):
def __init__(self, p_name=None):
self.name = p_name
@property
def name(self):
return self._name
@name.setter
def name(self, new_name):
if type(new_name) == str: #type checking for name property
self._name = new_name
else:
raise Exception("Invalid value for name")
이를 통해 실제로 _name
클라이언트 개발자로부터 속성을 '숨기기' 하고 이름 속성 유형을 확인합니다. 시작하는 동안에도이 접근 방식을 따르면 setter가 호출됩니다. 그래서:
p = Person(12)
다음으로 이어질 것입니다 :
Exception: Invalid value for name
그러나:
>>>p = person('Mike')
>>>print(p.name)
Mike
>>>p.name = 'George'
>>>print(p.name)
George
>>>p.name = 2.3 # Causes an exception
@property
데코레이터를 확인하십시오 .
접근 자 / 뮤 테이터 (예 : @attr.setter
및 @property
)를 사용할 수 있지만 가장 중요한 것은 일관된 것입니다 !
@property
단순히 속성에 액세스하는 데 사용 하는 경우 ( 예 :
class myClass:
def __init__(a):
self._a = a
@property
def a(self):
return self._a
이것을 사용하여 every * 속성 에 액세스하십시오 ! 접근자를 사용 하지 않고 일부 속성을 사용 @property
하고 다른 속성을 공개 (예 : 밑줄없는 이름)로 두는 것은 좋지 않습니다. 예를 들어
class myClass:
def __init__(a, b):
self.a = a
self.b = b
@property
def a(self):
return self.a
참고 self.b
가 공공 비록 여기에서 명시 적으로 접근이 없습니다.
세터 (또는 뮤 테이터 ) 와 마찬가지로 자유롭게 사용 @attribute.setter
하지만 일관성을 유지하십시오! 예를 들어
class myClass:
def __init__(a, b):
self.a = a
self.b = b
@a.setter
def a(self, value):
return self.a = value
당신의 의도를 추측하기가 어렵습니다. 한 손으로 당신은 두 말을하는지 a
그리고 b
내가 이론적 접근 / 개의 mutate (GET / SET) 모두 허용해야하므로 (이름에 선두에 밑줄) 공개됩니다. 하지만 당신은 단지에 대한 명시 뮤 테이터 지정 a
어쩌면 내가 설정할 수 없습니다 것을 나에게 알려줍니다 b
. 명시 적 뮤 테이터를 제공했기 때문에 명시 적 접근 자 ( @property
) 가 부족 하여 해당 변수 중 하나에 액세스 할 수 없어야하는지 또는 단순히 사용하는 것에 대해 절박한 것인지 확실 하지 않습니다 @property
.
* 일부 변수를 명시 적으로 액세스 가능하거나 변경 가능하게 만들거나 두 가지 모두 허용하지 않으려는 경우 또는 속성에 액세스하거나 변경할 때 추가 논리를 수행하려는 경우는 예외입니다 . 이것은 내가 개인적으로 사용 @property
하고있는 경우입니다 @attribute.setter
(그렇지 않으면 공개 속성에 대한 명시 적 후임 / 뮤 테이터가 없음).
마지막으로 PEP8 및 Google 스타일 가이드 제안 :
상속을위한 디자인 PEP8 은 다음과 같이 말합니다.
단순한 공개 데이터 속성의 경우 복잡한 접근 자 / 돌연변이 방법없이 속성 이름 만 노출 하는 것이 가장 좋습니다 . 간단한 데이터 속성이 기능적 행동을 키워야한다는 사실을 알게되면 Python은 향후 개선을위한 쉬운 길을 제공한다는 점을 명심하십시오. 이 경우 속성을 사용하여 간단한 데이터 속성 액세스 구문 뒤에 기능 구현을 숨기십시오.
반면, Google 스타일 가이드 Python 언어 규칙 / 속성에 따르면 권장 사항은 다음과 같습니다.
새 코드의 속성을 사용하여 일반적으로 단순하고 가벼운 접근 자 또는 세터 메서드를 사용했던 데이터에 액세스하거나 데이터를 설정하십시오.
@property
데코레이터로 속성을 만들어야합니다 .
이 접근법의 장점 :
간단한 속성 액세스를위한 명시적인 get 및 set 메소드 호출을 제거함으로써 가독성이 향상되었습니다. 계산이 지연 될 수 있습니다. 클래스의 인터페이스를 유지하는 파이썬 방식을 고려했습니다. 성능면에서 직접 변수 액세스가 합리적인 경우 속성을 허용하는 것은 사소한 접근 자 방법이 필요하지 않습니다. 또한 나중에 인터페이스를 손상시키지 않고 접근 자 메서드를 추가 할 수 있습니다.
그리고 단점 :
object
파이썬 2에서 상속 받아야 합니다. 연산자 오버로딩과 같은 부작용을 숨길 수 있습니다. 서브 클래스를 혼동 할 수 있습니다.
@property
경우 나머지도 사용 @property
하는 것은 좋지 않은 결정처럼 보입니다.
@property
(예 : 속성을 반환하기 전에 일부 특수 로직 실행). 그렇지 않으면 왜 하나의 속성을 @propery
다른 속성으로 장식 하지 않겠습니까?
@property
, 시작하기 위해 사용해서는 안됩니다 . getter가 return this._x
있고 setter가 this._x = new_x
인 경우 @property
전혀 사용 하는 것이 어리 석습니다.
@property
일관성이있다"는 글을 읽은 것 같습니다 .
당신은 마법의 방법을 사용할 수 있습니다 __getattribute__
및 __setattr__
.
class MyClass:
def __init__(self, attrvalue):
self.myattr = attrvalue
def __getattribute__(self, attr):
if attr == "myattr":
#Getter for myattr
def __setattr__(self, attr):
if attr == "myattr":
#Setter for myattr
__getattr__
그리고 __getattribute__
동일하지 않다는 것을 명심하십시오 . __getattr__
속성을 찾을 수 없을 때만 호출됩니다.