К сожалению, func_code.co_names
вряд ли сильно поможет.Он содержит все имена, к которым осуществляется доступ в сегменте кода, включая глобальные переменные, в порядке их появления.
class Test(object):
def calc_a(self):
return self.b + self.c
def calc_x(self):
return self.y.a + self.y.b
>>> Test.calc_a.func_code.co_names
('b', 'c')
>>> Test.calc_x.func_code.co_names
('y', 'a', 'b')
Невозможно определить из этого массива, загружены ли 'a' и 'b' из '«Я» или «Я. я».Как правило, единственный способ узнать схему доступа к коду без его выполнения - это разобрать его.
>>> import dis
>>> dis.dis(Test.calc_x)
23 0 LOAD_FAST 0 (self)
3 LOAD_ATTR 0 (y)
6 LOAD_ATTR 1 (a)
9 LOAD_FAST 0 (self)
12 LOAD_ATTR 0 (y)
15 LOAD_ATTR 2 (b)
18 BINARY_ADD
19 RETURN_VALUE
Мы видим, что функция загружает переменную self (которая всегда co_varnames[0]
).для связанной функции), затем из этого объекта загружается атрибут 'y' (co_names[0]
), а затем из этого объекта загружается атрибут 'a' (co_names[1]
).Второй объект стека выталкивается из self.yb, затем добавляются два.
Посмотрите на источник dis.py в стандартной библиотеке lib, чтобы увидеть, как разбирается двоичный код на языке Python C.Загрузка 0-й переменной будет важна для связанных функций.Еще один полезный момент: аргументы функции: co_varnames[:co_argcount]
(остальные или переменные - локальные), а co_freevars
- переменные из включенной неглобальной области.