装饰器作为通用的预绑定钩子 [英] decorators as generalized pre-binding hooks

查看:54
本文介绍了装饰器作为通用的预绑定钩子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

;-)

我们有


@deco

def foo():传递

作为糖(除非装饰者中有未被捕获的例外)

def foo():传递

foo = deco(foo)


类名的绑定类似,类装饰器看起来很自然,即


@cdeco

class Foo :传递

for

class Foo:传递

Foo = cdeco(Foo)


什么正在发生的是我们正在截取某个对象的绑定

并让装饰器在绑定发生之前对该对象做了一些事情。


那么为什么不呢? />

@deco

foo = lambda:传递

相当于

foo = deco(lambda:pass )


从那里,

@deco

< left-hand-side> =<右手边>

相当于

< left-hand-side> = deco(< right-hand-side>)


例如,

@range_check(1,5)

a = 42

for

a = range_check(1,5)(42)




@ default_value(42)

b = ce [''f''](''g'')

for

b = default_value(42) (ce [''f''](''g''))


Hm,binding-intercept-decoration也可以用来捕捉异常,

并将它们传递给装饰者,例如,上面可能是糖用于


尝试:

b = default_value(42)(ce [''f ''](''g''))

除了Exception,e:

b = default_value(__ exception __ = e)#so decorator可以检查

#并返回一个值或者只是通过加注重新加注[注1]


这对于普通的旧函数装饰器也是有用的,如果你想装饰器

来定义替换某些东西的政策,例如:默认参数评估

抛出和异常。因此


@deco

def foo(x = a / b):传递#例如,如果b == 0怎么办?

as

试试:

def foo(x = a / b):传递#例如,如果b == 0怎么办?

foo = deco(foo)

除了异常,e:

如果不是deco.func_code.co_flags& 0x08:引发#avoid神秘意外关键字TypeError

foo = deco(__ exception __ = e)


[注1:]

有趣的提升似乎不必在同一帧中或者向下堆叠,所以上面调用的装饰者

可以重新加注:

def deco(** kw):
... print kw

... raise

... try:1/0



...除了异常,e:deco(__ exception __ = e)

...

{''__ exception__'':< exceptions.ZeroDivisionError实例位于0x02EF190C>}

回溯(最近一次调用最后一次):

文件"< stdin>",第2行,在?

文件"< stdin>",第1行,在?

ZeroDivisionError:整数除法或模数为零

正交 - 沉思;-)


问候,

Bengt里希特

解决方案

Bengt Richter写道:

;-)
我们有


我们有吗?


到目前为止看起来并不是很多感兴趣的人。


但我会咬人。 ;-)

< clip intro>

为什么不呢

@deco
foo = lambda:pass
相当于
foo = deco(lambda:pass)

从那里,
@deco
<左手边> =<右手边>
相当于
< left-hand-side> = deco(< right-hand-side>)

例如,
@range_check(1,5)
a = 42

= range_check(1,5)(42)

@default_value(42)
b = ce [''f''](''g'')
for
b = default_value(42)(ce [''f''](''g''))


到目前为止它们相当。所以在等效内联函数上没有任何优势

。但我想我知道你是什么了b $ b。当函数定义为
时,必须使用装饰器。此选项试图使它们更具动态性,以便它们可以在需要的时间和地点使用。


如果你也可以选择它?


if keep_log:

@log_of_interesting_values

b = get_value(c,d):


或者......


@@ keeplog log_of_interesting_values#如果keeplog装饰。

b = get_value(c,d)

只是一个想法。

Hm,绑定拦截装饰也可以用来捕捉异常,
并将它们传递给装饰者,例如,上面可能是糖for

尝试:
b = default_value(42)(ce [''f''](''g''))
除了例外,e:
b = default_value(__ exception __ = e)#so decorator可以检查
#并返回一个值或者只是通过加注重新加注[注1]


我''我不确定我是否遵循这一个......嗯,我做了一点。看起来好像它可能会继续使用with语句,但只适用于单个

表达式而不是块或套件。


这对于普通的旧函数装饰器也许有用,如果你想要装饰器
来定义替换某些东西的策略,例如默认参数评估
抛出和异常。因此

@deco
def foo(x = a / b):传递#例如,如果b == 0怎么样?
作为
尝试:
def foo(x = a / b):传递#例如,如果b == 0怎么办?
foo = deco(foo)
除了Exception,e:
如果不是deco.func_code .co_flags& 0x08:引发#avoid神秘意外关键字TypeError
foo = deco(__ exception __ = e)


这个现在不能用吗?

