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

时间:2015-04-20 06:35:48

标签: python function typeerror python-3.4 python-decorators

我正在学习Python 3,并希望编写一个简单的代码来学习装饰器。我试着运行这段代码:

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\92\Python\Projects\PythonSamplesByMsn\05 Functions\D03_Decorator01.py", line 29, in <module>
    print(hello())
TypeError: 'str' object is not callable

我做错了什么?我怎么能纠正这个?

3 个答案:

答案 0 :(得分:4)

您必须在()结束时删除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>

答案 1 :(得分:3)

首先,请注意

@bar
def foo():
    ...

只是简写:

foo = bar(foo)

即。你用函数本身调用bar的结果替换函数。因此,在此之后,foo('baz')确实是bar(foo)('baz'),即尝试调用 bar 返回的任何内容。

正是由于这个原因,用作装饰器的函数的返回值本身必须是可调用的。但是,您的“装饰器”会返回字符串,它们可调用。如果我们定义:

def bar(func):
    return 'bar'

然后很明显bar(foo)('baz')变为'bar'('baz'),导致您看到的错误:

TypeError: 'str' object is not callable

您的装饰器返回字符串,因为您调用wrapped ,因此返回它返回的任何内容(字符串):

return wrapped()
            # ^ note parentheses in your version

而不是返回函数本身:

return wrapped
            # ^ and their absence when fixed

您遇到的第二个错误是wrapped函数内部有:

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

这里你有相反的问题 - 你正在创建一个函数本身的字符串,而不是使用函数返回的字符串。

请记住装饰器使用它作为参数装饰的函数调用,即装饰器内的fn引用正在装饰的函数(例如hello for {{ 1}})。你真正想要包装标签的是包装函数返回的内容(已经是一个字符串,所以你不需要调用makebold

str

您也可以使用正确的字符串格式,而不是return '<i>' + fn() + '</i>' # ^ again, parentheses are important! 连接:

+

答案 2 :(得分:-1)

你应该试试这个:

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())

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

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