내가 원하는 것은이 동작입니다.
class a:
list = []
x = a()
y = a()
x.list.append(1)
y.list.append(2)
x.list.append(3)
y.list.append(4)
print(x.list) # prints [1, 3]
print(y.list) # prints [2, 4]
물론 인쇄 할 때 실제로 발생하는 일은 다음과 같습니다.
print(x.list) # prints [1, 2, 3, 4]
print(y.list) # prints [1, 2, 3, 4]
분명히 그들은 수업 시간에 데이터를 공유하고 있습니다 a
. 원하는 동작을 수행하기 위해 별도의 인스턴스를 얻으려면 어떻게해야합니까?
답변
당신은 이것을 원합니다 :
class a:
def __init__(self):
self.list = []
클래스 선언 내부의 변수를 선언하면 인스턴스 멤버가 아닌 “클래스”멤버가됩니다. __init__
메서드 내에서 선언 하면 멤버의 새 인스턴스가 객체의 모든 새 인스턴스와 함께 만들어 지므로 원하는 동작입니다.
답변
받아 들여진 대답은 효과가 있지만 조금 더 설명해도 아프지 않습니다.
인스턴스 생성시 클래스 속성은 인스턴스 속성이되지 않습니다. 값이 할당되면 인스턴스 속성이됩니다.
원래 코드에서는 list
인스턴스화 후 속성에 값이 할당되지 않습니다 . 그래서 클래스 속성으로 남아 있습니다. 인스턴스화 후 호출 __init__
되므로 작업 내부 목록 정의 __init__
또는이 코드는 원하는 출력을 생성합니다.
>>> class a:
list = []
>>> y = a()
>>> x = a()
>>> x.list = []
>>> y.list = []
>>> x.list.append(1)
>>> y.list.append(2)
>>> x.list.append(3)
>>> y.list.append(4)
>>> print(x.list)
[1, 3]
>>> print(y.list)
[2, 4]
그러나 질문에서 혼란스러운 시나리오는 숫자와 문자열과 같은 불변의 객체에는 절대로 발생하지 않습니다. 할당없이 값을 변경할 수 없기 때문입니다. 예를 들어 문자열 속성 유형을 가진 원본과 비슷한 코드는 아무런 문제없이 작동합니다.
>>> class a:
string = ''
>>> x = a()
>>> y = a()
>>> x.string += 'x'
>>> y.string += 'y'
>>> x.string
'x'
>>> y.string
'y'
요약하자면, 클래스 속성은 인스턴스화 후 __init__
메소드에 있는지 여부에 관계없이 값이 지정된 경우에만 인스턴스 속성이됩니다 . 인스턴스화 후 속성에 값을 할당하지 않으면 정적 속성을 가질 수 있기 때문에 이것은 좋은 방법입니다.
답변
“인스턴스 레벨 특성”이 아닌 “목록”을 “클래스 레벨 특성”으로 선언했습니다. 인스턴스 수준에서 속성 범위를 지정하려면 __init__
메서드 에서 “self”매개 변수를 참조하여 (또는 상황에 따라 다른 곳 에서) 속성을 초기화해야합니다 .
__init__
메서드 에서 인스턴스 속성을 엄격하게 초기화 할 필요는 없지만 이해하기 쉽습니다.
답변
허용 된 답변이 발견되었지만 약간의 설명을 추가하고 싶습니다.
작은 운동을하자
우선 다음과 같이 클래스를 정의하십시오.
class A:
temp = 'Skyharbor'
def __init__(self, x):
self.x = x
def change(self, y):
self.temp = y
그래서 우리는 여기에 무엇을해야합니까?
- 우리는
temp
문자열 인 속성 을 가진 매우 간단한 클래스를 가지고 있습니다 __init__
설정 하는 방법self.x
- 변경 방법 세트
self.temp
지금까지 꽤 직설적입니까? 이제이 수업을 시작해 봅시다. 이 클래스를 먼저 초기화 해 봅시다 :
a = A('Tesseract')
이제 다음을 수행하십시오.
>>> print(a.temp)
Skyharbor
>>> print(A.temp)
Skyharbor
글쎄, a.temp
예상대로 작동했지만 어떻게 A.temp
작동 했습니까? temp는 클래스 속성이기 때문에 잘 작동했습니다. 파이썬의 모든 것은 객체입니다. 여기 A는 class의 객체이기도합니다 type
. 따라서 속성 temp는 A
클래스가 보유한 속성 이므로 temp의 값을 A
(를 통해가 아닌) 통해 a
변경하면 변경된 값이 모든 A
클래스 의 인스턴스에 반영됩니다 . 계속해서 해봅시다 :
>>> A.temp = 'Monuments'
>>> print(A.temp)
Monuments
>>> print(a.temp)
Monuments
흥미롭지 않습니까? 그리고 점에 유의 id(a.temp)
하고 id(A.temp)
여전히 동일합니다 .
모든 파이썬 객체 __dict__
에는 속성 목록이 포함 된 속성 이 자동으로 부여됩니다 . 예제 객체에 대해이 사전에 포함 된 내용을 조사해 보겠습니다.
>>> print(A.__dict__)
{
'change': <function change at 0x7f5e26fee6e0>,
'__module__': '__main__',
'__init__': <function __init__ at 0x7f5e26fee668>,
'temp': 'Monuments',
'__doc__': None
}
>>> print(a.__dict__)
{x: 'Tesseract'}
참고 temp
속성 사이에 나열되어 A
있는 동안 클래스의 속성 x
인스턴스에 대해 나열됩니다.
따라서 a.temp
인스턴스에 대해 나열되지 않은 경우 의 정의 된 값을 얻는 방법은 무엇입니까 a
? 이것이 바로 __getattribute__()
방법 의 마술입니다 . 파이썬에서 점으로 구분 된 구문은이 메소드를 자동으로 호출하므로 우리가 작성할 때 a.temp
파이썬이 실행 a.__getattribute__('temp')
됩니다. 이 메소드는 속성 조회 조치를 수행합니다. 즉, 다른 위치를보고 속성의 값을 찾습니다.
__getattribute__()
검색 의 표준 구현은 먼저 객체 의 내부 사전 ( dict )과 객체 자체의 유형을 차례로 검색합니다. 이 경우 a.__getattribute__('temp')
먼저 실행 a.__dict__['temp']
한 다음a.__class__.__dict__['temp']
자 이제 우리의 change
방법을 사용하자 :
>>> a.change('Intervals')
>>> print(a.temp)
Intervals
>>> print(A.temp)
Monuments
글쎄 지금 우리가 사용하는 것으로 self
, print(a.temp)
우리는 다른 값을 제공합니다 print(A.temp)
.
이제 id(a.temp)
와 를 비교하면 id(A.temp)
서로 다릅니다.
답변
예. 목록이 클래스 속성이 아닌 객체 속성이되도록하려면 “생성자”에서 선언해야합니다.
답변
따라서 거의 모든 반응이 특정 요점을 놓친 것 같습니다. 클래스 변수 는 아래 코드에서 보여주는 것처럼 인스턴스 변수가 되지 않습니다 . 메타 클래스를 사용하여 클래스 수준에서 변수 할당을 가로 채면 a.myattr이 다시 할당 될 때 클래스의 필드 할당 마법 메서드가 호출되지 않음을 알 수 있습니다. 할당 이 새 인스턴스 변수를 작성 하기 때문 입니다. 이 문제는 없습니다 절대적으로 아무것도 더 클래스 변수가 없습니다 아직 여전히 필드 할당을 허용하는 두 번째 클래스에 의해 입증 된 바와 같이 클래스 변수로 할 수 있습니다.
class mymeta(type):
def __init__(cls, name, bases, d):
pass
def __setattr__(cls, attr, value):
print("setting " + attr)
super(mymeta, cls).__setattr__(attr, value)
class myclass(object):
__metaclass__ = mymeta
myattr = []
a = myclass()
a.myattr = [] #NOTHING IS PRINTED
myclass.myattr = [5] #change is printed here
b = myclass()
print(b.myattr) #pass through lookup on the base class
class expando(object):
pass
a = expando()
a.random = 5 #no class variable required
print(a.random) #but it still works
짧은 클래스 변수는 인스턴스 변수와 관련이 없습니다.
더 명확하게 인스턴스에 대한 검색 범위 내에있게됩니다. 클래스 변수는 실제로 클래스 객체 자체의 인스턴스 변수 입니다. 메타 클래스 자체도 객체이기 때문에 원하는 경우 메타 클래스 변수를 가질 수도 있습니다 . 모든 것은 다른 객체를 만드는 데 사용되는지 여부에 관계없이 객체이므로 단어 클래스의 다른 언어 사용의 의미에 묶이지 마십시오. 파이썬에서 클래스는 실제로 다른 객체를 만드는 방법과 그 동작을 결정하는 데 사용되는 객체 일뿐입니다. 메타 클래스는이 점을 더 자세히 설명하기 위해 클래스를 만드는 클래스입니다.
답변
다른 인스턴스가 공유하는 변수를 보호하려면 인스턴스를 작성할 때마다 새 인스턴스 변수를 작성해야합니다. 클래스 내에서 변수를 선언하면 클래스 변수이며 모든 인스턴스가 공유합니다. 예를 들어 현명하게 만들려면 인스턴스 를 참조하여 변수를 다시 초기화 하기 위해 init 메소드를 사용해야합니다
에서 파이썬은 객체와 클래스 Programiz.com에 의해 :
__init__()
함수. 이 특수 함수는 해당 클래스의 새 객체가 인스턴스화 될 때마다 호출됩니다.이 유형의 함수는 객체 지향 프로그래밍 (OOP)에서 생성자라고도합니다. 일반적으로 모든 변수를 초기화하는 데 사용합니다.
예를 들면 다음과 같습니다.
class example:
list=[] #This is class variable shared by all instance
def __init__(self):
self.list = [] #This is instance variable referred to specific instance