python装饰方法,【译】Python装饰方法漫谈(二)

讲在开始

这是针对以下内容的第二部分翻译

基础部分在这里:

原答案代码在2.7版本下可以全部运行成功,我将其中的代码用3.5版本重写,并改正了一些没有遵循PEP8规范的代码,以便自己学习理解的更深入一些

揭秘

在之前的例子中,我们直接使用的Python的装饰器语法:

@my_shiny_new_decorator

def another_stand_alone_function():

print("Leave me alone")

another_stand_alone_function()

# 输出 :

# 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中的装饰器是decorator design pattern的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~

#

更Pythonic的用法:

@bread

@ingredients

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

print(food)

sandwich()

设置装饰器的顺序不能随意设定,因为

@ingredients

@bread

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

print(food)

sandwich()

#输出 :

##tomatoes#

#''''''\>

# --ham--

#

# ~salad~

和上一个例子的运行结果是不同的。

进阶

仅仅满足于现状是不够的,如果你希望学到更深层更Pythonic的用法,请继续读下去。

向装饰器函数中传入参数

# 这没什么神奇的,你只需要让负责“包装”的函数来传递参数就可以了

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

@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

def another_print_full_name(first_name, last_name):

print("My name is", first_name, last_name)

# 直白版

a_decorator_passing_arguments((another_print_full_name("Jim", "Raynor")))

# 输出 :

# My name is Jim Raynor

在Python中一个有趣的事情是,无论是函数还是方法(指类中的方法)其实都是一样的。唯一的区别是方法的第一个参数是对当前对象的引用(即约定俗成的self)

因此,既然我们可以编写装饰函数,同样我们也可以为方法编写装饰器,只是这次我们要考虑到self的存在

def method_friendly_decorator(method_to_decorate):

def wrapper(self, lie):

lie -= 3 # very friendly, decrease age even more :-)

return method_to_decorate(self, lie)

return wrapper

class Lucy(object):

def __init__(self):

self.age = 32

@method_friendly_decorator

def say_age(self, lie):

print("I am %s, what did you think?" % (self.age + lie))

l = Lucy()

l.say_age(-3)

# 输出 : I am 26, what did you think?

Kulbear:插一句,从注释和例子中感受一下老外的幽默感?反正我在国外待了很久仍然觉得这个有的时候会很冷...

Kulbear:在下一段开始之前,如果你不明白什么是args和什么是kwargs,可以参考这里

如果你希望你的装饰器(decorator)可以更通用一些,比如你不希望受到参数数量的制约,那么只需要使用*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)

# 现在你将这些参数传入

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 is cool, no argument here.

@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!'}

# Do Bill, Linus and Steve like platypus? Indeed!

class Mary(object):

def __init__(self):

self.age = 31

@a_decorator_passing_arbitrary_arguments

def say_age(self, lie=-3): # You can now add a default value

print("I am %s, what did you think ?" % (self.age + lie))

m = Mary()

m.say_age()

# 输出 :

# Do I have args?:

# (<__main__.mary object at>,)

# {}

# I am 28, what did you think?

后记

在这里,再次推荐一个Python进阶的读物,感谢我看了半天也不会读名字的作者 Muhammad Yasoob Ullah Khalid

后面的部分会继续翻译,敬请期待

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值