如何解决显示装饰器结果的错误?

How do I solve an error in showing the result of a decorator?

我正在学习Python3,想写一个简单的代码来学习装饰器。我试过 运行 这个代码:

def makebold(fn):
    def wrapped():
            return '<b>' + str(fn) + '</b>'
    return wrapped()

def makeitalic(fn):
    def wrapped():
        return '<i>' + str(fn) + '</i>'
    return wrapped()

@makebold
@makeitalic
def hello():
    return "Hello World"

print(hello())

但我收到以下错误:

Traceback (most recent call last):
  File "E:\Msn Folder\Python\Projects\PythonSamplesByMsn Functions\D03_Decorator01.py", line 29, in <module>
    print(hello())
TypeError: 'str' object is not callable

我做错了什么?我该如何纠正?

您必须删除 return wrapped() 末尾的 () 并将 str(fn) 更改为 str(fn()) 因为必须调用 fn 函数对象。

使用这个

def makebold(fn):
    def wrapped():
        return '<b>' + str(fn()) + '</b>'
    return wrapped

def makeitalic(fn):
    def wrapped():
        return '<i>' + str(fn()) + '</i>'
    return wrapped


@makeitalic
@makebold
def hello():
    return "Hello World"

print(hello())


<i><b>Hello World</b></i>

你应该试试这个:

def makebold(fn):
    def wrapped():
            return '<b>' + str(fn()) + '</b>'
    return wrapped

def makeitalic(fn):
    def wrapped():
        return '<i>' + str(fn()) + '</i>'
    return wrapped

@makebold
@makeitalic
def hello():
    return "Hello World"

print(hello())

你应该在装饰器方法中调用包装函数。

装饰器方法必须return一个函数对象。

首先,请注意

@bar
def foo():
    ...

只是 shorthand 用于:

foo = bar(foo)

即您用函数本身调用bar的结果替换函数。因此,在此之后,foo('baz') 实际上是 bar(foo)('baz'),即试图调用 bar 编辑的 return。

正是出于这个原因,用作装饰器的函数的 return 值 本身必须是可调用的 。但是,您的 "decorators" return stringsnot 可调用的。如果我们定义:

def bar(func):
    return 'bar'

那么很明显 bar(foo)('baz') 变成了 'bar'('baz'),导致您看到的错误:

TypeError: 'str' object is not callable

你的装饰器 return 字符串,因为你 调用 wrapped,因此 return 不管它 return 是什么(一个字符串):

return wrapped()
            # ^ note parentheses in your version

而不是return函数本身:

return wrapped
            # ^ and their absence when fixed

第二个错误是在 wrapped 函数中,您有:

return '<b>' + str(fn) + '</b>'

这里你遇到了与上面 相反的问题 - 你正在制作一个 函数本身 的字符串,而不是使用字符串 the函数 returns。

记住装饰器是用它装饰的函数作为参数调用的,即装饰器内部的 fn 指的是 被装饰的函数 (例如 hello 对于 makebold)。你真正想要包裹标签的是 what the wrapped function returns (它已经是一个字符串,所以你不需要调用 str :

return '<i>' + fn() + '</i>'
               # ^ again, parentheses are important!

您也可以使用适当的字符串格式,而不是 + 连接:

return '<i>{}</i>'.format(fn())