이미 인스턴스화 된 객체에 속성을 추가 할 수있는 이유는 무엇입니까?
나는 파이썬을 공부하고 있는데, 파이썬의 전체 개념과 개념을 이해한다고 생각하지만, 오늘 완전히 이해하지 못한 코드 조각을 우연히 발견했습니다.
서클을 정의해야하지만 본문이없는 클래스가 있다고 가정 해 보겠습니다.
class Circle():
pass
속성을 정의하지 않았으므로 어떻게 할 수 있습니까?
my_circle = Circle()
my_circle.radius = 12
이상한 부분은 파이썬이 위의 문장을 받아 들인다는 것입니다. 왜 파이썬이 undefined name error
. 동적 타이핑 을 통해 원할 때마다 변수를 개체에 바인딩하지만이 를 수행 할 수 있도록 클래스에 속성 radius
이 없어야한다는 Circle
것을 이해합니다.
편집 : 귀하의 답변에 멋진 정보가 많이 있습니다! 모든 환상적인 답변에 감사드립니다! 하나만 답으로 표시하는 것이 유감입니다.
선도적 인 원칙은 선언과 같은 것이 없다는 것 입니다. 즉, "이 클래스에는 foo 메소드가 있습니다."또는 "이 클래스의 인스턴스에는 속성 막대가 있습니다."라고 선언하지 않고 거기에 저장할 객체 유형에 대한 설명을 작성하지도 않습니다. 메소드, 속성, 클래스 등을 정의하기 만하면 추가됩니다. JBernardo가 지적했듯이 모든 __init__
방법은 똑같은 일을합니다. 새 속성 생성을 이름이있는 메서드로 임의로 제한하는 것은 의미가 없습니다 __init__
. 그리고 __init__
실제로 그 이름이없는 함수 (예 : 데코레이터) 를 저장하는 것이 유용 할 때가 있습니다. 그런 제한은 그것을 깨뜨릴 것입니다.
자, 이것은 보편적으로 사실이 아닙니다. 내장 유형은이 기능을 최적화로 생략합니다. 를 통해 __slots__
사용자 정의 클래스에서도이를 방지 할 수 있습니다. 그러나 이것은 단지 공간 최적화 (모든 객체에 대한 사전이 필요 없음) 일 뿐이며 정확성이 아닙니다.
안전망을 원한다면 너무 나쁘다. 파이썬은 하나를 제공하지 않으며 합리적으로 추가 할 수 없으며, 가장 중요한 것은 언어를 포용하는 파이썬 프로그래머에 의해 피할 수 있다는 것입니다 (읽기 : 함께 일하고 싶은 거의 모든 사람들). 테스트와 규율은 여전히 정확성을 보장하는 데 큰 도움이됩니다. __init__
피할 수있는 경우 외부 속성을 구성하는 자유를 사용하지 말고 자동화 된 테스트를 수행하십시오. 나는 AttributeError
이와 같은 속임수로 인해 또는 논리적 오류가 거의 없으며 발생하는 것 중 거의 모두가 테스트에 의해 포착됩니다.
여기 논의에서 오해를 명확히하기 위해서입니다. 이 코드 :
class Foo(object):
def __init__(self, bar):
self.bar = bar
foo = Foo(5)
그리고이 코드 :
class Foo(object):
pass
foo = Foo()
foo.bar = 5
입니다 정확히 상응 . 정말 차이가 없습니다. 똑같은 일을합니다. 이 차이점은 첫 번째 경우에 캡슐화되어 있고 bar 속성이 Foo 유형 객체의 일반적인 부분이라는 것이 분명하다는 것입니다. 두 번째 경우에는 이것이 확실하지 않습니다.
첫 번째 경우에는 bar 속성이없는 Foo 객체를 만들 수 없습니다 (글쎄요, 가능하지만 쉽지는 않습니다). 두 번째 경우에는 설정하지 않는 한 Foo 객체에 bar 속성이 없습니다.
따라서 코드는 프로그래밍 방식으로 동일하지만 다른 경우에 사용됩니다.
Python을 사용하면 거의 모든 인스턴스 (또는 클래스)에 모든 이름의 속성을 저장할 수 있습니다. 내장 유형과 같이 C로 클래스를 작성하거나 __slots__
특정 이름 만 허용 하는 것을 사용 하여 이를 차단할 수 있습니다.
작동하는 이유는 대부분의 인스턴스가 사전에 속성을 저장하기 때문입니다. 예, {}
. 사전은라는 인스턴스 속성에 저장됩니다 __dict__
. 사실, 어떤 사람들은 "클래스는 사전의 문법적 설탕 일뿐"이라고 말합니다. 즉, 사전이있는 클래스로 할 수있는 모든 것을 할 수 있습니다. 수업이 더 쉬워집니다.
컴파일 타임에 모든 속성을 정의해야하는 정적 언어에 익숙합니다. Python에서 클래스 정의는 컴파일되지 않고 실행됩니다 . 클래스는 다른 것과 마찬가지로 객체입니다. 속성을 추가하는 것은 사전에 항목을 추가하는 것만 큼 쉽습니다. 이것이 파이썬이 동적 언어로 간주되는 이유 입니다.
아니요, 파이썬은 이와 같이 유연하며 사용자 정의 클래스에 저장할 수있는 속성을 적용하지 않습니다.
그러나 트릭이 있지만 클래스 정의에 __slots__
속성 을 사용 하면 __slots__
시퀀스에 정의되지 않은 추가 속성을 만들 수 없습니다 .
>>> class Foo(object):
... __slots__ = ()
...
>>> f = Foo()
>>> f.bar = 'spam'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'bar'
>>> class Foo(object):
... __slots__ = ('bar',)
...
>>> f = Foo()
>>> f.bar
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: bar
>>> f.bar = 'spam'
의 radius
데이터 멤버를 만듭니다 my_circle
.
요청했다면 my_circle.radius
예외가 발생했을 것입니다.
>>> print my_circle.radius # AttributeError
Interestingly, this does not change the class; just that one instance. So:
>>> my_circle = Circle()
>>> my_circle.radius = 5
>>> my_other_circle = Circle()
>>> print my_other_circle.radius # AttributeError
There are two types of attributes in Python - Class Data Attributes
and Instance Data Attributes
.
Python gives you flexibility of creating Data Attributes
on the fly.
Since an instance data attribute is related to an instance, you can also do that in __init__
method or you can do it after you have created your instance..
class Demo(object):
classAttr = 30
def __init__(self):
self.inInit = 10
demo = Demo()
demo.outInit = 20
Demo.new_class_attr = 45; # You can also create class attribute here.
print demo.classAttr # Can access it
del demo.classAttr # Cannot do this.. Should delete only through class
demo.classAttr = 67 # creates an instance attribute for this instance.
del demo.classAttr # Now OK.
print Demo.classAttr
So, you see that we have created two instance attributes, one inside __init__
and one outside, after instance is created..
But a difference is that, the instance attribute created inside __init__
will be set for all the instances, while if created outside, you can have different instance attributes for different isntances..
This is unlike Java, where each Instance of a Class have same set of Instance Variables..
- NOTE: - While you can access a class attribute through an instance, you cannot delete it.. Also, if you try to modify a class attribute through an instance, you actually create an instance attribute which shadows the class attribute..
As delnan said, you can obtain this behavior with the __slots__
attribute. But the fact that it is a way to save memory space and access type does not discard the fact that it is (also) a/the mean to disable dynamic attributes.
Disabling dynamic attributes is a reasonable thing to do, if only to prevent subtle bugs due to spelling mistakes. "Testing and discipline" is fine but relying on automated validation is certainly not wrong either – and not necessarily unpythonic either.
Also, since the attrs
library reached version 16 in 2016 (obviously way after the original question and answers), creating a closed class with slots has never been easier.
>>> import attr
...
... @attr.s(slots=True)
... class Circle:
... radius = attr.ib()
...
... f = Circle(radius=2)
... f.color = 'red'
AttributeError: 'Circle' object has no attribute 'color'
ReferenceURL : https://stackoverflow.com/questions/12569018/why-is-adding-attributes-to-an-already-instantiated-object-allowed
'IT Share you' 카테고리의 다른 글
C ++에서 조합 생성 (0) | 2021.01.10 |
---|---|
US-ASCII에서 UTF-8 (iconv)로 강제 인코딩 (0) | 2021.01.10 |
datatable jquery-테이블 헤더 너비가 본문 너비와 정렬되지 않음 (0) | 2021.01.10 |
Bash 자동화를 위해 명령 줄에서 Postgres 용 사용자를 만드는 방법 (0) | 2021.01.10 |
CertPathValidatorException : 인증서 경로에 대한 신뢰 앵커를 찾을 수 없음-Retrofit Android (0) | 2021.01.10 |