装饰器中的命名关键字?
在查看其他人的代码之前,我一直在深入尝试编写自己版本的记忆装饰器。老实说,这更像是一种有趣的练习。然而,在玩弄的过程中,我发现我无法用装饰器做我想做的事情。
def addValue( func, val ):
def add( x ):
return func( x ) + val
return add
@addValue( val=4 )
def computeSomething( x ):
#function gets defined
如果我想这样做,我必须这样做:
def addTwo( func ):
return addValue( func, 2 )
@addTwo
def computeSomething( x ):
#function gets defined
为什么我不能以这种方式将关键字参数与装饰器一起使用?我做错了什么,你能告诉我应该怎么做吗?
I've been playing around in depth with attempting to write my own version of a memoizing decorator before I go looking at other people's code. It's more of an exercise in fun, honestly. However, in the course of playing around I've found I can't do something I want with decorators.
def addValue( func, val ):
def add( x ):
return func( x ) + val
return add
@addValue( val=4 )
def computeSomething( x ):
#function gets defined
If I want to do that I have to do this:
def addTwo( func ):
return addValue( func, 2 )
@addTwo
def computeSomething( x ):
#function gets defined
Why can't I use keyword arguments with decorators in this manner? What am I doing wrong and can you show me how I should be doing it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您需要定义一个返回装饰器的函数:
当您编写
@addTwo
时,addTwo
的值直接用作装饰器。但是,当您编写@addValue(4)
时,首先通过调用 addValue 函数来计算addValue(4)
。然后将结果用作装饰器。You need to define a function that returns a decorator:
When you write
@addTwo
, the value ofaddTwo
is directly used as a decorator. However, when you write@addValue(4)
, firstaddValue(4)
is evaluated by calling the addValue function. Then the result is used as a decorator.您想要部分应用函数
addValue
- 给出val
参数,但不给出func
。通常有两种方法可以做到这一点:第一种称为“柯里化”(currying),并在 interjay 的回答中使用:
f(a,b) -> 代替具有两个参数的函数。 res
,您编写第一个参数的函数,该函数返回另一个采用第二个参数的函数g(a) -> (h(b) -> res)
另一种方式是
functools.partial
对象。它使用对函数的检查来确定函数需要运行哪些参数(在您的情况下为 func 和 val )。您可以在创建部分时添加额外的参数,一旦调用该部分,它就会使用给定的所有额外参数。对于这个部分应用问题,分部通常是一种更简单的解决方案,尤其是在有多个参数的情况下。
You want to partially apply the function
addValue
- give theval
argument, but notfunc
. There are generally two ways to do this:The first one is called currying and used in interjay's answer: instead of a function with two arguments,
f(a,b) -> res
, you write a function of the first arg that returns another function that takes the 2nd argg(a) -> (h(b) -> res)
The other way is a
functools.partial
object. It uses inspection on the function to figure out what arguments a function needs to run (func and val in your case ). You can add extra arguments when creating a partial and once you call the partial, it uses all the extra arguments given.Partials are usually a much simpler solution for this partial application problem, especially with more than one argument.
具有任何种参数的装饰器——命名/关键字参数、未命名/位置参数或每种参数中的一些参数——本质上是你在
@name上调用的参数
行而不仅仅是在那里提及——需要双层嵌套(而您刚刚提到的装饰器只有单层嵌套)。如果您想在@
行中调用它们,那么即使对于无参数的装饰器也是如此 - 这是最简单的、不执行任何操作的双嵌套装饰器:请
注意括号(在本例中为空,因为不需要也不想要任何参数):它们意味着您正在调用
double
,它返回middling< /code>,它装饰
whatever
。一旦您了解了“调用”和“只是提及”之间的区别,添加(例如可选)命名参数并不难:
可以使用 as:
或 as:
或等效为:
Decorators with any kinds of arguments -- named/keyword ones, unnamed/positional ones, or some of each -- essentially, ones you call on the
@name
line rather than just mention there -- need a double level of nesting (while the decorators you just mention have a single level of nesting). That goes even for argument-less ones if you want to call them in the@
line -- here's the simplest, do-nothing, double-nested decorator:You'd use this as
note the parentheses (empty in this case since there are no arguments needed nor wanted): they mean you're calling
double
, which returnsmiddling
, which decorateswhatever
.Once you've seen the difference between "calling" and "just mentioning", adding (e.g. optional) named args is not hard:
usable either as:
or as:
or equivalently as: