2010-06-30 6 views
10

저는 아직 Python을 처음 접했고 Java에서 온 OO 환경을 제공합니다.Python 클래스 범위 및 목록

class MyClass(): 
     mylist = [] 
     mynum = 0 

     def __init__(self): 
       # populate list with some value. 
       self.mylist.append("Hey!") 
       # increment mynum. 

       self.mynum += 1 

a = MyClass() 

print a.mylist 
print a.mynum 

b = MyClass() 

print b.mylist 
print b.mynum 

이 다음과 같은 출력 결과를 실행 : 그래서 내가 주어진, 다음 코드 나에게 매우 이상한 행동을하네요 파이썬으로 작성한 몇 가지 코드가 분명히

['Hey!'] 
1 
['Hey!', 'Hey!'] 
1 

을, 나는 기대 같은 정확한 데이터와 똑같은 결과를 가져 오는 클래스 변수 ... 어디서나 찾을 수없는 것은 문자열이나 숫자를 말하는 것과 다른 목록을 만드는 것입니다. 왜리스트는 같은 목록을 참조하고 있습니까? 후속 인스턴스에서의 첫 번째 인스턴스화? 분명히 나는 ​​어떤 종류의 범위 메카닉이나리스트 생성 메카닉을 오해하고있을 것입니다.

답변

8

tlayton의 답변은 이야기의 일부이지만 모든 것을 설명하지는 않습니다.

print MyClass.mynum 

이 :) 더 많은 혼동을 추가합니다. '0'이 인쇄됩니다. 왜?광고 때문에

self.mynum += 1 

인스턴스 변수를 만들고이어서 그것을 증가시킨다. 클래스 변수는 증가하지 않습니다.

mylist의 이야기가 다릅니다.

self.mylist.append("Hey!") 

은 목록을 만들지 않습니다. 그것은 'append'함수가있는 변수가 존재할 것으로 기대합니다. 인스턴스에는 그러한 변수가 없으므로 인스턴스를 초기화 한 후에 이되는 클래스의 참조를 끝냅니다. Java에서와 마찬가지로 인스턴스는 클래스 변수를 '암시 적으로'참조 할 수 있습니다. '클래스 필드는 인스턴스가 아닌 클래스에 의해 참조되어야합니다'와 같은 경고 (예 : 자바에서 본 이후로 오랜 시간이 걸렸습니다)가 순서대로 표시됩니다. 줄을 추가하십시오

print MyClass.mylist 

이 답변을 확인하십시오 :).

간단히 말해 클래스 변수를 초기화하고 인스턴스 변수를 업데이트하는 것입니다. 인스턴스는 클래스 변수를 참조 할 수 있지만, 일부 'update'문은 자동으로 인스턴스 변수를 작성합니다.

+0

여전히 중요한 부분을 놓치고 있습니다. @ 켄의 대답을 참조하십시오. 'self.mynum + = 1'은'self.mynum = self.mynum + 1'으로 확장됩니다. 이 작업이 실행되면 먼저 오른쪽이 평가됩니다. 'self.mynum'은 인스턴스에서 mynum을 찾아보고 (적어도'__init__'가 처음 호출 될 때) 그것을 찾지 못하고 클래스에서 mynum을 찾는다. 그래서 오른쪽에있는'self.mynum'은'MyClass.mynum'의 값으로 평가됩니다. 그 값은 이제'self '에 할당됩니다.여기서 인스턴스 변수를 참조합니다. –

5

여기에서 뭘하는지는 클래스 변수를 만드는 것이 아닙니다. Python에서 클래스 본문에 정의 된 변수는 클래스 변수 ("MyClass.mylist")와 인스턴스 변수 ("a.mylist") 모두를 생성합니다. 이들은 단일 변수에 대한 다른 이름뿐만 아니라 별개의 변수입니다.

