다음은 간단한 예제 모듈에 대한 코드의 디스 어셈블리입니다. 코드 객체는 바이트 코드, 사용되는 상수 및 이름에 대한 읽기 전용 컨테이너이며 로컬 변수의 수, 필수 스택 크기 등에 대한 메타 데이터입니다. 모든 코드 객체는 상수로 컴파일됩니다. 이들은 컴파일 시간에 생성됩니다. 그러나 객체 class A
및 function test
은 실행시에 인스턴스화됩니다 (예 : 모듈을 가져올 때).
는
BUILD_CLASS
이름
'A'
, 기지
tuple
(object,)
하고, 클래스 네임 스페이스의 속성을 포함하는
dict
소요 클래스를 확인하십시오. 이는
type(name, bases, dict)
을 호출하여 수동으로 유형을 인스턴스화하는 것과 같습니다.
dict
을 만들려면 코드 객체
A
에서 함수가 만들어지고 호출됩니다. 마지막으로 클래스 객체는
STORE_NAME
을 통해 모듈 네임 스페이스에 저장됩니다.
코드 개체 A
에서 의 인수로 self.z
이 스택에로드됩니다. 바이트 코드가 LOAD_NAME
인 경우 현재 지역 (즉, 클래스 네임 스페이스가 정의 됨), 모듈 전역 및 기본 제공 항목에서 self
을 검색합니다. self
이 global 또는 builtins 범위에 정의되어 있지 않으면 분명히 실패합니다. 그것은 분명히 지역 범위에서 정의되지 않습니다.
그러나 성공한 경우 (self.z,)
이라는 특성을 사용하여 __defaults__
특성으로 만든 다음 로컬 이름 test
에 저장합니다.
>>> code = compile('''
... class A(object):
... def test(self, a=self.z): pass
... ''', '<input>', 'exec')
>>> dis.dis(code)
2 0 LOAD_CONST 0 ('A')
3 LOAD_NAME 0 (object)
6 BUILD_TUPLE 1
9 LOAD_CONST 1 (<code object A ...>)
12 MAKE_FUNCTION 0
15 CALL_FUNCTION 0
18 BUILD_CLASS
19 STORE_NAME 1 (A)
22 LOAD_CONST 2 (None)
25 RETURN_VALUE
>>> dis.dis(code.co_consts[1]) # code object A
2 0 LOAD_NAME 0 (__name__)
3 STORE_NAME 1 (__module__)
3 6 LOAD_NAME 2 (self)
9 LOAD_ATTR 3 (z)
12 LOAD_CONST 0 (<code object test ...>)
15 MAKE_FUNCTION 1
18 STORE_NAME 4 (test)
21 LOAD_LOCALS
22 RETURN_VALUE
@uselpa : 귀하의 페이스트 빈 예 (2.X 용으로 다시 작성) : 당신이 볼 수 있듯이
이
>>> code = compile('''
... default = 1
... class Cl(object):
... def __init__(self, a=default):
... print a
... Cl()
... default = 2
... Cl()
... ''', '<input>', 'exec')
>>> dis.dis(code)
2 0 LOAD_CONST 0 (1)
3 STORE_NAME 0 (default)
3 6 LOAD_CONST 1 ('Cl')
9 LOAD_NAME 1 (object)
12 BUILD_TUPLE 1
15 LOAD_CONST 2 (<code object Cl ...>)
18 MAKE_FUNCTION 0
21 CALL_FUNCTION 0
24 BUILD_CLASS
25 STORE_NAME 2 (Cl)
6 28 LOAD_NAME 2 (Cl)
31 CALL_FUNCTION 0
34 POP_TOP
7 35 LOAD_CONST 3 (2)
38 STORE_NAME 0 (default)
8 41 LOAD_NAME 2 (Cl)
44 CALL_FUNCTION 0
47 POP_TOP
48 LOAD_CONST 4 (None)
51 RETURN_VALUE
는, 클래스 객체 Cl
(그리고 함수 객체 __init__
가)에만 인스턴스화 로컬 이름 'Cl'
에 한 번 저장됩니다. 런타임에 모듈이 순차적으로 실행되므로 default
이라는 이름을 다시 바인딩하면 기본값 인 __init__
에 아무런 영향을 미치지 않습니다. 새로운 __defaults__
튜플로 함수를 작성하는이 __init__.__code__
에서 이미 컴파일 된 코드 개체를 재사용
>>> default = 1
>>> class Cl(object):
... def __init__(self, a=default):
... print a
...
>>> from types import FunctionType
>>> default = 2
>>> Cl.__init__ = FunctionType(
... Cl.__init__.__code__, globals(), '__init__', (default,), None)
>>> c = Cl()
2
: 당신은 동적 이전에 컴파일 된 코드와 새로운 기본값을 사용하여 새 기능을 인스턴스화 할 수
인수가 falsy 값을 취할 수없는 경우
>>> Cl.__init__.__defaults__
(2,)
, 당신은 단지'작성해야하는 경우 A : = self.z' 또는 'A = A 또는 self.z'. – danijar
나는 당신이 'a not : a = self.z'를 의미한다고 생각한다. – BBischof
이것은 표준 pythonic 패턴인가? 선택적인 메소드 속성의 폴백 (fall-back)으로 사용되는 기본값을 가진 클래스 속성을 갖는가? 아니면'z = None' 속성을 포함하도록'extendedClass' __init__ 생성자를 변경하는 것이 더 낫습니다. 그리고'None'을 메소드 내부의 어떤 디폴트로 설정하고 메소드 매개 변수로 가지지 않는다면? 하드 코딩 된 클래스 속성을 가지는 것은 실제로 상수 일 때 유용하다고 생각할 수 있습니다. 둘 이상의 메소드에서 필요합니다. 그렇지 않으면 메소드의 범위에 'z'를 제한하지 않는 것이 좋습니다. 클래스 나 객체가 없을 수도 있습니다. 속성? – Davos