[注1:]
有趣的是,提升似乎不必在同一帧或下层,所以如上所述的装饰者可以重新加注:

>>> def deco(** kw):... print kw
... raise
...>>>尝试:1/0

...除了Exception,e:deco(__ exception __ = e)
...
{''__ exception__'':< exceptions.ZeroDivisionError instance at 0x02EF190C>回溯(最近一次调用最后一次):
文件"< stdin>",第2行,在?
文件"< stdin>",第1行,in ?ZeroQivision错误:整数除法或模数为零




有趣的。


说到装饰器,和现在有了陈述,我不能帮助

但是觉得有某种潜在的概念可以更好地运作
。它与以动态方式推广流量控制有关。相对于相关块,



一个想法是能够使用占位符表达式列表

告诉声明何时执行以下代码块。


我会在这里使用''do''...因为它目前尚未使用,所以使用@@@作为

占位符。


(这些都没有想到那么远,我知道...只是试图

显示可能的方向。)

do f = open(filename); @@@; f.close():#do the block where @@@ is。

for line in f:

print line,

print

和类似于with的备用版本声明。


尝试f = open(filename); @@@;最后f.close():

换行如果f:

打印行,

打印


也许这个例外可以在试用线完成之后保留吗?

占位符的想法也可能对装饰有用。但是我不知道
不知道函数名和arguemtns会如何传递给它。


do deco(@@@):

def foo():

通过


或者可能需要...


做f = @@@,deco(f):

def foo()

通过


我说,它仍然需要一些思考.. ;-)

也许离开冒号会使用以下行,而不是

缩进按照你的例子?


做装饰(@@@)

b = 42


我觉得这样做并不是很好。可能有几个

不同类型的占位符符号可能会改变行为?


做装饰(


< blockquote>)#


截取名称绑定操作?

b = 42

好​​吧,它可能需要一点点(或者改变。但是用

控制带有占位符符号流的想法可能是一种推广

一些已经浮动到一个工具中的概念的方法。


我喜欢这个占位符因为我认为他们使代码更加明确而且他们更灵活,因为你可以将它们放在你的位置

需要它们。


正交 - 沉思;-)


Orthogonal是一种不寻常的计算机语言,程序在其中流动

可以侧身。实际上可以进入你想要的任何方向。

http://www.muppetlabs.com/~breadbox/orth/

;-)


干杯,

Ron


问候,
Bengt Richter



;-)
We have

@deco
def foo(): pass
as sugar (unless there''s an uncaught exception in the decorator) for
def foo(): pass
foo = deco(foo)

The binding of a class name is similar, and class decorators would seem natural, i.e.,

@cdeco
class Foo: pass
for
class Foo: pass
Foo = cdeco(Foo)

What is happening is we are intercepting the binding of some object
and letting the decorator do something to the object before the binding occurs.

So why not

@deco
foo = lambda:pass
equivalent to
foo = deco(lambda:pass)

and from there,
@deco
<left-hand-side> = <right-hand-side>
being equivalent to
<left-hand-side> = deco(<right-hand-side>)

e.g.,
@range_check(1,5)
a = 42
for
a = range_check(1,5)(42)

or
@default_value(42)
b = c.e[''f''](''g'')
for
b = default_value(42)(c.e[''f''](''g''))

Hm, binding-intercept-decoration could be sugar for catching exceptions too,
and passing them to the decorator, e.g., the above could be sugar for

try:
b = default_value(42)(c.e[''f''](''g''))
except Exception, e:
b = default_value(__exception__=e) # so decorator can check
# and either return a value or just re-raise with raise [Note 1]

This might be useful for plain old function decorators too, if you wanted the decorator
to define the policy for substituting something if e.g. a default argument evaluation
throws and exception. Thus

@deco
def foo(x=a/b): pass # e.g., what if b==0?
as
try:
def foo(x=a/b): pass # e.g., what if b==0?
foo = deco(foo)
except Exception, e:
if not deco.func_code.co_flags&0x08: raise #avoid mysterious unexpected keyword TypeError
foo = deco(__exception__=e)

[Note 1:]
Interestingly raise doesn''t seem to have to be in the same frame or down-stack, so a decorator
called as above could re-raise:

def deco(**kw): ... print kw
... raise
... try: 1/0


... except Exception, e: deco(__exception__=e)
...
{''__exception__'': <exceptions.ZeroDivisionError instance at 0x02EF190C>}
Traceback (most recent call last):
File "<stdin>", line 2, in ?
File "<stdin>", line 1, in ?
ZeroDivisionError: integer division or modulo by zero
orthogonal-musing-ly ;-)