그러나이 방법으로 변수를 초기화하면 초기 값은 한 번만 평가되고 각 인스턴스의 변수로 전달됩니다. 즉, 코드에서 MyClass의 각 인스턴스에 대한 mylist 변수가 단일 목록 객체를 참조하고 있음을 의미합니다.

이 경우 목록과 숫자의 차이점은 자바와 마찬가지로 숫자와 같은 프리미티브 값이 한 변수에서 다른 변수로 전달 될 때 복사된다는 것입니다. 이렇게하면 나타나는 동작이 발생합니다. 변수 초기화가 한 번만 평가 되더라도 0은 각 인스턴스의 변수에 전달 될 때 복사됩니다. 그러나 객체로서, 목록은 그런 일을하지 않으므로 append() 호출은 모두 같은 목록에서옵니다. 대신 다음을 시도하십시오.

class MyClass(): 
    def __init__(self): 
     self.mylist = ["Hey"] 
     self.mynum = 1 

이렇게하면 인스턴스가 생성 될 때마다 값이 별도로 평가됩니다. Java와는 달리,이 스 니펫과 함께 클래스 본문 선언이 필요하지 않습니다. __init __()의 할당은 필요한 모든 선언으로 사용됩니다.

+1

"이 변수는 단일 변수의 다른 이름이 아니라 별도의 변수입니다." <- 나는 이것이 사실이라고 생각하지 않는다. 'id (a.mylist)'와'id (MyClass.mylist)'를 해보고 당신이 얻는 것을보십시오. –

+0

이들은 변수와 값을 구분하는 별도의 변수입니다. a.mylist와 MyClass.mylist는 모두 동일한 객체 (mylist = [] "행을 평가할 때 생성되었지만 여전히 분리되어 있으므로 완전히 다른 목록을 할당 함)를 참조하므로 id()에 대한 두 호출은 equal을 반환합니다. 그 중 하나에 대해서는 나중에 다른 클래스의 값을 변경하지 않을 것입니다. – tlayton

+0

@Mark : 맞지 않습니다. 클래스의 처음 두 줄은 클래스 변수와 클래스 변수 만 만듭니다. 정확한 이야기는 내 대답을 참조하십시오. 인스턴스가 클래스 변수를 참조 할 수 있고 두 개의 명령이 실제로 같은 ID를 반환하지만 'mynum'변수를 반복하면 다른 ID를 반환하십시오. – Confusion

5

+=은 할당 (단지 =+과 동일) 인 반면 append은 개체를 현재 위치로 변경한다는 점에서 차이가 있다고 생각합니다.

mylist = [] 
    mynum = 0 

이렇게하면 클래스 정의 시간에 한 번 클래스 변수를 할당합니다.

self.mylist.append("Hey!") 

문자열을 추가하여 MyClass.mylist 값을 변경합니다.

self.mynum += 1 

이것은, 즉을 self.mynum = self.mynum + 1 같은, 그것 self.mynum (인스턴스 부재)에 할당한다. self.mynum에서 읽는 것은 해당 시간에 해당 이름의 인스턴스 멤버가 없으므로 클래스 멤버로 전달됩니다.

+0

기술적으로 MyClass.mylist는 값이 아닙니다. self.mylist와 마찬가지로 변수입니다. self.mylist.append()를 호출해도 MyClass.mylist의 값은 변경되지 않습니다. 두 변수가 참조하는 목록을 변경합니다. – tlayton

+0

+1. 좋은 대답. @tlayton : '가치'란 무엇을 의미합니까? 확실히'self.mylist.append ("Hey!")를 호출하면 MyClass.mylist의 값이 변경된다고 말할 수 있습니다. –

+0

이 문맥에서 "가치"의 의미를 이해하지 못했습니다. MyClass.mylist의 값은 참조하는 목록입니다. append()를 호출해도 mylist는 다른 목록을 참조하지 않고 목록 자체를 변경합니다. 나는 아마도 "가치"를 너무 기술적으로 해석 할 것입니다. – tlayton