Ответ 1
Новые операторы хранятся в вложенном байт-коде. Вы можете увидеть при разборке, что загружен другой объект кода:
9 LOAD_CONST 1 (<code object A at 0x1004ebb30, file "test0.py", line 4>)
Вам нужно проверить этот объект кода. Это потому, что тело класса выполняется точно так же, как объект функции, и локальное пространство имен, которое вызывает вызовы, затем используется для формирования членов класса.
Демо:
>>> import dis
>>> def wrapper():
... class A(object):
... pass
...
>>> dis.dis(wrapper)
2 0 LOAD_CONST 1 ('A')
3 LOAD_GLOBAL 0 (object)
6 BUILD_TUPLE 1
9 LOAD_CONST 2 (<code object A at 0x104b99930, file "<stdin>", line 2>)
12 MAKE_FUNCTION 0
15 CALL_FUNCTION 0
18 BUILD_CLASS
19 STORE_FAST 0 (A)
22 LOAD_CONST 0 (None)
25 RETURN_VALUE
>>> dis.dis(wrapper.__code__.co_consts[2])
2 0 LOAD_NAME 0 (__name__)
3 STORE_NAME 1 (__module__)
3 6 LOAD_LOCALS
7 RETURN_VALUE
Это та же настройка, что и ваш первый образец; доступ к элементу класса осуществляется через кортеж wrapper.__code__.co_consts
, к которому относится код байта LOAD_CONST
; индекс указывается как 2
.
Теперь мы можем добавить тело класса:
>>> def wrapper():
... class A(object):
... print 'hello'
... 1+1
... pass
...
>>> dis.dis(wrapper)
2 0 LOAD_CONST 1 ('A')
3 LOAD_GLOBAL 0 (object)
6 BUILD_TUPLE 1
9 LOAD_CONST 2 (<code object A at 0x104b4adb0, file "<stdin>", line 2>)
12 MAKE_FUNCTION 0
15 CALL_FUNCTION 0
18 BUILD_CLASS
19 STORE_FAST 0 (A)
22 LOAD_CONST 0 (None)
25 RETURN_VALUE
>>> dis.dis(wrapper.__code__.co_consts[2])
2 0 LOAD_NAME 0 (__name__)
3 STORE_NAME 1 (__module__)
3 6 LOAD_CONST 0 ('hello')
9 PRINT_ITEM
10 PRINT_NEWLINE
4 11 LOAD_CONST 2 (2)
14 POP_TOP
5 15 LOAD_LOCALS
16 RETURN_VALUE
Теперь появляется класс класса; мы можем видеть байт-код, который будет выполняться при загрузке тела класса.
Следует отметить, что байт-коды LOAD_NAME
и STORE_NAME
выполняются для каждого класса класса; те извлекают имя модуля и сохраняют их как новое локальное имя __module__
, так что ваш класс будет иметь атрибут __module__
после создания.
Байт-код LOAD_LOCALS
затем собирает все локальные имена, созданные в этой "функции", и возвращает их вызывающему, так что байт-код BUILD_CLASS
может использовать это вместе со строкой 'A'
и базой object
кортеж (созданный с помощью BUILD_TUPLE
) может создать ваш новый объект класса.