IT Share you

이미 인스턴스화 된 객체에 속성을 추가 할 수있는 이유는 무엇입니까?

shareyou 2021. 1. 10. 19:21
반응형

이미 인스턴스화 된 객체에 속성을 추가 할 수있는 이유는 무엇입니까?


나는 파이썬을 공부하고 있는데, 파이썬의 전체 개념과 개념을 이해한다고 생각하지만, 오늘 완전히 이해하지 못한 코드 조각을 우연히 발견했습니다.

서클을 정의해야하지만 본문이없는 클래스가 있다고 가정 해 보겠습니다.

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

반응형