Метод класса в модуле не видит мои глобальные переменные () - PullRequest
0 голосов
/ 06 декабря 2018

У меня проблема с глобальными переменными, использующими метод класса из моего тестового модуля

Пример: Текст моего тестового модуля:

cat ./testmodule.py

class testclass(object):
    def __init__(self):
        self.testfunc()

    def testfunc(self):
        print(' '.join(globals()).split(' '))

Текст моего тестового класса такой же:

class testclass(object):
    def __init__(self):
        self.testfunc()

    def testfunc(self):
        print(' '.join(globals()).split(' '))

Текст моего тестового функционала, ничего нового:

def testfunc():
    print(' '.join(globals()).split(' '))

И иди, чтобы проверить его.

Python 3.6.6 (default, Aug 13 2018, 18:24:23)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>>
>>> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa='a'
>>>
>>> import testmodule
>>>
>>> class testclass(object):
...     def __init__(self):
...         self.testfunc()
...
...     def testfunc(self):
...         print(' '.join(globals()).split(' '))
...
>>> def testfunc():
...     print(' '.join(globals()).split(' '))

Все готово, давайте проверим

>>> testfunc()
['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'testmodule', 'testclass', 'testfunc']

Отлично, я вижу мою переменную aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

>>> testclass.testfunc(testclass)
['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'testmodule', 'testclass', 'testfunc']

Тот же результат, посмотрите на переменную, потрясающий

>>> testmodule.testclass.testfunc(testclass)
['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__file__', '__cached__', '__builtins__', 'testclass']
>>>

Привет!легко легко!WTF?Переменная потеряна.

Помогите мне, пожалуйста. Как я могу получить такой же результат от testmodule, как от testclass и testfunc?

1 Ответ

0 голосов
/ 06 декабря 2018

Расширение комментария @ chepner: globals() возвращает переменные уровня модуля только текущего модуля.

  • Когда вы определяете testfunc() в REPL, оно определяется как __main__.testfuncи вызов globals() возвращает по существу __main__.__dict__.
  • Когда определено в вашем testmodule, оно определяется как testmodule.testfunc, а globals() возвращает testmodule.__dict__.

Если вы хотите, чтобы testfunction имел доступ к глобальным переменным другого модуля, вам необходимо убедиться, что globals() вызывается в лексической области видимости модуля.Самым простым было расширить testfunction, чтобы получить словарь в качестве аргумента:

## testmodule.py
def testfunc(globals_):
    print(globals)

## REPL or other module
import testmodule
testmodule.testfunc(globals())

Дополнительные сведения

  • __main__ не определено по умолчанию.Вам нужно import __main__, прежде чем вы сможете его использовать.Но вы можете видеть, что текущий модуль называется __main__ из переменной __name__.
  • Когда вы запускаете python somescript.py, содержимое файла выполняется как модуль __main__, а не какsomescript module.
  • В Python есть замыкания, а функции внутри модулей ведут себя практически как замыкания в области видимости модуля - поэтому я ожидал, что globals() будет членом каждого модуля.Тогда следующее дало бы ожидаемый результат:

    %% testmodule.py
    def testfunc(globals_):
        print(_globals())
    
    %% REPL
    import testmodule
    testmodule.testfunc(globals)
    

    , но опять же, это возвращает глобальные переменные только тестового модуля.Вместо этого globals определяется только в __builtin__ и, похоже, использует область вызова как скрытый аргумент.Как следствие:

    ## REPL
    import testmodule
    testmodule.testfunc(globals) # prints testmodule.__dict__
    testmodule.testfunc(lambda: globals())  # prints __main__.__dict__
    

    Обычно ожидайте, что f и lambda: f() будут иметь одинаковый результат.

  • Вы не можете полагаться на somemodule.__dict__ длябыть определенным.Модуль может на самом деле вернуть некоторый объект-обертку вместо обычного объекта модуля, когда вы импортируете его.На самом деле, ничто даже не навязывает, что somemodule имеет типичную семантику модуля!Например, попробуйте модуль:

    ## somemodule.py -- Please don't actually do this.
    import sys
    sys.modules["somemodule"] = "not a module"
    
    ## REPL
    >>> import somemodule
    >>> somemodule
    'not a module'
    

    Реальным примером таких изменений будет os.path:

    >>> import os.path
    >>> os.path
    <module 'ntpath' from 'C:\tools\msys64\mingw64\lib\python2.7\ntpath.pyc'>
    
...