2016-03-12 7 views
4

Я открываю реализацию CPython, структуру объектов Python и байт-коды Python.Python: информация о реализации функции Python

Играя с функциями, я обнаружил, что пустые функции имеют размер стека 1.
Почему? Что объявлено, что занять пространство стека?


Empty функция:

def empty(): 
    pass 

Функция информация о:

>>> dis.show_code(empty) 

Name:    empty 
Filename:   <pyshell#27> 
Argument count:  0 
Kw-only arguments: 0 
Stack size:   1 
Number of locals: 0 
Variable names: 
Constants: 
    0: None 

Names: 
Flags:    OPTIMIZED, NEWLOCALS, NOFREE 
First line number: 1 
Free variables: 
Cell variables: 



Функция с местными жителями:

def withlocals(): 
    first = 0 
    second = [1, 2, 3] 

Функция: информация о

>>> dis.show_code(withlocals) 

Name:    withlocals 
Filename:   <pyshell#27> 
Argument count:  0 
Kw-only arguments: 0 
Stack size:   3 
Number of locals: 2 
Variable names: 
    0: first 
    1: second 

Constants: 
    0: None 
    1: 0 
    2: 1 
    3: 2 
    4: 3 

Names: 
Flags:    OPTIMIZED, NEWLOCALS, NOFREE 
First line number: 1 
Free variables: 
Cell variables: 
+0

Сама функция, предположительно - это еще один объект в Python. – jonrsharpe

+0

Да, и что означает базовое стекирование? – JumpAlways

+0

Догадка: если функции могут иметь нулевой размер стека, если у них нет локальных переменных, тогда функция, вызывающая другую функцию, может привести к тому, что оба имеют один и тот же адрес. –

ответ

5

stack_size является верхняя граница от использования стека интерпретатором опкодами. Тем не менее, анализ имеет некоторые bugs, а другой, более крупный в конце этого сообщения, поэтому граница не является жесткой.

>>> def empty(): 
...  pass 
... 
>>> import dis 
>>> dis.dis(empty) 
    2   0 LOAD_CONST    0 (None) 
       3 RETURN_VALUE   

Пустая функция возвращает None. Для загрузки ссылки на None поверх стека требуется 1 элемент стека; RETURN_VALUE возвращает значение, которое хранится поверх стека.

локальные переменные сами не входят в этот счет, что очень видно из

>>> def many_vars(): 
...  a = 1 
...  b = 2 
...  c = 3 
...  d = 4 
...  e = 5 
...  f = 6 
...  g = 7 
... 
>>> many_vars.__code__.co_stacksize 
1 

В случае

def withlocals(): 
    first = 0 
    second = [1, 2, 3] 

стек должен быть достаточно большим, чтобы построить список 3. Если вы добавляете элементы в список, стек увеличивается на эту сумму. Я добавил размер стека в каждой точке на свалку:

>>> dis.dis(withlocals) 
    2   0 LOAD_CONST    1 (0)   1 
       3 STORE_FAST    0 (first)  0 

    3   6 LOAD_CONST    2 (1)   1 
       9 LOAD_CONST    3 (2)   2 
      12 LOAD_CONST    4 (3)   3 
      15 BUILD_LIST    3    1 
      18 STORE_FAST    1 (second)  0 
      21 LOAD_CONST    0 (None)  1 
      24 RETURN_VALUE       0 

Однако анализ, кажется, есть ошибки, когда речь идет кортеж констант:

>>> def a_long_tuple(): 
...  first = (0, 0, 0, 0, 0, 0, 0) 
... 
... 
>>> dis.dis(a_long_tuple) 
    2   0 LOAD_CONST    2 ((0, 0, 0, 0, 0, 0, 0)) 
       3 STORE_FAST    0 (first) 
       6 LOAD_CONST    0 (None) 
       9 RETURN_VALUE   
>>> dis.show_code(a_long_tuple) 
Name:    withlocals 
Filename:   <stdin> 
Argument count: 0 
Kw-only arguments: 0 
Number of locals: 1 
Stack size:  7 
Flags:    OPTIMIZED, NEWLOCALS, NOFREE 
Constants: 
    0: None 
    1: 0 
    2: (0, 0, 0, 0, 0, 0, 0) 
Variable names: 
    0: first 

код имеет только один кортеж , то есть константа, но анализ утверждает, что требует пространства стека 7, как в Python 2, так и в 3!

Причина в том, что собранный код для построения постоянного кортежа изначально идентичен строительству списка, за исключением BUILD_TUPLE кода операции в конце; но peephole optimizer optimizes, что в LOAD_CONST из частичного выхода ассемблера. Однако co_stacksize рассчитан на основе исходного собранного кода!

+0

Итак, этот стек используется компилятором Py, и размер ссылается на необходимое пространство для генерации валов PyObjects (int, list, tuple ...), а не в стек кадров текущего кода, а не Это? – JumpAlways

+0

Байт-код Python использует виртуальную машину на основе стека. Это означает, что все стеки доступа к кодам операций отсутствуют, регистров нет. Стекизация - это консервативная оценка верхнего предела, что для байтового кода потребуется пространство стека. –