【问题标题】:A per-activation "global" variable in Python?Python中的每次激活“全局”变量?
【发布时间】:2013-02-22 20:41:04
【问题描述】:

这似乎是一件很奇怪的事情,但我很好奇是否可以在 Python 中将变量隐式传递到调用链中而不将其作为参数传递。为了更好地说明这里是一个例子:

这里是“正常”的方式:

def three(something):
    print(something)

def two(something):
    # ...
    three(something)

def one(something):
    # ...
    two(something)

这就是我想要做的:

def three():
    # something is defined implicitly
    print(something)

def two():
    # ...
    three()

def one(something):
    # somehow define something inside a context
    # for this activation 
    two()

为此,onetwothree 不在同一类甚至同一模块中。

【问题讨论】:

  • 如果它们不在同一个类或模块中,如何保证在调用three时会定义一个something
  • 什么都没有。这是一个非常糟糕的 hack,但我仍然希望它能够工作。
  • 所以您正在寻找一个不存在的问题的解决方案?如果您提供一些上下文可能会有所帮助。
  • 你关心线程的情况吗?如果没有,那么调用堆栈永远不应该被中断——那么全局变量如何不够呢?如果线程是一个问题,那么为什么不输入全局变量呢?在某种程度上,必须采取明确的行动来支持您的要求 - 您是在寻找语言功能还是某种框架/使用魔法语言功能就足以满足您的要求?

标签: python


【解决方案1】:
  1. 你不想这样做。

  2. 如果你真的确信你想折磨自己,那么你可以创建一个单独的线程并在该线程中运行对one() 的调用。然后只需将threading.local 用于共享状态。

  3. 你真的不想这样做。

以下是使用线程本地存储的方法:

import threading
state = threading.local()

def three():
    # something is defined implicitly
    print(state.something)

def two():
    # ...
    three()

def one(something):
    # somehow define something inside a context
    # for this activation
    def inner():
        state.something = something
        two()
    t = threading.Thread(target=inner)
    t.start()
    t.join()

if __name__=='__main__':
    one(42)
    one(24)

【讨论】:

  • TLS 具有必须创建另一个线程的开销,并且在由于某种原因(即事件处理程序)无法创建另一个线程的情况下并不总是可以接受的。
  • 虽然 erm,但它适用于 join。尽管如此,仍然有在操作系统级别创建线程的开销。
【解决方案2】:

如果必须,您可以为函数对象本身赋值。理想情况下,如果 'something' 设置不正确,three() 和 two() 都会执行会引发比 AttributeError 更好的异常的检查。

def three():
    print(three.something)

def two():
    three.something = two.something
    three()

def one(something):
    two.something = something
    two()

【讨论】:

  • 但是在这种情况下,两个人必须明确地做一些事情来将那个东西传递给三个人,这不是我想要的。它必须在调用链中向下传递,而无需任何函数执行任何操作。此外,在这种情况下,变量最终是全局变量,而不是在每次激活的基础上完成。
  • 这不会是可重入的
【解决方案3】:

您可以利用词法闭包 - 在 one() 的定义中定义 two() 和 three()。

>>> def one(something):
...     def two():
...         three()
...     def three():
...         print something
...     two()
...
>>> one(1)
1

【讨论】:

  • "为此,一、二、三不在同一个类甚至同一个模块。"
【解决方案4】:

您可以使用__builtins__ 来保存您的“全局变量”。

>>> __builtins__.something = "Hello world!"
>>> def foo():
    print something


>>> foo()
Hello world!

这可以帮助您避免显式传递变量。
这是一个可怕的黑客攻击。恕我直言,你真的不需要这样做。

【讨论】:

  • 这不会使这些变量不依赖于调用它们的激活吗?
猜你喜欢
  • 2020-03-06
  • 2021-04-23
  • 2014-03-06
  • 2013-10-05
  • 2019-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-28
相关资源
最近更新 更多