Regards,
Bengt Richter

解决方案

Bengt Richter wrote:

;-)
We have
Have we?

Looks like not a lot of interested takers so far.

But I''ll bite. ;-)
<clip intro>
So why not

@deco
foo = lambda:pass
equivalent to
foo = deco(lambda:pass)

and from there,
@deco
<left-hand-side> = <right-hand-side>
being equivalent to
<left-hand-side> = deco(<right-hand-side>)

e.g.,
@range_check(1,5)
a = 42
for
a = range_check(1,5)(42)

or
@default_value(42)
b = c.e[''f''](''g'')
for
b = default_value(42)(c.e[''f''](''g''))
So far they are fairly equivalent. So there''s not really any advantage
over the equivalent inline function. But I think I see what you are
going towards. Decorators currently must be used when a function is
defined. This option attempts to makes them more dynamic so that they
can be used where and when they are needed.

How about if you make it optional too?

if keep_log:
@log_of_interesting_values
b = get_value(c,d):

Or...

@@keeplog log_of_interesting_values # if keeplog decorate.
b = get_value(c,d)

Just a thought.
Hm, binding-intercept-decoration could be sugar for catching exceptions too,
and passing them to the decorator, e.g., the above could be sugar for

try:
b = default_value(42)(c.e[''f''](''g''))
except Exception, e:
b = default_value(__exception__=e) # so decorator can check
# and either return a value or just re-raise with raise [Note 1]
I''m not sure I follow this one.. Well I do a little. Looks like it might
be going the direction of with statements, but only applied to a single
expression instead of a block or suite.

This might be useful for plain old function decorators too, if you wanted the decorator
to define the policy for substituting something if e.g. a default argument evaluation
throws and exception. Thus

@deco
def foo(x=a/b): pass # e.g., what if b==0?
as
try:
def foo(x=a/b): pass # e.g., what if b==0?
foo = deco(foo)
except Exception, e:
if not deco.func_code.co_flags&0x08: raise #avoid mysterious unexpected keyword TypeError
foo = deco(__exception__=e)
Wouldn''t this one work now?
[Note 1:]
Interestingly raise doesn''t seem to have to be in the same frame or down-stack, so a decorator
called as above could re-raise:

>>> def deco(**kw): ... print kw
... raise
... >>> try: 1/0

... except Exception, e: deco(__exception__=e)
...
{''__exception__'': <exceptions.ZeroDivisionError instance at 0x02EF190C>}
Traceback (most recent call last):
File "<stdin>", line 2, in ?
File "<stdin>", line 1, in ?
ZeroDivisionError: integer division or modulo by zero



Interestin.

When it comes to decorators, and now the with statements, I can''t help
but feel that there''s some sort of underlying concept that would work
better. It has to do with generalizing flow control in a dynamic way
relative to an associated block.

One thought is to be able to use a place holder in an expression list to
tell a statement when to do the following block of code.

I''ll use ''do'' here... since it''s currently unused and use @@@ as the
place holder.

(These are *NOT* thought out that far yet, I know... just trying to
show a direction that might be possible.)
do f=open(filename); @@@; f.close(): # do the block where @@@ is.
for line in f:
print line,
print
And an alternate version similar to a "with" statement.

try f=open(filename); @@@; finally f.close():
for line if f:
print line,
print

Maybe the exception could be held until after the try line is complete?
The place holder idea might be useful for decorating as well. But I''m
not sure how the function name and arguemtns would get passed to it.

do deco(@@@):
def foo():
pass

or maybe it would need to be...

do f=@@@, deco(f):
def foo()
pass

As I said, it still needs some thinking.. ;-)
Maybe leaving off the colon would use the following line without
indenting as per your example?

do deco(@@@)
b = 42

It doesn''t quite work this way I think. Possibly having a couple of
different types of place holder symbols which alter the behavior might work?

do deco(


) #


intercept name binding operation?
b = 42
Well, it may need to be a bit (or a lot) of changing. But the idea of
controlling flow with a place holder symbol might be a way to generalize
some of the concepts that have been floating around into one tool.

I like the place holders because I think they make the code much more
explicit and they are more flexible because you can put them where you
need them.

orthogonal-musing-ly ;-)
"Orthogonal is an unusual computer language in which your program flow
can go sideways. In actuality in can go in just about any direction you
could want."

http://www.muppetlabs.com/~breadbox/orth/
;-)

Cheers,
Ron

Regards,
Bengt Richter



这篇关于装饰器作为通用的预绑定钩子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