문제

다음 사이에 의미있는 차이가 있습니까?

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

그리고 시각적 형태로

enter image description here

클래스 속성 할당

  • 클래스에 액세스하여 클래스 속성이 설정되면 모든 인스턴스

    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, 그것은 내가 여기에 들어가고 싶지 않은 두 가지 다른 문제에 빠지지 않는 것입니다. 두 가지 다른 이유로 완전히 별도로 만들어졌습니다 5s는 숫자의 동일한 인스턴스가 될 수 있습니다. 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 행).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top