【问题标题】:Decorators not changing dir()装饰器不改变 dir()
【发布时间】:2017-03-22 06:17:13
【问题描述】:

不使用

的 Python 装饰器
@functools.wraps(function)

改变原来函数的__doc__,__name__,help,这可以理解为装饰器很简单

fun=decorate(fun)

但是为什么它不改变那个函数的 dir(fun) 呢?它不应该也改变吗?

例如:

def wow(func):
    def __wow():
        return func()
    return __wow

@wow
def fun():
    print "yes"
fun.b=1
print fun.__name__
print dir(fun)

输出是

__wow   => name of decorator
[...   '__sizeof__', '__str__', '__subclasshook__', 'b', 'func_closure', ...]
                                                    ^^

如果你看到这里,当我们打印 name 时它是 decorator 但是当我们打印 dir 它的 fun 因为 b 在那里。那么为什么 b 在那里?把dir(decorator) 当作乐趣。name 是装饰者的名字

【问题讨论】:

  • 您希望有什么不同?
  • @vks:您将属性 dir() 应用于装饰结果。您只需在该对象上设置一个新属性,当然dir() 将包含该属性。
  • 我还要求你明确一点:你只是在dir() 中突出显示'b'。你没想到它会在那里吗?请解释输出有什么令人惊讶的地方以及原因。
  • 函数是对象。您从装饰器返回了__wow,因此Python 将该对象分配给funfun 在这里只是一个名称,它引用了装饰器的结果。

标签: python python-2.7 decorator python-decorators


【解决方案1】:

您似乎错过了装饰器的关键步骤。您确实掌握了在函数fun 上使用装饰器@decorate 可以做到这一点:

fun = decorate(fun)

但是不要坚持到底。 fun 现在绑定到装饰器的返回值。

你说:

Python 装饰器 [...] 更改了原始函数的 __doc____name__help

这不是真的。原始的、未装饰的功能没有改变。它仍然具有相同的__doc__、相同的__name__ 等。来自装饰器的返回对象,现在绑定到原始名称,但是,很可能具有不同的名称或文档字符串。毕竟,它很可能是一个完全不同的对象

在您的示例中,您从装饰器返回了__wow,因此Python 将该对象分配给funfun 在这里只是一个名字,它引用了装饰器的结果。 原始 fun 函数不再通过该名称可用; 没有一点你在这里检查原始的,未装饰的功能。

所以在 name fun 上使用 dir() 意味着它适用于现在绑定到 fun 的任何内容,这就是装饰器生成的 __wow 函数。在fun 上设置属性,在同一函数对象上设置属性。所有属性都反映了这一点。

您可能会发现逐步了解 Python 所做的工作并将这些步骤可视化很有帮助。看到这个Python Tutor visualisation;它向您展示了 fun 最后引用的内容(以及原始函数对象的最终位置):

【讨论】:

    【解决方案2】:

    dir() 的函数将返回如下内容:

    >>> dir(f)
    ['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']
    

    你怎么知道这些是原始函数的属性名,还是包装函数的属性名?无论哪种情况,它都是完全相同的列表。

    【讨论】:

    • 如果添加fun.c=1之类的属性,那么您可以自己查看
    • @vks:你真的需要在你的函数中添加一个minimal reproducible example。在代码中向我们展示这些步骤,并解释这些步骤产生的输出如何与您的预期输出不匹配。
    猜你喜欢
    • 2019-06-11
    • 2020-10-09
    • 2019-07-21
    • 2020-05-25
    • 2020-12-20
    • 2020-02-26
    • 2020-06-13
    • 1970-01-01
    • 2022-08-15
    相关资源
    最近更新 更多