【问题标题】:Method of class in module doesn't see my globals()模块中的类方法看不到我的 globals()
【发布时间】:2019-05-08 09:24:54
【问题描述】:

我在使用我的测试模块中的类方法时遇到全局变量问题

示例: 我的测试模块的文本:

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']

变量存在

>>> 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']
>>>

变量丢失。

如何从 testmodule 中获得与 testclass 和 testfunc 相同的结果?

【问题讨论】:

  • Python 没有进程范围的全局变量,只有模块级的全局变量。
  • 感谢您的回答!有没有办法在模块函数中使用手动定义的变量?可能不是全局变量而是其他东西?
  • 您不想像这样手动创建变量。您的代码如何知道存在哪些变量?
  • 你可能会发现将它们全部打包到模块级字典中是最简单的

标签: python globals


【解决方案1】:

扩展@chepner 的评论:globals() 仅返回当前模块的模块级变量。

  • 当您在 REPL 中定义 testfunc() 时,它被定义为 __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__才能使用它。但是你可以从变量__name__看到当前模块被命名为__main__
  • 当您运行python somescript.py 时,文件的内容将作为__main__ 模块执行,而不是作为somescript 模块执行。
  • 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__
    

    通常期望flambda: 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'>
    

【讨论】:

  • 优秀的答案!我将import __main__ 添加到模块并使用__main__.__dict__ 而不是globals() 这正是我需要的,而且效果很好。非常感谢!
  • 为了澄清:尽可能避免使用双下划线函数!它们总是被用作内省和实施的内部领域,例如运算符重载,或其他“神奇”的东西。例如。不要打电话给obj.__len__,而是len(obj)。当然,如果您正在编写一个使交互式 shell 更方便的模块,它可能是完全有效的,但通常模块不应依赖于来自 __main__ 模块的值,除非作为参数显式传递。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-01
  • 2020-08-30
  • 2022-12-20
相关资源
最近更新 更多