当前位置: 首页 > 面试题库 >

装饰器设置功能的属性

澹台鸿熙
2023-03-14
问题内容

我希望仅当登录用户具有所需的权限级别时,其他功能才可执行。

为了使我的生活更加复杂,我想使用装饰器。下面,我尝试permission在“装饰”功能上设置属性-如下所示。

def permission(permission_required):
    def wrapper(func):
        def inner(*args, **kwargs):
            setattr(func, 'permission_required', permission_required)
            return func(*args, **kwargs)
        return inner
    return wrapper

@permission('user')
def do_x(arg1, arg2):

    ...

@permission('admin')
def do_y(arg1, arg2):
    ...

但是当我这样做时:

fn = do_x
if logged_in_user.access_level == fn.permission_required:
    ...

我得到一个错误 'function' object has no attribute 'permission_required'

我想念什么?


问题答案:

您正在检查内部(包装)函数上的属性,但在原始(包装)函数上进行了设置。但是,您 根本 需要包装函数:

def permission(permission_required):
    def decorator(func):
        func.permission_required = permission_required
        return func
    return decorator

你的装饰需要返回 的东西 那将取代原有的功能。原始函数本身(添加了属性)可以很好地完成此任务,因为您要做的只是向其添加一个属性。

如果仍然需要包装器,则在 包装器函数 上设置属性:

from functools import wraps

def permission(permission_required):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # only use a wrapper if you need extra code to be run here
            return func(*args, **kwargs)
        wrapper.permission_required = permission_required
        return wrapper
    return decorator

毕竟,您要用装饰器返回的包装器替换包装的函数,因此这就是您要在其上查找属性的对象。

我还将@functools.wraps()装饰器添加到包装器中,该装饰器将重要的标识信息和其他有用的东西复制func到包装器中,从而使使用起来更加容易。



 类似资料:
  • 问题内容: 装饰器模式(功能)有很多好处: 当一个方法具有许多正交的关注点时,这将非常有用…也就是说,这些关注点均不相关,除了我们每次调用我们的方法时都希望全部(或部分)关注它们。这是装饰器模式真正有用的地方。 通过实现装饰器模式,我们订阅了开闭主体。我们的方法对将来的扩展开放,但对将来的修改不开放。遵循开放-封闭原则有很多有趣的好处。 但是,我发现的所有示例都非常复杂(例如,编写带有许多中间件的

  • 问题内容: 这段代码返回一个错误:AttributeError:无法设置属性这真的很遗憾,因为我想使用属性而不是调用方法。有谁知道为什么这个简单的例子不起作用? 问题答案: 这是你想要的吗? 取自http://docs.python.org/library/functions.html#property。

  • 问题内容: globalList = [] class MyList: def init(self): self._myList = [1, 2, 3] 结果: 我面临的问题是mL1.myList.append(4)和mL1.myList.extend([5,6,“ eight”,“ IX”])不会修改mL1对象中的_myList属性。我该如何解决该问题? 问题答案: 我为类对象定义了方法appe

  • Object.defineProperty(target, key, { writable: false }); } @ReadOnly // notice there are no `()` name: string; const t = new Test(); t.name = 'jan';

  • 问题 你想通过反省或者重写类定义的某部分来修改它的行为,但是你又不希望使用继承或元类的方式。 解决方案 这种情况可能是类装饰器最好的使用场景了。例如,下面是一个重写了特殊方法 __getattribute__ 的类装饰器, 可以打印日志: def log_getattribute(cls): # Get the original implementation orig_getatt

  • 问题内容: 假设我编写了一个装饰器,它执行了非常通用的操作。例如,它可能会将所有参数转换为特定类型,执行日志记录,实现备忘录等。 这是一个例子: 到目前为止一切都很好。但是,有一个问题。装饰的函数不保留原始函数的文档: 幸运的是,有一种解决方法: 这次,函数名称和文档是正确的: 但是仍然存在一个问题:函数签名是错误的。信息“ * args,** kwargs”几乎没有用。 该怎么办?我可以想到两个