클래스와 인스턴스 속성의 차이점은 무엇입니까?
-
03-07-2019 - |
문제
다음 사이에 의미있는 차이가 있습니까?
class A(object):
foo = 5 # some default value
vs.
class B(object):
def __init__(self, foo=5):
self.foo = foo
많은 인스턴스를 만들고 있다면 두 스타일의 성능 또는 공간 요구 사항에 차이가 있습니까? 코드를 읽을 때 두 스타일의 의미가 크게 다르다고 생각하십니까?
해결책
성능 고려 사항 외에도 중요한 것이 있습니다 시맨틱 차이점. 클래스 속성 케이스에는 하나의 객체 만 참조됩니다. 인스턴스 attribute-set-instantiation에는 여러 개체가 참조 할 수 있습니다. 예를 들어
>>> class A: foo = []
>>> a, b = A(), A()
>>> a.foo.append(5)
>>> b.foo
[5]
>>> class A:
... def __init__(self): self.foo = []
>>> a, b = A(), A()
>>> a.foo.append(5)
>>> b.foo
[]
다른 팁
차이점은 클래스의 속성이 모든 인스턴스에서 공유된다는 것입니다. 인스턴스의 속성은 해당 인스턴스에 고유합니다.
C ++에서 오면 클래스의 속성은 정적 멤버 변수와 비슷합니다.
여기에 아주 좋은 것이 있습니다 게시하다, 아래와 같이 요약하십시오.
class Bar(object):
## No need for dot syntax
class_var = 1
def __init__(self, i_var):
self.i_var = i_var
## Need dot syntax as we've left scope of class namespace
Bar.class_var
## 1
foo = MyClass(2)
## Finds i_var in foo's instance namespace
foo.i_var
## 2
## Doesn't find class_var in instance namespace…
## So look's in class namespace (Bar.__dict__)
foo.class_var
## 1
그리고 시각적 형태로
클래스 속성 할당
클래스에 액세스하여 클래스 속성이 설정되면 모든 인스턴스
foo = Bar(2) foo.class_var ## 1 Bar.class_var = 2 foo.class_var ## 2
인스턴스에 액세스하여 클래스 변수가 설정되면 값을 대체합니다. 해당 인스턴스에만 해당됩니다. 이것은 본질적으로 클래스 변수를 무시하고 직관적으로 사용 가능한 인스턴스 변수로 바꿉니다. 해당 인스턴스에만 해당됩니다.
foo = Bar(2) foo.class_var ## 1 foo.class_var = 2 foo.class_var ## 2 Bar.class_var ## 1
클래스 속성은 언제 사용 하시겠습니까?
상수 저장. 클래스 속성에 클래스 자체의 속성으로 액세스 할 수 있으므로 클래스 전체의 클래스 별 상수를 저장하는 데 사용하는 것이 좋습니다.
class Circle(object): pi = 3.14159 def __init__(self, radius): self.radius = radius def area(self): return Circle.pi * self.radius * self.radius Circle.pi ## 3.14159 c = Circle(10) c.pi ## 3.14159 c.area() ## 314.159
기본값 정의. 사소한 예로, 우리는 경계 목록 (예 : 특정 수의 요소 만 보유 할 수있는 목록)을 만들고 기본 캡이 10 개 항목을 선택할 수 있습니다.
class MyClass(object): limit = 10 def __init__(self): self.data = [] def item(self, i): return self.data[i] def add(self, e): if len(self.data) >= self.limit: raise Exception("Too many elements") self.data.append(e) MyClass.limit ## 10
여기에있는 의견과 dups로 표시된 두 가지 질문에 모두 같은 방식으로 이것에 대해 혼란스러워 보이기 때문에 그 위에 추가 답변을 추가 할 가치가 있다고 생각합니다. Alex Coventry 's.
Alex가 목록과 마찬가지로 변한 유형의 값을 할당한다는 사실은 물건이 공유되는지 여부와 관련이 없습니다. 우리는 이것을 볼 수 있습니다 id
기능 또는 is
운영자:
>>> class A: foo = object()
>>> a, b = A(), A()
>>> a.foo is b.foo
True
>>> class A:
... def __init__(self): self.foo = object()
>>> a, b = A(), A()
>>> a.foo is b.foo
False
(내가 왜 사용했는지 궁금하다면 object()
말하는 대신 5
, 그것은 내가 여기에 들어가고 싶지 않은 두 가지 다른 문제에 빠지지 않는 것입니다. 두 가지 다른 이유로 완전히 별도로 만들어졌습니다 5
s는 숫자의 동일한 인스턴스가 될 수 있습니다. 5
. 그러나 완전히 별도로 만들어졌습니다 object()
S는 할 수 없습니다.)
그래서 왜 그런가요? a.foo.append(5)
Alex의 예에서는 영향을 미칩니다 b.foo
, 하지만 a.foo = 5
내 예에서는 그렇지 않습니까? 글쎄요 a.foo = 5
Alex의 예에서, 그것이 영향을 미치지 않는다는 것을 알았습니다. b.foo
거기 어느 하나.
a.foo = 5
그냥 만들고 있습니다 a.foo
이름으로 5
. 그것은 영향을 미치지 않습니다 b.foo
, 또는 이전 가치에 대한 다른 이름 a.foo
* 우리가 클래스 속성을 숨기는 인스턴스 속성을 만드는 것은 약간 까다 롭습니다.
Alex가 목록을 사용한 이유는 이제 분명합니다. 목록을 돌연변이 할 수 있다는 사실은 두 개의 변수가 동일한 목록의 이름을 표시하는 것이 더 쉽고 실제 코드에서 두 목록이 있는지 또는 두 개의 목록이 있는지 여부를 아는 것이 더 중요하다는 것을 의미합니다. 같은 목록의 두 이름.
* C ++와 같은 언어에서 나오는 사람들의 혼란은 파이썬에서 값이 변수에 저장되지 않는다는 것입니다. 값은 가치 고유로 살아 가고, 그 자체로는 변수는 값의 이름 일 뿐이며, 할당은 단지 값의 새 이름을 만듭니다. 도움이되면 각 파이썬 변수를 shared_ptr<T>
대신 a T
.
** 일부 사람들은 인스턴스가 설정되거나 설정되지 않을 수있는 인스턴스 속성에 대한 클래스 속성을 "기본값"으로 사용하여이를 활용합니다. 이것은 경우에 따라 유용 할 수 있지만 혼란 스러울 수도 있으므로주의하십시오.
상황이 하나 더 있습니다.
클래스 및 인스턴스 속성입니다 설명자.
# -*- encoding: utf-8 -*-
class RevealAccess(object):
def __init__(self, initval=None, name='var'):
self.val = initval
self.name = name
def __get__(self, obj, objtype):
return self.val
class Base(object):
attr_1 = RevealAccess(10, 'var "x"')
def __init__(self):
self.attr_2 = RevealAccess(10, 'var "x"')
def main():
b = Base()
print("Access to class attribute, return: ", Base.attr_1)
print("Access to instance attribute, return: ", b.attr_2)
if __name__ == '__main__':
main()
위의 출력 :
('Access to class attribute, return: ', 10)
('Access to instance attribute, return: ', <__main__.RevealAccess object at 0x10184eb50>)
클래스 또는 인스턴스를 통한 동일한 유형의 인스턴스 액세스가 다른 결과를 반환합니다!
그리고 나는 발견했다 c.pyobject_genericgetattr 정의, 그리고 위대한 게시하다.
설명
속성이 구성된 클래스 사전에있는 경우. 객체 MRO를 확인한 다음, 속성이 데이터 디스크립터를 가리키는 지 확인하십시오 (이는 두 가지를 구현하는 클래스가 더 이상 아무것도 아닙니다.
__get__
그리고__set__
행동 양식). 그렇다면 호출하여 속성 조회를 해결하십시오.__get__
데이터 설명 자의 방법 (28-33 행).