【问题标题】:Handling `NameError` without raising `SyntaxError` when referencing global variables in python3在python3中引用全局变量时处理`NameError`而不引发`SyntaxError`
【发布时间】:2018-02-10 21:51:26
【问题描述】:

处理NameError 就是提升SyntaxError

所以我正在制作一个装饰器函数,它将生成器函数与字典相关联,目的是让 send() 函数使用起来不那么麻烦。

默认行为是使用在(惊喜!)全局命名空间中定义的名为 global_registry_dict 的字典。

如果global_registry_dict 不存在并且没有明确传入替代字典,则NameError 由python 引发。

当我尝试通过在全局命名空间中创建变量来处理错误时,我收到 SyntaxError 告诉我在分配之前引用了该变量。这是有道理的......但是......就像......这就是我想要解决的问题!

任何帮助将不胜感激!

装饰器的来源:

def make_stateless_actor(func):
    def wrapper(registry_dict=None, *args, **kwargs):
        try:
            if registry_dict is None:
                internal_registry_dict = global_registry_dict
            elif isinstance(registry_dict, dict) or issubclass(registry_dict, dict):
                internal_registry_dict = registry_dict
            else:
                internal_registry_dict = global_registry_dict
        except NameError: # <<== CATCHES IF `global_registry_dict` IS REF'D BUT NOT DEFINED. 
            global global_registry_dict # <<== SYNTAX ERROR HAPPENS HERE
            global_registry_dict = {}
            internal_registry_dict = global_registry_dict
        gen = func(*args, **kwargs)
        next(gen)
        internal_registry_dict[func.__name__] = gen
    return wrapper

异常返回:

File "C:/yall/dont/need/to/know/this/generator_pipeline_utils.py", line 74
global global_registry_dict
^
SyntaxError: name 'global_registry_dict' is used prior to global declaration

整个模块的来源:

# global_registry_dict = {}


def make_stateless_actor(func):
    """
    DESCRIPTION:
    ===========
    This DECORATOR FUNCTION simplifies & centralizes the use of `send()` on generators.

    It does this by ASSOCIATING the decorated function to a dictionary:

        - by default, a global variable named `global_registry_dict` will be used.
        - by default, `global_registry_dict = {}` will be created in the GLOBAL-NAMESPACE if it does not exist.

    IMPORTANT NOTE:
    ==============
    Use the `registry_dict` kwarg to manually assign your generator-func to an alternate dictionary:
            `foo_decorated_func(registry_dict=foo_alternative_dictionary)`

    REQUIREMENTS:
    ============
    You can apply `@make_stateless_actor` to any GENERATOR FUNCTION which:

        - INCLUDES A `yield` expression to the RIGHT of an `=` sign.
        - INCLUDES `**kwargs` as a function argument.
    """
    def wrapper(registry_dict=None, *args, **kwargs):
        try:
            if registry_dict is None: # <<-- necessary to prevent the next elif from throwing an exception.
                internal_registry_dict = global_registry_dict
            elif isinstance(registry_dict, dict) or issubclass(registry_dict, dict):
                internal_registry_dict = registry_dict
            else:
                internal_registry_dict = global_registry_dict
        except NameError:
            print('WARNING: global_registry_dict IS NOT DEFINED AND YOU DID NOT EXPLICITLY PASS registry_dict TO THE DECORATED FUNCTION.\n\
                  `global_registry_dict = {}` has been instantiated in the global-namespace.\n')
            global global_registry_dict
            global_registry_dict = {}
            internal_registry_dict = global_registry_dict
        gen = func(*args, **kwargs)
        next(gen)
        internal_registry_dict[func.__name__] = gen
    return wrapper

@make_stateless_actor
def printer(*args, **kwargs):
    while True:
        item = yield
        print("Got: ", item)

def send(name, msg, registry_dict=None):
    if registry_dict is None:
        global_registry_dict[name].send(msg)
    else:
        registry_dict[name].send(msg)

if __name__ == "__main__":
    printer(registry_dict=None) #<<==BEGIN THE CRAZY.
    # send('printer', 'HEY WHAT IS UP?')
    # send('printer', 666)
    # send('printer', [1, 'a', [], True])

【问题讨论】:

    标签: python python-3.x exception exception-handling decorator


    【解决方案1】:

    您在else 子句中使用名称global_registry_dict 并排几行。如果它是全局的,你必须在使用它之前声明它,就像错误消息所说的那样。通常,名称在函数开头声明为全局的。

    【讨论】:

    • 我可以在开头添加一个检查,但我想我应该澄清一下:在使用except发现它不存在之后,有没有办法实例化一个全局变量?
    • 是的。做你正在做的事,除了将 global 声明移到第一次使用名称的上方,就像我刚才说的那样。
    • 大声笑。是的。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-19
    • 1970-01-01
    相关资源
    最近更新 更多