我是Python的新手,并且被Boto项目中的这段代码所困扰:
class SubdomainCallingFormat(_CallingFormat):
@assert_case_insensitive
def get_bucket_server(self, server, bucket):
return '%s.%s' % (bucket, server)
def assert_case_insensitive(f):
def wrapper(*args, **kwargs):
if len(args) == 3 and not (args[2].islower() or args[2].isalnum()):
raise BotoClientError("Bucket names cannot contain upper-case " \
"characters when using either the sub-domain or virtual " \
"hosting calling format.")
return f(*args, **kwargs)
return wrapper
试图了解这里发生了什么。
@assert_case_sensitive
中的'@'符号是什么?*args, **kwargs
是什么意思?f
'代表什么?谢谢!
答案 0 :(得分:6)
@符号用于表示decorator的应用。
这些星号表示参数为excess positional/keyword arguments put into a list/dictionary。
“f”表示作为第一类对象传入装饰器的函数。有人写的时候
@decorate
def whizbang(): pass
它真的等同于
def whizbang(): pass
whizbang = decorate(whizbang)
本手册更详细,但装饰器基本上是一种用现有代码包围的代码,可以在其前后执行,而无需修改您正在装饰的代码。一切都具有一流功能的魔力。
答案 1 :(得分:4)
@assert_case_sensitive中的'@'符号是什么?
@是装饰器语法,基本上是:
@decor
def func(arg):
pass
相当于:
def func(arg):
pass
func = decor(func)
args * args是什么,** kwargs是什么意思?
* args和** kwargs是参数解包。它类似于C的varargs,因为任何多余的未命名参数都将转到* args元组,而无法识别的命名参数将转到** kwargs dict。
def foo(a, *arg, **kwarg):
print a # prints 1
print arg # prints (2, 3)
print kwarg # prints {'foo': 4}
foo(1, 2, 3, foo=4)
'f'代表什么?
这是python的高级功能。基本上在python中,一切都是包含函数的对象。由于函数是一个对象,因此可以将函数作为参数传递给另一个函数。如果这是C,则类似于传递函数指针。
答案 2 :(得分:4)
在这种特殊情况下,assert_case_sensitive
是一个函数包装函数,也称为decorator。
装饰器接受现有函数并返回不同的函数。通常它返回一个以某种方式调用原始函数的新函数。在这种情况下,assert_case_insensitive
始终返回wrapper
,这是一个在其中定义的函数,其名称仅在assert_case_insensitive
内知道。
当一个函数在另一个函数体中声明时,每次调用外部函数时,封闭函数都会重新创建。这意味着内部函数可以访问它所在函数中的变量。
此技术称为closure,Python对闭包的支持不完整,因为无法修改封闭范围内的变量。但这与这个问题并不十分相关。
assert_case_insensitive
的目标是对它传递的函数的参数强制执行某些条件。它返回一个新函数,强制执行这些条件并调用原始函数。为了使assert_case_insensitive
能够用于包装任何函数,它需要用于具有不同数量的参数的函数,以及具有关键字参数的函数。这是*args
和**kargs
进来的地方。
*something
形式的参数获得任何剩余的非关键字(也称为位置)参数的元组,这些参数不会被先前的位置参数所占据。 **something
形式的参数获取字典中任何剩余的关键字参数,这些参数不会被先前的位置参数解释。 *something
或**something
形式的参数必须在所有其他参数之后出现。
类似的语法用于调用具有不知道的参数列表的函数。形式*(iterable sequence)
的参数变成一系列位置参数,形式**(dictionary)
的参数变成一组关键字参数。
所以wrapper
正在使用这些结构,因此它可以非常适用于任何函数。一般来说装饰器可以用于任何功能,因此在编写时强烈建议这样做。
答案 3 :(得分:1)
@assert_case_sensitive这里是来自维基百科的装饰器的解释:
装饰器是一个Python对象,可以使用单个参数调用,并修改函数或方法。 Python装饰器的灵感部分来自Java注释,并具有类似的语法;装饰器语法是纯粹的语法糖,使用@作为关键字:
@viking_chorus
def menu_item():
print "spam"
相当于
def menu_item():
print "spam"
menu_item = viking_chorus(menu_item)