Python 装饰器的学习重点

装饰器基础
Python的函数是对象
为了理解装饰器, 你必须先理解: 在Python的世界, 函数是对象. 这一点很重要. 让我们通过一个简单的例子来看看为什么:

def shout(word="yes"):
    return word.capitalize()+"!"

print shout()
# 输出 : 'Yes!'

# 作为一个对象, 你可以像任何其他对象一样, 将函数赋值给一个变量

scream = shout

# 注意, 我们并没有使用括号:
# 我们没有调用函数, 我们是将"shout"函数装入到"scream"变量中
# 这意味着你可以像从"scream"调用"shout"

print scream()
# 输出 : 'Yes!'

# 不仅如此, 它还意味着你可以删除旧的名字"shout",
# 而仍然可以通过"scream"访问函数

del shout
try:
    print shout()
except NameError, e:
    print e
    # 输出: "name 'shout' is not defined"

print scream()
# 输出: 'Yes!'
Okay! 在脑海中保留这个概念. 我们之后会用到它.

Python函数的另一个有趣的属性是: 它们可以在另一个函数的内部被定义…

def talk():

    # 你可以在运行时, 在"talk"函数内部定义一个函数
    def whisper(word="yes"):
        return word.lower()+"..."

    # ... 然后立马使用它

    print whisper()

# 当调用"talk"时, 你的每一次调用都会定义"whisper"一次,
# 再调用"whisper"
talk()
# 输出:
# "yes..."

# 但是, "whisper"在"talk"函数之外实际是不存在的

try:
    print whisper()
    except NameError, e:
        print e
        #输出 : "name 'whisper' is not defined"
        #Python的函数是对象
函数引用
还跟得上吗? 现在开始讲有趣的部分…

你已经见识过了函数是对象. 因此,

函数可以赋值给一个变量
函数可以在另一个函数中被定义
这意味着函数可以返回(return)另一个函数. 看仔细了!

def getTalk(kind="shout"):

    # 我们在运行时定义函数
    def shout(word="yes"):
        return word.capitalize()+"!"

    def whisper(word="yes") :
        return word.lower()+"...";

    # 然后我们返回其中的一个
        if kind == "shout":
            # 不适用括号, 我们并不是在调用函数
            # 我们是在返回一个函数对象
            return shout
        else:
            return whisper

# 你要如何使用这洪荒巨兽呢?

# 取得函数, 并将其赋给一个变量
talk = getTalk()

# 此处, 你可以看见"talk"是一个函数对象
print talk
#输出 : <function shout at 0xb7ea817c>

# 以下对象是函数"talk"的一项返回
print talk()
#输出 : Yes!

# 你甚至可以直接使用
# And you can even use it directly if you feel wild:
print getTalk("whisper")()
#输出 : yes...
等等…不止如此!

如果你要return一个函数, 可以传入一个函数作为参数:

def doSomethingBefore(func):
    print "I do something before then I call the function you gave me"
    print func()

doSomethingBefore(scream)
#输出:
#I do something before then I call the function you gave me
#Yes!
现在, 你已经具备了理解装饰器所需的一切知识. 如你所见, 装饰器就是”包装纸(wrapper)”, 也就是说, 装饰器允许你在被装饰的函数前后执行代码, 而不对函数本身做任何修改.

动手写装饰器
你最好动手写一写(装饰器):

# 装饰器是函数, 它以另一个函数作为参数
def my_shiny_new_decorator(a_function_to_decorate):

    # 在装饰器的内部, 定义一个"wrapper"函数
    # wrapper函数用于包装原函数, 以在原函数前后执行代码
    def the_wrapper_around_the_original_function():

        # 在此处输入你想在调用原函数之前执行的代码
        print "Before the function runs"

        # 调用被装饰的函数(是函数调用, 需要括号)
        a_function_to_decorate()

        # 在此处输入你想在调用原函数之后执行的代码
        print "After the function runs"

    # 此处, 被装饰的函数并没有被执行
    # 返回刚刚创建的包装函数
    # 包装函数包括被装饰的函数, 在函数前后执行的代码
    return the_wrapper_around_the_original_function

# 现在, 假设你创建了一个可能用不到的函数
def a_stand_alone_function():
    print "I am a stand alone function, don't you dare modify me"

a_stand_alone_function()
#输出: I am a stand alone function, don't you dare modify me

