在对另一个问题的答案的评论中,有人说他们不确定functools.wraps在做什么.所以,我问这个问题,以便在StackOverflow上有一个记录,供将来参考:究竟functools.wraps做了什么?
可能重复:
在python中获取方法参数名称
有没有一种简单的方法可以在python函数中获取参数名称列表?
例如:
def func(a,b,c):
print magic_that_does_what_I_want()
>>> func()
['a','b','c']
Run Code Online (Sandbox Code Playgroud)
谢谢
鉴于Python函数:
def a_method(arg1, arg2):
pass
Run Code Online (Sandbox Code Playgroud)
如何提取参数的数量和名称.即,鉴于我有一个func的引用,我想要返回func.[something]("arg1","arg2").
这种情况的使用场景是我有一个装饰器,我希望使用方法参数的顺序与它们为实际函数出现的顺序相同.也就是说,当我调用aMethod("a","b")时,装饰器看起来会打印出"a,b"吗?
假设我有一个通用函数f.我想以编程方式创建一个与f相同的函数f2,但它具有自定义签名.
更多详情
给定列表l和字典d我希望能够:
即.假设我们有
l=["x", "y"]
d={"opt":None}
def f(*args, **kwargs):
#My code
Run Code Online (Sandbox Code Playgroud)
然后我想要一个带签名的函数:
def f2(x, y, opt=None):
#My code
Run Code Online (Sandbox Code Playgroud)
一个特定的用例
这只是我特定用例的简化版本.我只是以此为例.
我的实际用例(简化)如下.我们有一个通用的启动函数:
def generic_init(self,*args,**kwargs):
"""Function to initiate a generic object"""
for name, arg in zip(self.__init_args__,args):
setattr(self, name, arg)
for name, default in self.__init_kw_args__.items():
if name in kwargs:
setattr(self, name, kwargs[name])
else:
setattr(self, name, default)
Run Code Online (Sandbox Code Playgroud)
我们想在许多类中使用此函数.特别是,我们想要创建一个函数init,其行为类似于generic_init,但在创建时具有由某些类变量定义的签名:
class my_class:
__init_args__=["x", "y"]
__kw_init_args__={"my_opt": None}
__init__=create_initiation_function(my_class, generic_init)
setattr(myclass, "__init__", __init__)
Run Code Online (Sandbox Code Playgroud)
我们希望create_initiation_function创建一个新函数,其签名使用init_args和kw_init_args定义.可以写create_initiation_function吗?
请注意: …
这是我的装饰者:
def check_domain(func):
def wrapper(domain_id, *args, **kwargs):
domain = get_object_or_None(Domain, id=domain_id)
if not domain:
return None
return func(domain_id, *args, **kwargs)
return wrapper
Run Code Online (Sandbox Code Playgroud)
这是一个包裹的功能:
@check_domain
def collect_data(domain_id, from_date, to_date):
do_stuff(...)
Run Code Online (Sandbox Code Playgroud)
如果我这样做,collect_data.__name__我会得到wrapper而不是collect_data
有任何想法吗?
举个例子,
def get_booking(f=None):
print "Calling get_booking Decorator"
def wrapper(request, **kwargs):
booking = _get_booking_from_session(request)
if booking == None:
# we don't have a booking in our session.
return HttpRedirect('/')
else:
return f(request=request, booking=booking, **kwargs)
return wrapper
@get_booking
def do_stuff(request, booking):
# do stuff here
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是,甚至在我调用我正在装饰的函数之前,就会调用@get_booking装饰器.
开始输出:
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
[26/Oct/2008 19:54:04] "GET /onlinebooking/?id=1,2 HTTP/1.1" …Run Code Online (Sandbox Code Playgroud) decorator模块的功能与functools.wraps密切相关.两者之间有什么区别(从Python 3.3/3.4开始)?
我有我的简单装饰器my_decorator装饰my_func.
def my_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
wrapper._decorator_name_ = 'my_decorator'
return wrapper
@my_decorator
def my_func(x):
print('hello %s'%x)
my_func._decorator_name_
'my_decorator'
Run Code Online (Sandbox Code Playgroud)
直到这里工作,但我看不到功能的实际签名.
my_func?
Signature: my_func(*args, **kwargs)
Docstring: <no docstring>
File: ~/<ipython-input-2-e4c91999ef66>
Type: function
Run Code Online (Sandbox Code Playgroud)
如果我用python's装饰我的装饰器decorator.decorator,我可以看到我的函数的签名但我不能拥有我定义的新属性.
import decorator
@decorator.decorator
def my_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
wrapper._decorator_name_ = 'my_decorator'
return wrapper
@my_decorator
def my_func(x):
print('hello %s'%x)
my_func?
Signature: my_func(x)
Docstring: <no docstring>
File: ~/<ipython-input-8-934f46134434>
Type: function
my_func._decorator_name_
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-10-7e3ef4ebfc8b> …Run Code Online (Sandbox Code Playgroud) 有没有办法获得传递给函数的实际参数的数量
def foo(a, optional=42):
if ????
print "1 arg"
else:
print "2 args"
foo(11) # should print 1 arg
foo(22, 42) # should print 2 args
Run Code Online (Sandbox Code Playgroud)
没有改变其签名接受*args?
我有一个带有许多参数和详细帮助信息的函数,例如:
def worker_function(arg1, arg2, arg3):
""" desired help message:
arg1 - blah
arg2 - foo
arg3 - bar
"""
print arg1, arg2, arg3
Run Code Online (Sandbox Code Playgroud)
我也有一个包装函数,做一些会计,然后叫我worker_function,所有参数传递给它的是.
def wrapper_function(**args):
""" this function calls worker_function """
### do something here ...
worker_function(**args)
Run Code Online (Sandbox Code Playgroud)
我希望包装函数的帮助消息(由python内置的help()函数显示)具有来自worker函数的参数列表和帮助消息.
我能得到的最接近的解决方案是:
wrapper_function.__doc__ += "\n\n" + worker_function.__doc__
Run Code Online (Sandbox Code Playgroud)
这导致:
>>? help(wrapper_function)
Help on function wrapper_function in module __main__:
wrapper_function(**args)
this function calls worker function
desired help message:
arg1 - blah
arg2 - foo
arg3 - bar
Run Code Online (Sandbox Code Playgroud)
但是这个描述缺少必要的部分 - 参数列表,即: …
我怎么能很好地写一个装饰师?
特别的问题包括:与其他装饰者的兼容性,保留签名等.
如果可能的话,我想避免依赖于装饰器模块,但如果有足够的优势,那么我会考虑它.
有关
python ×11
decorator ×6
function ×3
django ×2
built-in ×1
functools ×1
ipython ×1
parameters ×1
python-2.7 ×1
python-3.x ×1