繁体   English   中英

如何在python中的类定义内访问非本地作用域?

[英]How to access nonlocal scope inside class definition in python?

我想这样做(虚拟示例):

def func():
    nonlocal var
    print (var)

class A:
    var = 'hola'
    func()

但我得到:“ SyntaxError:未找到非本地'var'的绑定”

我真正打算做的是,如果装饰了方法,则将方法名称附加到类范围内的列表中。 像这样:

def decorator(func):
    nonlocal decorated
    decorated.append(func.__name__)
    return func

class A:
    decorated = []
    @decorate
    def f(self):
        pass
y = 20
def f():
    x = 7
    def g():
        nonlocal x # 7
        global y # 20

nonlocal限定符是指外部函数范围中的名称,其中不包括模块范围。 global则做补充。 因此,您错误地使用了nonlocal

使用修饰符标记功能,然后将修饰为返回所有修饰函数的类方法。

import inspect

def decorate(func):
    func.decorated = True
    return func

class A:
    def foo():
        print('foo')

    @decorate
    def bar():
        print('bar')

    @classmethod
    def decorated(cls):
        def is_decorated_method(obj):
            try:
                return inspect.isfunction(obj) and obj.decorated
            except AttributeError:
                # The object has no decorated attribute
                return False

        return [result[1] for result in inspect.getmembers(cls, predicate=is_decorated_method)]

print(A.decorated())
# [<function A.bar at 0x6ffffc0aa60>]

Python只是不允许您这样做。 您可以使用locals()访问类名称空间。 但是在这一点上,您最好将感兴趣的变量传递给装饰器。

# using locals()

def decorator(class_namespace):
    def _decorator(func):
        class_namespace["decorated"].append(func)
        return func
    return _decorator

class A:
    store = decorator(locals())

    decorated = []

    @store
    def func(self):
        pass

    del store

通常,使用一对装饰器很容易。 一种标记您感兴趣的功能,另一种收集它们。

from types import FunctionType

def collect(cls):
    for item in vars(cls).values():
        print(item)
        if isinstance(item, FunctionType) and getattr(item, "marked", False):
            cls.marked_funcs.append(item)
    return cls

def mark(func):
    func.marked = True
    return func

@collect
class B:
    marked_funcs = []

    @mark
    def func(self):
        pass

但是在您的情况下,在类的末尾创建一组函数名可能会更简单。 例如。

class C:
    def func(self):
        pass

    func_names = [f.__name__ for f in [func]]

那个怎么样?

decorated = []

def decorator(func):
    decorated.append(func.__name__)
    def wrapper(self):
        print('wrapper called')
        func(self)
    return wrapper

class A:
    @decorator
    def f(self): print('function called')

print(decorated)
A().f()

输出:

['f']
wrapper called
function called

笔记:

您提供的代码遇到了描述的问题,因为var是类变量,因此必须将其引用为A.var但是您不能在代码中这样做,因为您尝试在定义A之前使用它。 如果是不同的类,则有可能:

class X:
    decorated = []

def decorator(func):
    X.decorated.append(func.__name__)
    return func

class A:

    @decorator
    def f(self):
        pass

print(X.decorated)

请注意,如果您没有分配给变量,而是调用诸如append()类的方法,则无需指定nonlocal变量。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM