Oto demontaż kodu dla prostego przykładowego modułu. Obiekt kodu jest kontenerem tylko do odczytu dla kodu bajtowego, stałych i nazw, których używa, oraz metadanych dotyczących liczby zmiennych lokalnych, wymaganego rozmiaru stosu itp. Należy zauważyć, że wszystkie obiekty kodu są kompilowane jako stałe. Są one tworzone w czasie kompilacji. Ale obiekty są tworzone w czasie wykonywania (na przykład, gdy moduł jest importowany).
Aby klasę, BUILD_CLASS
przyjmuje nazwę 'A'
, podstawy tuple
(object,)
i dict
który zawiera atrybuty przestrzeni nazw klasy. To jest jak ręczne tworzenie instancji typu przez wywołanie type(name, bases, dict)
. Aby utworzyć dict
, funkcja jest tworzona z obiektu kodu A
i wywoływana. Na koniec obiekt klasy jest przechowywany w przestrzeni nazw modułu poprzez STORE_NAME
.
W obiekcie kodu A
, self.z
jest ładowany na stos jako argument do MAKE_FUNCTION
. Kod bajtowy op LOAD_NAME
wyszuka self
w bieżących locals (tj. Definiowana przestrzeń nazw klasy), globale modułu i wbudowane. To oczywiście nie powiedzie się, jeśli self
nie jest zdefiniowany w zasięgu globalnym lub wbudowanym; wyraźnie nie jest zdefiniowany w zakresie lokalnym.
Jeśli jednak się to uda, funkcja zostanie utworzona z (self.z,)
jako jej atrybut __defaults__
, a następnie zapisana pod lokalną nazwą 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: Twoja wklejarka przykład (przepisany na 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
Jak widać, klasa obiektu Cl
(i funkcja obiektu __init__
) jest tworzony tylko i zapisywane do lokalnej nazwy 'Cl'
jeden raz. Moduł wykonuje sekwencyjnie w czasie wykonywania, więc ponowne przypisanie nazwy default
nie będzie miało wpływu na domyślną wartość w __init__
.
Można dynamicznie wystąpienia nowej funkcji przy użyciu wcześniej skompilowany kod i nową wartość domyślną:
>>> 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
to ponowne wykorzystanie już skompilowany obiekt kodu z __init__.__code__
aby utworzyć funkcję z nowym __defaults__
krotki:
>>> Cl.__init__.__defaults__
(2,)
Jeśli argument nie może przyjąć wartości falsy, powinieneś po prostu napisać 'if a: a = self.z' lub nawet' a = a lub self.z'. – danijar
Myślę, że masz na myśli 'if not a: a = self.z' – BBischof
Czy jest to standardowy wzorzec pytonowy, tj. Mający właściwość klasy z wartością domyślną, która jest używana jako fallback z opcjonalnej właściwości metody? Czy lepiej zmienić konstruktor 'extendedClass' __init__ tak, aby zawierał opcjonalną własność' z = None', a jeśli 'None' ustawi ją jako domyślną w metodzie, a nie jako parametr metody? Mogę tylko myśleć, że posiadanie zakodowanej klasy własności jest użyteczne, jeśli tak naprawdę jest stałą i wymaganą przez więcej niż jedną metodę, w przeciwnym razie dlaczego nie wystarczy ograniczyć 'z' do zakresu metody, może bez klasy lub obiektu własność w ogóle? – Davos