Python 修饰函数是否有方法引用由修饰器创建的对象?

Python 修饰函数是否有方法引用由修饰器创建的对象?,python,python-decorators,Python,Python Decorators,我想知道是否有一种方法可以让修饰函数引用由修饰器的包装器创建的对象。我的问题出现在我考虑使用装饰师来: 制作一个包装器,用于创建具有子地块的地物 在包装器内部执行修饰函数,该函数将添加一些绘图 最后将图形保存在包装器中 但是,修饰函数需要引用包装器创建的图形。修饰函数如何引用该对象?我们必须求助于全局变量吗 下面是一个简短的示例,其中我在修饰函数中引用了包装器中创建的变量(但如果不使用全局变量,我无法做到这一点): 我知道这在一个类中很容易做到,但我问这个问题是出于好奇。是的,函数可以通过查看自

我想知道是否有一种方法可以让修饰函数引用由修饰器的包装器创建的对象。我的问题出现在我考虑使用装饰师来:

  • 制作一个包装器,用于创建具有子地块的地物
  • 在包装器内部执行修饰函数,该函数将添加一些绘图
  • 最后将图形保存在包装器中
  • 但是,修饰函数需要引用包装器创建的图形。修饰函数如何引用该对象?我们必须求助于全局变量吗

    下面是一个简短的示例,其中我在修饰函数中引用了包装器中创建的变量(但如果不使用全局变量,我无法做到这一点):


    我知道这在一个类中很容易做到,但我问这个问题是出于好奇。

    是的,函数可以通过查看自身来引用它

    装饰师结束了。它只是获取属性并在函数上设置它们 如果它看起来有点复杂,那是因为接受参数的装饰器需要这个特定的结构才能工作。看

    打电话给装修工 输出 实际上,我经常使用这个。我的想法是将Django视图函数与它们必须协作的特定后端数据类和模板相关联。因为它是声明性的,所以我可以通过所有Django视图进行内省,并跟踪它们关联的URL以及自定义数据对象和模板。工作得很好,但是是的,函数确实希望某些属性本身存在。它不知道是装饰师设计的

    哦,在我的例子中,没有很好的理由让这些变量在我的用例中作为参数传递,这些变量基本上都是硬编码的值,从函数的POV来看,这些值永远不会改变

    一开始很奇怪,但功能非常强大,没有运行时或维护方面的缺陷

    这里有一个活生生的例子,把它放在上下文中

    @declare_view(
        viewmanager_cls=backend.VueManagerDetailPSCLASSDEFN,
        template_name="pssecurity/detail.html",
        objecttype=constants.OBJECTTYPE_PERMISSION_LIST[0],
        bundle_name="pssecurity/detail.psclassdefn",
    )
    def psclassdefn_detail(request, CLASSID, dbr=None, PORTAL_NAME="EMPLOYEE"):
        """
    
        """
        f_view = psclassdefn_detail
        viewmanager = f_view.viewmanager_cls(request, mdb, f_view=f_view)
        ...do things based on the parameters...
        return viewmanager.HttpResponse(f_view.template_name)
    
    试着去做

    使用参数将对象传递给函数 向函数传递值有一种规范的方法:参数

    调用包装器时,将对象作为参数传递给修饰函数

    from functools import wraps
    
    def decorator(f):
        obj = 1
    
        @wraps(f)
        def wrapper(*args):
            return f(obj, *args)
    
        return wrapper
    
    @decorator
    def func(x)
        print(x)
    
    func() # prints 1
    
    使用默认参数传递同一对象 如果需要将同一对象传递给所有函数,则可以将其存储为decorator的默认参数

    from functools import wraps
    
    def decorator(f, obj={}):
        @wraps(f)
        def wrapper(*args):
            return f(obj, *args)
    
        return wrapper
    
    @decorator
    def func(params)
        params['foo'] = True
    
    @decorator
    def gunc(params)
        print(params)
    
    func()
    
    # proof that gunc receives the same object
    gunc() # prints {'foo': True}
    
    上面创建了一个公共的私有dict,它只能由修饰函数访问。由于dict是可变的,所以更改将反映在函数调用中。

    类作为装饰器 将类指向decorator,这似乎是指向decorator中定义的状态的更优雅的方式。它依赖于函数属性,并在装饰类中使用特殊的
    \uuuu call\uuuu()
    方法

    下面是我使用类而不是函数作为装饰器的示例:

    class my_class_decorator:
        def __init__(self, func):
            self.func = func
            self.x =  0
    
        def __call__(self, *args, **kwargs):
            print("x in wrapper:", self.x)
            return self.func(*args, **kwargs)
    
    @my_class_decorator
    def decorated_func():
        decorated_func.x += 1
        print("x in decorated_func:", decorated_func.x)
    
    decorated_func()
    # prints:
    # x in wrapper: 0
    # x in decorated_func: 1
    

    decorator可以在调用包装函数时为其提供额外的参数。通常这是个坏主意,因为装饰是可以选择对函数执行的操作,但您所讨论的场景是装饰与装饰之间的耦合比正常情况要紧密得多。在Python3中,您可以使用
    非局部
    来引用已知由装饰创建的对象。@user2357112好的,对。我把闭包和动态作用域弄糊涂了。你能添加一个代码片段来让你的请求更清晰吗?有多种方法可以实现这一点,但没有一种方法看起来特别好,而且如果你的修饰函数需要了解一些关于修饰器内部的信息,对于一个装饰者来说,这可能不是一个好的用例。你可以在函数上设置属性!?在Python中,一切都是对象。因此,是的,因为视图是Python对象,并且没有
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。在Python2和Python3之间,它们自己的内部属性发生了一些变化。例如,3中的名称可能是
    func.\uuu name\uuu
    ,但2中的名称稍微复杂一些。编辑:在我前面的注释中,阅读“函数”而不是“视图”。
    @declare_view(
        viewmanager_cls=backend.VueManagerDetailPSCLASSDEFN,
        template_name="pssecurity/detail.html",
        objecttype=constants.OBJECTTYPE_PERMISSION_LIST[0],
        bundle_name="pssecurity/detail.psclassdefn",
    )
    def psclassdefn_detail(request, CLASSID, dbr=None, PORTAL_NAME="EMPLOYEE"):
        """
    
        """
        f_view = psclassdefn_detail
        viewmanager = f_view.viewmanager_cls(request, mdb, f_view=f_view)
        ...do things based on the parameters...
        return viewmanager.HttpResponse(f_view.template_name)
    
    from functools import wraps
    
    def decorator(f):
        obj = 1
    
        @wraps(f)
        def wrapper(*args):
            return f(obj, *args)
    
        return wrapper
    
    @decorator
    def func(x)
        print(x)
    
    func() # prints 1
    
    from functools import wraps
    
    def decorator(f, obj={}):
        @wraps(f)
        def wrapper(*args):
            return f(obj, *args)
    
        return wrapper
    
    @decorator
    def func(params)
        params['foo'] = True
    
    @decorator
    def gunc(params)
        print(params)
    
    func()
    
    # proof that gunc receives the same object
    gunc() # prints {'foo': True}
    
    class my_class_decorator:
        def __init__(self, func):
            self.func = func
            self.x =  0
    
        def __call__(self, *args, **kwargs):
            print("x in wrapper:", self.x)
            return self.func(*args, **kwargs)
    
    @my_class_decorator
    def decorated_func():
        decorated_func.x += 1
        print("x in decorated_func:", decorated_func.x)
    
    decorated_func()
    # prints:
    # x in wrapper: 0
    # x in decorated_func: 1