# 然而, 你可以装饰它, 扩展它
# 只需要将它传递给一个装饰器, 装饰器将动态地将函数包装进任何你想要的代码中
# 并返回一个可用的新函数

a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function_decorated()
#输出:
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs
现在, 你可能想要在每次调用a_stand_alone_function时, 替代地调用a_stand_alone_function_decorated. 很简单, 用装饰器my_shiny_new_decorator返回的函数覆盖原函数a_stand_alone_function即可.

a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function()
#输出:
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs

# 这就是装饰器的作用了
装饰器揭秘
用装饰器语法重现先前的例子, 是这样的:

@my_shiny_new_decorator
def another_stand_alone_function(:
    print "Leave me alone"

another_stand_alone_function(
#outputs:
#Before the function runs
#Leave me alone
#After the function runs
是的, 就是这样, 这么简单. @decorator是以下形式的缩写:

another_stand_alone_function = my_shiny_new_decorator(another_stand_alone_function)
此处所讲的装饰器是装饰器设计模式的python变种. 在python中有一些经典的设计模式, 可使开发更加容易(比如迭代器(iterator)).

当然, 你可以叠加装饰器:

def bread(func):
    def wrapper():
        print "</''''''\>"
        func()
        print "<\______/>"
    return wrapper

def ingredients(func):
    def wrapper():
        print "#tomatoes#"
        func()
        print "~salad~"
    return wrapper

def sandwich(food="--ham--"):
    print food

sandwich()
#输出: --ham--
sandwich = bread(ingredients(sandwich))
sandwich()
#输出:
#</''''''\>
# #tomatoes#
# --ham--
# ~salad~
#<\______/>
python装饰器的语法:

@bread
@ingredients
def sandwich(food="--ham--"):
    print food

sandwich()
#输出:
#</''''''\>
# #tomatoes#
# --ham--
# ~salad~
#<\______/>
你设置装饰器的顺序很重要:

@ingredients
@bread
def strange_sandwich(food="--ham--"):
    print food

strange_sandwich()
#输出:
##tomatoes#
#</''''''\>
# --ham--
#<\______/>
# ~salad~
现在: 针对你的问题(在python中, 如何实现串级装饰器)…
(译者注: 本文是stackoverflow上一个回答)

结论是, 如你所见, 很容易就可以实现串级装饰器:

# 加粗装饰器
def makebold(fn):
    # 装饰器返回的新的函数
    def wrapper():
        # 在前后插入一些代码
        return "<b>" + fn() + "</b>"
    return wrapper

# 斜体装饰器
def makeitalic(fn):
    # 装饰器返回的新的函数
    def wrapper():
        # 在前后插入一些代码
        return "<i>" + fn() + "</i>"
    return wrapper

@makebold
@makeitalic
def say():
    return "hello"

print say()
#输出: <b><i>hello</i></b>

# 等价于
def say():
    return "hello"
say = makebold(makeitalic(say))

print say()
#输出: <b><i>hello</i></b>
现在, 你可以愉快地离开了(译者注: 这是作者对提问者说的). 或者接着烧脑, 看看装饰器的一些高级用法.

装饰器进阶
向被装饰函数传递参数
# 这并不是黑魔法, 你只需要在包装过程中传入参数

def a_decorator_passing_arguments(function_to_decorate):
    def a_wrapper_accepting_arguments(arg1, arg2):
        print "I got args! Look:", arg1, arg2
        function_to_decorate(arg1, arg2)
    return a_wrapper_accepting_arguments

# 当你调用装饰器返回的函数时, 你调用了包装纸(wrapper)
# 向包装纸传递的参数将可继续传递给被装饰函数

@a_decorator_passing_arguments
def print_full_name(first_name, last_name):
    print "My name is", first_name, last_name

print_full_name("Peter", "Venkman")
# 输出:
#I got args! Look: Peter Venkman
#My name is Peter Venkman
装饰方法
python好的一点是, 方法(method)和函数(function)实际是一样的. 唯一的区别在于, 方法的第一个参数需要是当前对象(self)的引用.

这意味着, 你可以用同样的方式创建方法的装饰器! 不过, 别忘了self.

def method_friendly_decorator(method_to_decorate):
    def wrapper(self, lie):
        lie = lie - 3 # 真好, 年龄更小了 :-)
        return method_to_decorate(self, lie)
    return wrapper

class Lucy(object):

    def __init__(self):
        self.age = 32

    @method_friendly_decorator
    def sayYourAge(self, lie):
        print "I am %s, what did you think?" % (self.age + lie)

l = Lucy()
l.sayYourAge(-3)
#输出: I am 26, what did you think?
如果要写一个通用的装饰器–可用于任何函数或方法, 而不必考虑其参数–那么, 用*args, **kwargs就好了:

def a_decorator_passing_arbitrary_arguments(function_to_decorate):
    # 包装纸接收任意参数
    def a_wrapper_accepting_arbitrary_arguments(*args, **kwargs):
        print "Do I have args?:"
        print args
        print kwargs
        # 将得到的参数解压(unpack), 此处为*args, **kwargs
        # 如果对解压不熟悉, 可参考
        # http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/
        function_to_decorate(*args, **kwargs)
    return a_wrapper_accepting_arbitrary_arguments

@a_decorator_passing_arbitrary_arguments
def function_with_no_argument():
    print "Python is cool, no argument here."

function_with_no_argument()
#输出
#Do I have args?:
#()
#{}
#python就是这么酷, 此地无参.

@a_decorator_passing_arbitrary_arguments
def function_with_arguments(a, b, c):
    print a, b, c

function_with_arguments(1,2,3)
#输出
#Do I have args?:
#(1, 2, 3)
#{}
#1 2 3

@a_decorator_passing_arbitrary_arguments
def function_with_named_arguments(a, b, c, platypus="Why not ?"):
    print "Do %s, %s and %s like platypus? %s" %\
    (a, b, c, platypus)

function_with_named_arguments("Bill", "Linus", "Steve", platypus="Indeed!")
#输出
#Do I have args ? :
#('Bill', 'Linus', 'Steve')
#{'platypus': 'Indeed!'}
#Bill, Linus and Steve喜欢鸭嘴兽吗? 千真万确!

class Mary(object):

    def __init__(self):
        self.age = 31

    @a_decorator_passing_arbitrary_arguments
    def sayYourAge(self, lie=-3): # 现在你可以添加一个默认值
        print "I am %s, what did you think ?" % (self.age + lie)

m = Mary()
m.sayYourAge()
#输出
# Do I have args?:
#(<__main__.Mary object at 0xb7d303ac>,)
#{}
#I am 28, what did you think?
向装饰器传递参数
好吧, 现在你觉得如何向装饰器本身传递参数呢?

这有点绕, 因为装饰器必须接收一个函数作为参数. 因此, 你不能向装饰器直接传递被装饰的函数的参数.

在讲解解决方法之前, 让我们先做一个小小的回顾:

# 装饰器是 普通 函数
def my_decorator(func):
    print "I am an ordinary function"
    def wrapper():
        print "I am function returned by the decorator"
        func()
    return wrapper

# 所以, 你可以不使用"@"调用它

def lazy_function():
    print "zzzzzzzz"

decorated_function = my_decorator(lazy_function)
#输出: I am an ordinary function

# 它将会输出 "I am an ordinary function", 因为这就是你所做的:
# 调用一个函. 没有一点魔法在里面

@my_decorator
def lazy_function():
    print "zzzzzzzz"

#输出: I am an ordinary function
上述两者完全相同, 都是调用了my_decorator. 所以当你@my_decorator, 你是在告诉Python去调用被变量my_decorator标记的函数.

这一点很重要! 你可以用标签直接指明装饰器, 或者不这样.

让我们再深入一点.

def decorator_maker():

    print "I make decorators! I am executed only once: "+\
          "when you make me create a decorator."

    def my_decorator(func):

        print "I am a decorator! I am executed only when you decorate a function."

        def wrapped():
            print ("I am the wrapper around the decorated function. "
                  "I am called when you call the decorated function. "
                  "As the wrapper, I return the RESULT of the decorated function.")
            return func()

        print "As the decorator, I return the wrapped function."

        return wrapped

    print "As a decorator maker, I return a decorator"
    return my_decorator

# 让我们创建一个装饰器
new_decorator = decorator_maker()
# 输出:
#I make decorators! I am executed only once: when you make me create a decorator.
#As a decorator maker, I return a decorator

# 接下来, 我们来装饰函数

def decorated_function():
    print "I am the decorated function."

decorated_function = new_decorator(decorated_function)
#输出:
#I am a decorator! I am executed only when you decorate a function.
#As the decorator, I return the wrapped function

# 调用函数:
decorated_function()
#输出:
#I am the wrapper around the decorated function. I am called when you call the decorated function.
#As the wrapper, I return the RESULT of the decorated function.
#I am the decorated function.
这里没有什么可惊奇的.

跳过所有繁琐的中间变量, 以下与上述方法完全一样.

def decorated_function():
    print "I am the decorated function."
decorated_function = decorator_maker()(decorated_function)
#输出:
#I make decorators! I am executed only once: when you make me create a decorator.
#As a decorator maker, I return a decorator
#I am a decorator! I am executed only when you decorate a function.
#As the decorator, I return the wrapped function.

# 最后:
decorated_function()
#输出:
#I am the wrapper around the decorated function. I am called when you call the decorated function.
#As the wrapper, I return the RESULT of the decorated function.
#I am the decorated function.
还可以更精简一些:

@decorator_maker()
def decorated_function():
    print "I am the decorated function."
#outputs:
#I make decorators! I am executed only once: when you make me create a decorator.
#As a decorator maker, I return a decorator
#I am a decorator! I am executed only when you decorate a function.
#As the decorator, I return the wrapped function.

#Eventually:
decorated_function()
#outputs:
#I am the wrapper around the decorated function. I am called when you call the decorated function.
#As the wrapper, I return the RESULT of the decorated function.
#I am the decorated function.
嘿, 你看到了吗? 我们通过”@“语法使用了函数.

所以, 回到带参的装饰器. 如果我们可以用函数在运行时生成装饰器, 我们就能够向那个函数传递参数了, 对吧?

def decorator_maker_with_arguments(decorator_arg1, decorator_arg2):

    print "I make decorators! And I accept arguments:", decorator_arg1, decorator_arg2

    def my_decorator(func):
        # 此处传递参数的能力, 得益于闭包的性质
        # 如果你不习惯闭包, 你可以假设它是ok的, 或者看一下这篇文章:
        # http://stackoverflow.com/questions/13857/can-you-explain-closures-as-they-relate-to-python
        print "I am the decorator. Somehow you passed me arguments:", decorator_arg1, decorator_arg2

        # 不要混淆了装饰器参数和函数参数!
        def wrapped(function_arg1, function_arg2) :
            print ("I am the wrapper around the decorated function.\n"
                  "I can access all the variables\n"
                  "\t- from the decorator: {0} {1}\n"
                  "\t- from the function call: {2} {3}\n"
                  "Then I can pass them to the decorated function"
                  .format(decorator_arg1, decorator_arg2,
                          function_arg1, function_arg2))
            return func(function_arg1, function_arg2)

        return wrapped

    return my_decorator

@decorator_maker_with_arguments("Leonard", "Sheldon")
def decorated_function_with_arguments(function_arg1, function_arg2):
    print ("I am the decorated function and only knows about my arguments: {0}"
           " {1}".format(function_arg1, function_arg2))

decorated_function_with_arguments("Rajesh", "Howard")
#输出:
#I make decorators! And I accept arguments: Leonard Sheldon
#I am the decorator. Somehow you passed me arguments: Leonard Sheldon
#I am the wrapper around the decorated function.
#I can access all the variables
#   - from the decorator: Leonard Sheldon
#   - from the function call: Rajesh Howard
#Then I can pass them to the decorated function
#I am the decorated function and only knows about my arguments: Rajesh Howard
这就是带参的装饰器了.参数也可以设置成变量:

c1 = "Penny"
c2 = "Leslie"

@decorator_maker_with_arguments("Leonard", c1)
def decorated_function_with_arguments(function_arg1, function_arg2):
    print ("I am the decorated function and only knows about my arguments:"
           " {0} {1}".format(function_arg1, function_arg2))

decorated_function_with_arguments(c2, "Howard")
#输出:
#I make decorators! And I accept arguments: Leonard Penny
#I am the decorator. Somehow you passed me arguments: Leonard Penny
#I am the wrapper around the decorated function.
#I can access all the variables
#   - from the decorator: Leonard Penny
#   - from the function call: Leslie Howard
#Then I can pass them to the decorated function
#I am the decorated function and only knows about my arguments: Leslie Howard
如你所见, 使用该技巧, 你可以像任何(普通)函数一样向装饰器传递参数. 如果你愿意, 你甚至可以使用*args, **kwargs. 但是, 请记住装饰器只能被调用1次, 即在导入脚本的时候. 之后你就不能动态地设置参数了. 当你”import x”时, 函数已经被装饰了, 你不能再做任何修改.

练习: 装饰装饰器
作为福利, 我将给你一个能接收任意参数的装饰器代码片段. 然后, 我们用另一个函数来创建我们的装饰器, 以接收参数.

我们对装饰器进行了包装.

如前所见, 我们是用什么包装了函数?

是的, 就是装饰器!

让我们愉快地写一个装饰器的装饰器吧:

def decorator_with_args(decorator_to_enhance):
    """
    这个函数被用作一个装饰器.
    它必须装饰另一个函数, 那个函数也是一个装饰器
    它允许任何装饰器接收任意数量的参数, 这样就不用每次写(装饰器)的时候都回忆一遍.
    """

    # 使用了与上述一样的技巧传递参数
    def decorator_maker(*args, **kwargs):

        # 我们在运行时创建了一个装饰器, 它接收一个函数作为参数
        # 但它可以持有maker传来的参数
        def decorator_wrapper(func):

            # 我们返回原始装饰器的结果, 一个普通函数
            # 唯一的异错的地方在于: 装饰器必须这样才能正常工作
            return decorator_to_enhance(func, *args, **kwargs)

        return decorator_wrapper

    return decorator_maker
它可以像下述一样使用:

# 你可以创建一个用作装饰器的函数. 再用一个装饰器来装饰它
# 不要忘了, 用法是"decorator(func, *args, **kwargs)"
@decorator_with_args
def decorated_decorator(func, *args, **kwargs):
    def wrapper(function_arg1, function_arg2):
        print "Decorated with", args, kwargs
        return func(function_arg1, function_arg2)
    return wrapper

# 现在, 你可以用刚刚创建的被装饰的装饰器来装饰函数了

@decorated_decorator(42, 404, 1024)
def decorated_function(function_arg1, function_arg2):
    print "Hello", function_arg1, function_arg2

decorated_function("Universe and", "everything")
#输出:
#Decorated with (42, 404, 1024) {}
#Hello Universe and everything

# 哇!
我知道, 你最近一次有这种感觉, 是听某人说了: “要理解递归, 你必须先理解递归”. 现在, 对于学会了(装饰器), 你不感觉很棒码?

最佳实践: 装饰器
装饰器最早出现于Python2.4, 所以请确保你的代码能在2.4之后的版本上运行
装饰器减慢了函数调用的速度. 谨记.
你无法对函数去装饰. (确实有技巧可以创建可移除的装饰器, 但没有人会使用它们.) 因此, 一旦函数被装饰了, 在整个代码中, 它都是被装饰的.
装饰器包装了函数, 这使得调试变得困难. (这一点在Pyhton2.5之后的版本得到缓解; 请看下面的内容)
Python2.5引入了functools模块, 该模块包含的funtools.wraps()函数, 可以将被装饰函数名称, 模块, 文档字符串(docstring)拷贝到它的包装纸中.

(有趣的事实是: funtools.wraps()还是一个装饰器!)

# 为了调试方便, 栈回溯(stacktrace)打印函数的__name__属性
def foo():
    print "foo"

print foo.__name__
#输出: foo

# 当使用装饰器时, 就显得混乱了
def bar(func):
    def wrapper():
        print "bar"
        return func()
    return wrapper

@bar
def foo():
    print "foo"

print foo.__name__
#输出: wrapper

# "functools"`模块能解决这个问题

import functools

def bar(func):
    # 我们说"wrapper"包装了"func", 然后魔法就发生了
    @functools.wraps(func)
    def wrapper():
        print "bar"
        return func()
    return wrapper

@bar
def foo():
    print "foo"

print foo.__name__
#输出: foo
如何使用装饰器
一个大问题: 我能用装饰器做什么?

(装饰器)看上去很酷很强大, 但是用一个实际例子来说明可能会更好. 装饰器的用法很多. 经典的用法是, 拓展一个外部库函数(你无法修改它)的功能, 或者用于调试(因为它是临时的, 你并不想进行修改).

你可以用装饰器不重复地拓展多个函数, 像这样:

def benchmark(func):
    """
    打印函数被执行的时间的装饰器
    """
    import time
    def wrapper(*args, **kwargs):
        t = time.clock()
        res = func(*args, **kwargs)
        print func.__name__, time.clock()-t
        return res
    return wrapper

def logging(func):
    """
    记录脚本活动的装饰器
    (事实上, 它只是进行了打印, 但可以进行日志打印)
    """
    def wrapper(*args, **kwargs):
        res = func(*args, **kwargs)
        print func.__name__, args, kwargs
        return res
    return wrapper

def counter(func):
    """
    统计并打印函数被执行次数的装饰器
    """
    def wrapper(*args, **kwargs):
        wrapper.count = wrapper.count + 1
        res = func(*args, **kwargs)
        print "{0} has been used: {1}x".format(func.__name__, wrapper.count)
        return res
    wrapper.count = 0
    return wrapper

@counter
@benchmark
@logging
def reverse_string(string):
    return str(reversed(string))

print reverse_string("Able was I ere I saw Elba")
print reverse_string("A man, a plan, a canoe, pasta, heros, rajahs, a coloratura, maps, snipe, percale, macaroni, a gag, a banana bag, a tan, a tag, a banana bag again (or a camel), a crepe, pins, Spam, a rut, a Rolo, cash, a jar, sore hats, a peon, a canal: Panama!")

#输出:
#reverse_string ('Able was I ere I saw Elba',) {}
#wrapper 0.0
#wrapper has been used: 1x
#ablE was I ere I saw elbA
#reverse_string ('A man, a plan, a canoe, pasta, heros, rajahs, a coloratura, maps, snipe, percale, macaroni, a gag, a banana bag, a tan, a tag, a banana bag again (or a camel), a crepe, pins, Spam, a rut, a Rolo, cash, a jar, sore hats, a peon, a canal: Panama!',) {}
#wrapper 0.0
#wrapper has been used: 2x
#!amanaP :lanac a ,noep a ,stah eros ,raj a ,hsac ,oloR a ,tur a ,mapS ,snip ,eperc a ,)lemac a ro( niaga gab ananab a ,gat a ,nat a ,gab ananab a ,gag a ,inoracam ,elacrep ,epins ,spam ,arutaroloc a ,shajar ,soreh ,atsap ,eonac a ,nalp a ,nam A
当然, 装饰器的好处是, 对于几乎所有东西, 在不重写的情况, 马上可用. 我说过, 不重复(D.R.Y, Don’t Repeat Yourself):

@counter
@benchmark
@logging
def get_random_futurama_quote():
    from urllib import urlopen
    result = urlopen("http://subfusion.net/cgi-bin/quote.pl?quote=futurama").read()
    try:
        value = result.split("<br><b><hr><br>")[1].split("<br><br><hr>")[0]
        return value.strip()
    except:
        return "No, I'm ... doesn't!"

print get_random_futurama_quote()
print get_random_futurama_quote()

#输出:
#get_random_futurama_quote () {}
#wrapper 0.02
#wrapper has been used: 1x
#The laws of science be a harsh mistress.
#get_random_futurama_quote () {}
#wrapper 0.01
#wrapper has been used: 2x
#Curse you, merciful Poseidon!
Python本身提供了多个装饰器: property, staticmethod等等.

Django用装饰器管理缓存(caching)和视图权限(view permissions).
内联异步函数调用的变向实现.

时间: 2024-10-29 17:30:39

Python 装饰器的学习重点的相关文章

Python装饰器模式学习总结

装饰器模式,重点在于装饰.装饰的核心仍旧是被装饰对象. 类比于Java编程的时候的包装模式,是同样的道理.虽然概念上稍有不同但是原理上还是比较相近的.下面我就来谈一谈我对Python的装饰器的学习的一点心得吧. 关于作用域 Python作用域 体现在LEGB中: L:local 函数内部 E: enclosing 函数内部和内置函数之间 G:global 全局性质,有命名空间的限制 B:build-in 内置函数,由python解释器管理 学过编程的人一眼就可以看得出来大致是什么意思,所以这里不

详解Python装饰器由浅入深_python

装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们以装饰函数为例子介绍其用法.要理解在Python中装饰器的原理,需要一步一步来.本文尽量描述得浅显易懂,从最基础的内容讲起. (注:以下使用Python3.5.1环境) 一.Python的函数相关基础 第一,必须强调的是python是从上往下顺序执行的,而且碰到函数的定义代码块是不会立即执行它的,只

对Python 装饰器的理解心得

最近写一个py脚本来整理电脑中的文档,其中需要检校输入的字符,为了不使代码冗长,想到使用装 饰器. 上网搜索有关python的装饰器学习文档,主要看的是AstralWind的一篇博文,以及Limodou的一篇文章 .作为初学者,这两篇文章对新手有很大的帮助,但仍然有些不易理解的地方.因此在此以一个初学者的 认知记录一下python的装饰器的学习心得. 1. 什么是装饰器? 顾名思义,装饰器就是在方法上方标一个带有@符号的方法名,以此来对被装饰的方法进行点缀改造. 当你明白什么是装饰器之后,自然会

对于Python装饰器使用的一些建议

  这篇文章主要介绍了对于Python装饰器使用的一些建议,装饰器是Python学习进阶中的重要知识,需要的朋友可以参考下 装饰器基本概念 大家都知道装饰器是一个很著名的设计模式,经常被用于 AOP (面向切面编程)的场景,较为经典的有插入日志,性能测试,事务处理,Web权限校验, Cache等. Python 语言本身提供了装饰器语法(@),典型的装饰器实现如下: ? 1 2 3 @function_wrapper def function(): pass @实际上是 python2.4 才提

九步学会Python装饰器

  本文实例讲述了Python装饰器.分享给大家供大家参考.具体分析如下: 这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 ? 1 2 3 4 5 6 # -*- coding:gbk -*- '''示例1: 最简单的函数,表示调用了两次''' def myfunc(): print("myfunc() called.") myfunc() myfunc() 第二步:使用装饰函数在函数执行前和执行后分别附加额外功能 ?

python-有关Python装饰器疑问?

问题描述 有关Python装饰器疑问? 最近学习了python的装饰器,基本上理解了.但是还是有一个小小问题没有找到答案,在这请教一下各位同行.(也许我有知识点遗漏,在这查漏补缺) 假设对一函数进行了装饰之后,在调用该函数的时候就是装饰后的结果,那么我该如何恢复原来函数功能呢. 比如我的程序里有其他部分代码在调用该函数时需要得到装饰后的功能,然而另外一部分代码只需要该函数本来功能.比如 #func函数已经被装饰过,然后执行以下代码 a=func() //假设这里实际需要装饰后的功能 b=func

Python装饰器详解

装饰器(decorator)是一种高级Python语法.装饰器可以对一个函数.方法或者类进行加工.在Python中,我们有多种方法对函数和类进行加工,比如在Python闭包中,我们见到函数对象作为某一个函数的返回结果.相对于其它方式,装饰器语法简单,代码可读性高.因此,装饰器在Python项目中有广泛的应用. 装饰器最早在Python 2.5中出现,它最初被用于加工函数和方法这样的可调用对象(callable object,这样的对象定义有__call__方法).在Python 2.6以及之后的

Python装饰器使用实例:验证参数合法性

          这篇文章主要介绍了Python装饰器使用实例:验证参数合法性,本文直接给出代码实例,代码中包含详细注释,需要的朋友可以参考下               python是不带静态检查的动态语言,有时候需要在调用函数时保证参数合法.检查参数合法性是一个显著的切面场景,各个函数都可能有这个需求.但另一方面,参数合法性是不是应该由调用方来保证比较好也是一个需要结合实际才能回答的问题,总之双方约定好,不要都不检查或者都检查就可以了.下面这个模块用于在函数上使用装饰器进行参数的合法性验证

对Python装饰器的个人理解方法

0.说明                   在自己好好总结并对Python装饰器的执行过程进行分解之前,对于装饰器虽然理解它的基本工作方式,但对于存在复杂参数的装饰器(装饰器和函数本身都有参数),总是会感到很模糊,即使这会弄懂了,下一次也很快忘记,其实本质上还是没有多花时间去搞懂其中的细节问题.         虽然网络上已经有很多这样的文章,但显然都是别人的思想,因此自己总是记不牢,所以花点时间自己好好整理一下.         最近在对<Python核心编程>做总结,收获了不少,下面分享