Содержимое Python3 globals () и locals () - PullRequest
0 голосов
/ 13 сентября 2018

В процессе изучения Python3, пробуя globals () и locals (), я создал очень простую, автономную программу на Python и получил результаты , для которых я прошу экспертного объяснения .

Затем я выполнил те же две функции внутри моей программы на Python (любой) и получил список многих (всех?) Значений в моей программе, независимо от того, было ли оно объявлено локальным или глобальным или не. Насколько я понимаю, функции globals () содержат список всех значений, которые были объявлены как глобальные (то же самое для локальных), но, по моим наблюдениям, результаты показывают что-то другое. Кто-нибудь может объяснить, что я вижу и почему?

Вот программа и результаты:

Программа Python:

 print("Globals=",globals())
 print("Locals=",locals())

Результат (для вышеуказанной двухстрочной программы):

=============== RESTART: /home/pi/Junk/globals_locals_test.py ==========
Globals= {'__package__': None, '__spec__': None, '__loader__': <class '
_frozen_importlib.BuiltinImporter'>, '__doc__': None, '__file__': '
/home/pi/Junk/globals_locals_test.py', '__builtins__': <module 'builtins'
 (built-in)>, '__name__': '__main__'}
Locals= {'__package__': None, '__spec__': None, '__loader__': <class '
_frozen_importlib.BuiltinImporter'>, '__doc__': None, '__file__': '
/home/pi/Junk/globals_locals_test.py', '__builtins__': <module 'builtins'
 (built-in)>, '__name__': '__main__'}
>>>

1 Ответ

0 голосов
/ 13 сентября 2018

Простое объяснение

globals() относится к словарю атрибутов текущего модуля.locals() относится к текущим локальным переменным в вашей функции / фрагменте кода.

Установка переменной будет только когда-либо изменяться locals().(Если вы не укажете python иначе, используя ключевое слово global или nonlocal.)

Здесь приведен пример

По умолчанию для глобалов области модуля по умолчаниюкак локальные:

>>> globals() is locals()
True

Поскольку глобальные переменные в данном случае являются локальными, изменение локальных также изменит глобальные переменные.

Если вы создадите функцию и посмотрите там на локальных, вы увидитечто местные значения будут отличаться

>>> def test():
...    print("globals is locals:", globals() is locals())
...    print("globals:", globals())
...    print("locals:", locals())
>>> test()
globals is locals: False
globals: {'__name__': '__main__', ...}
locals: {}

Местные жители будут автоматически обновляться при изменении локальной функции-функции

>>> def test2():
...     print("locals 1:", locals())
...     x = 1
...     print("locals 2:", locals())
>>> test2()
locals 1: {}
locals 2: {'x': 1}

Нечто подобное происходит при создании новых классов

>>> class Test:
...     print("locals:", locals())
locals: {'__module__': '__main__', '__qualname__': 'Test'}

Более подробное объяснение

Если вы хотите узнать, почему глобалы и местные жители таковы, как они есть, давайте посмотрим, что происходит под капотом Python.

Некоторая земляработа

Весь код Python передает то, что в какой-то момент соответствует функции eval или exec.Эти функции принимают три параметра: source, globals (по умолчанию - текущие глобальные) и locals (по умолчанию - текущие локальные).

Функция globals() и locals() вернет все, что былопередается в функции eval или exec, показанные выше.

Что делает оболочка Python?

Если вы делаете

>>> print(globals())

REPL будет внутренне делать что-то вроде

# This variable stores your globals.
_my_main_module = {}

def exec_some_line(line):
    return eval(line, globals=_my_main_module, locals=_my_main_module)

# ...

exec_some_line("print(globals())")

Как вы можете видеть, оболочка Python в какой-то момент установит globals и locals в один и тот же диктофон.

Выполнение функции

Внутренне выполнение функции по существу будет выполнять три вещи:

  1. Анализировать аргументы, переданные функции, и добавлять их в локальные переменные.
  2. Выполнить код функции
  3. Вернуть ее результат.

Здесь псевдоалгоритм:

def __call__(*args, **kwargs):
    local_variables = parse_signature_with_args(args, kwargs)
    exec(function_source, function_globals, local_variables)
    return function_result

Создание новогоклассы

При использовании оператора класса весь код с отступом будет выполняться отдельно.

  1. создан новый словарь, который будет действовать как locals()
  2. Ваш код выполняется с указанными локальными элементами.
  3. Класс создается с передачей локальных элементов в

Если вы выполните этот код:

class Test:
   a = 5

Это примерно то, что происходит:

 # 1. A new dictionary is created
 _dict = type.__prepare__()
 _dict["__module__"] = __name__
 _dict["__qualname__"] = "Test"

 # 2. Execute the code
 exec("a = 5", globals=globals(), locals=_dict)

 # 3. A class is created
 Test = type("Test", (), _dict)

Как это сопоставляется с импортом модуля

Если вы импортируете модуль, запустится сложный механизм импорта.Это упрощенный обзор:

  1. Интерпретатор будет искать, если модуль уже был импортирован.
  2. Интерпретатор найдет файл.
  3. Тогда файлчтение и анализ
  4. Создан объект модуля.
  5. Сценарий python выполняется, и его глобальные и локальные значения будут установлены на атрибут __dict__ новых модулей.
  6. Возвращается объект модуля.

Он работает примерно так:

import sys
from types import ModuleType
def __import__(name):
    # 1. See if module is already imported
    if name in sys.modules:
       return sys.modules[name]

    # 2. Find file.
    filename = find_out_path_to_file(name)

    # 3. Read and parse file
    with open(filename) as f:
      script = f.read()

    # 4. Create the new module
    module = ModuleType(name)

    # 5. Execute the code of the module.
    exec(script, globals=module.__dict__, locals=module.__dict__)

    # 6. Return the new module.
    return module
...