所以我是学习装饰的新手,我经历了无数的教程,虽然我理解并且大部分都可以按照所有的例子,我认为最好的学习方法,就是自己实现一个装饰师。所以我将在下面使用这个例子。我意识到装饰器根本不需要这样做,但为了学习,我想添加一个装饰器来过滤字符串,如狗名和品种,并将它们变成小写。任何有正确方向的想法或指示都会受到赞赏。
class Dogs:
totalDogs = 0
dogList=[]
def __init__(self, breed, color, age):
self.breed=breed
self.color=color
self.age=age
Dogs.dogList.append(self.breed)
Dogs.totalDogs += 1
def displayDogs(self):
print "breed: ", self.breed
print "color: ",self.color
print "age: ",self.age
print "list of breeds:", Dogs.dogList
print "total dogs: ", Dogs.totalDogs
def somedecorator(*args):
#now what
terrier=Dogs("TeRrIer", "white", 5)
terrier.displayDogs()
retriever=Dogs("goldenRETRIEVER", "brown", 10)
retriever.displayDogs()
答案 0 :(得分:2)
嗯,为了简化它,我们首先处理函数。假设您有一个函数可以打印有关其参数的信息:
def print_info(breed, name):
print "The doggie %s's breed is %s." % (name, breed)
因此:
>>> print_info("Labrador", "Spike")
The doggie Spike's breed is Labrador.
>>> print_info("Pit Bull", "Spot")
The doggie Spot's breed is Pit Bull.
现在您希望该功能始终小写该品种。所以你应该以理智的方式做到这一点:
def manually_lowered_print_info(breed, name):
print "The doggie %s's breed is %s." % (name, breed.lower())
输出是:
>>> manually_lowered_print_info("Labrador", "Spike")
The doggie Spike's breed is labrador.
但是,让我们说出于某种原因,你经常不得不小写你写的函数的第一个字符串参数,所以你想把它抽象为装饰器。我们希望它看起来像这样并具有相同的输出:
@lower_first_arg
def dec_lowered_print_info(breed, name):
print "The doggie %s's breed is %s." % (name, breed)
这只是语法糖:
def tmp_func(breed, name):
print "The doggie %s's breed is %s." % (name, breed)
dec_lowered_print_info = lower_first_arg(tmp_func)
因此,我们希望lower_first_arg
返回转换后的print_info
函数。让我们首先制作一个专门为print_info
函数量身定制的函数。
def lower_first_arg(print_info_func_arg):
def inner_print_info(breed, name):
return print_info_func_arg(breed.lower(), name)
return inner_print_info
有用吗?我们来看看:
>>> transformed_print_info = lower_first_arg(print_info)
>>> print_info("Pit Bull", "Spot")
The doggie Spot's breed is Pit Bull.
>>> transformed_print_info("Pit Bull", "Spot")
The doggie Spot's breed is pit bull.
大!请注意,我们将print_info
作为参数传递给lower_first_arg
函数,它由局部变量print_info_func_arg
引用。
如果我们使用装饰器语法,它的工作原理相同:
@lower_first_arg
def dec_lowered_print_info(breed, name):
print "The doggie %s's breed is %s." % (name, breed)
优秀:
>>> dec_lowered_print_info("Pit Bull", "Spot")
The doggie Spot's breed is pit bull.
很酷,所以就是这样,真的。现在为了使装饰器更通用,让我们首先概括名称:
def generic_lower_first_arg(f):
def wrapped(arg1, arg2):
return f(arg1.lower(), arg2)
return wrapped
现在问题是这个装饰器只适用于2个args的函数。理想情况下,我们希望它能够处理1 arg或更多的任何函数,例如:
@generic_lower_first_arg
def failed_whatnow(first, last, middle):
print "%s %s %s" % (first, middle, last)
现在,该代码将运行,但如果我们尝试调用它,我们会收到错误:
>>> failed_whatnow("Bob", "Jones", "The Killer")
Traceback (most recent call last):
File "<pyshell#26>", line 1, in <module>
failed_whatnow("Bob", "Jones", "The Killer")
TypeError: wrapped() takes exactly 2 arguments (3 given)
发生了什么事?好吧,装饰器使用failed_whatnow
并返回它定义的函数wrapped
,但wrapped
函数只接受两个参数!这里的修复是使用varargs语法。传递任何可能赋予包装函数的关键字参数通常也是一个好主意。
def proper_lower_first_arg(f):
def wrapped(arg1, *args, **kwargs):
return f(arg1.lower(), *args, **kwargs)
return wrapped
现在它适用于各种功能:
@proper_lower_first_arg
def proper_whatnow(first, last, middle):
print "%s %s %s" % (first, middle, last)
@proper_lower_first_arg
def multiplyit(mm, n=3):
return mm * n
证明:
>>> proper_whatnow("Bob", "Jones", "The Killer")
bob The Killer Jones
>>> multiplyit("HaHa.Fool!")
'haha.fool!haha.fool!haha.fool!'
>>> multiplyit("HaHa.Fool!", n=5)
'haha.fool!haha.fool!haha.fool!haha.fool!haha.fool!'
答案 1 :(得分:2)
装饰器实际上只是一个函数,它将函数作为参数并返回另一个函数。
def lower_output(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs).lower()
return wrapper
class Dogs(object):
totalDogs = 0
dogList=[]
def __init__(self, breed, color, age):
self.breed=breed
self.color=color
self.age=age
Dogs.dogList.append(self.breed)
Dogs.totalDogs += 1
@lower_output
def get_breed(self):
return self.breed
>>> terrier=Dogs("TeRrIer", "white", 5)
>>> terrier.get_breed()
terrier
答案 2 :(得分:0)
装饰器通常用于修改输入参数或函数/方法的返回值。
方法Dogs.displayDogs
不会返回任何数据(None
除外),因此您想要将字符串设为小写是没有意义的。哪个字符串?您只需打印值。所以你会这样做:
class Dogs:
totalDogs = 0
dogList=[]
def __init__(self, breed, color, age):
self.breed=breed
self.color=color
self.age=age
Dogs.dogList.append(self.breed)
Dogs.totalDogs += 1
def displayDogs(self):
print "breed: ", self.breed.lower()
print "color: ",self.color.lower()
...
否则你应该重构你的代码:
def make_lower(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
result = [value.lower() for value in result]
return result
return wrapper
class Dogs:
totalDogs = 0
dogList=[]
def __init__(self, breed, color, age):
self.breed=breed
self.color=color
self.age=age
Dogs.dogList.append(self.breed)
Dogs.totalDogs += 1
@make_lower
def getDogs(self):
return [
"breed: %s" % self.breed,
"color: %s" % self.color.lower(),
...
]
你做的
terrier = Dogs("TeRrIer", "white", 5)
print terrier.getDogs()