前PEP:简单的Thunk [英] pre-PEP: Simple Thunks

查看:71
本文介绍了前PEP:简单的Thunk的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是针对thunk的PEP的初稿。请让我知道你想要的是什么。如果有积极的回应,我会创建一个真正的PEP。


我做了一个补丁,实现了这里描述的thunk。可以在以下网址获得


http:/ /staff.washington.edu/sabbey/py_do


在参考资料中可以找到有关thunk的好背景信息。 [1]。


简单的Thunk?

-------------


就这个PEP而言,Thunks是匿名函数,它们将b / b混合到他们的环境中。它们的使用方式类似于Ruby或Smalltalk中的代码

块。 thunk的一个特定用途是作为一种方式来获取/ b $ b抽象获取/释放代码。另一个用途是作为

发电机的补充。


一组例子

========= ========


Thunk语句包含一个新关键字''do'',如下例所示。

thunk的主体是''do''语句中的套件;它传递给

函数出现在''do''旁边。 thunk作为第一个

参数插入到函数中,让人联想到''self''插入方法的第一个参数

的方式。


def f(thunk):

before()

thunk()

after()


做f():

stuff()


上面的代码效果如下:


之前()

stuff()

之后()


其他参数'' f''被放置在thunk之后:


def f(thunk,a,b):

#a == 27,b == 28

之前()

thunk()

之后()


do f(27,28 ):

stuff()


Thunk也可以接受参数:


def f(thunk):

thunk(6,7)

做x,y in f():

#x == 6,y = = 7

东西(x,y)


可以捕获返回值


def f(thunk ):

thunk()

返回8


做t = f():

#t尚未绑定

stuff()


打印t

==> 8

thunk融入他们的环境


def f(thunk):

thunk(6,7)


a = 20

做x,y in f():

a = 54

打印a,x,y


==> 54,6,7


Thunk可以返回值。因为使用''return''会让它不清楚

是否是thunk或周围的函数返回,应该使用

不同的关键字。通过类比''for''和''while''循环,

''continue''关键字用于此目的:


def f(thunk):

之前()

t = thunk()

#t == 11

之后()


做f():

继续11


在thunk中引发的异常通过thunk在回到定义thunk的帧之前,'来电者'的框架




def catch_everything(thunk):

尝试:

thunk()

除外:

传递#SomeException被抓到这里


尝试:

do catch_everything():

提高SomeException

除了:

传递#SomeException doesn因为它已被抓住而被抓到这里因为它已经被抓住了


因为thunk混合到他们的环境中,所以在
$ b之后无法使用thunk $ b周围的''do''声明已经完成:


thunk_saver =无

def f(thunk):

全局thunk_saver

thunk_saver = thunk


做f():

通过


thunk_saver()#exception,thunk已过期


''break''和'return''应该不允许在thunk中使用。人们可以使用例外情况来模拟这些,但是如果出现非特殊情况则会出现例外情况,这将是令人惊讶的。

必须在调用thunk的所有代码中使用try / finally块

才能处理正常情况。例如,使用代码如


def f(thunk):

thunk()

prevent_core_meltdown()


,代码类似


do f():

p = 1

返回p


会产生与使用它不同的效果


do f():

返回1


这种行为可能是导致错误的原因,因为这两个例子乍一看似乎是相同的。


thunk评估在与定义的函数相同的框架中。

定义。这个框架是可以访问的:


def f(thunk):

frame = thunk.tk_frame


do f ():

通过


动机

==========

Thunk可用于解决PEP 310 [2]

和PEP 288 [3]解决的大部分问题。


PEP 310处理获取/释放代码的抽象。当需要在使用资源之前获取资源并将其释放后,需要这样的代码是
。这通常需要样板,很容易出错,并且没有视觉指示代码的前后部分

是相关的。 Thunk通过允许将获取/释放

代码写入一个可重复使用的函数来解决这些问题。


def acquire_release(thunk):

f =获取()

尝试:

thunk(f)

终于:

f.release()


在buy_release()中执行:

print t


更一般地说,只要重复需要

相同的代码出现在其他代码之前和之后,就可以使用thunk。例如,


执行WaitCursor():

compute_for_a_long_time()


更有条理,更易于阅读并且比代码更容易发生错误


DoWaitCursor(1)

compute_for_a_long_time()

DoWaitCursor(-1)


PEP 288试图克服发电机的一些限制。一个

的限制是''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''声明。


def get_items():

f = acquire()

试试:

for我在f:

收益我#语法错误

终于:

f.release()


for get in get_items():

print i


此代码不被允许,因为执行后可能永远不会返回

''yield''语句,因此无法确保执行

''finally''块。对这种产量的禁止减少了发电机的适用性,作为从需要关闭b $ b b的资源生产物品的一种方式。当然,生成器可以包含在一个关闭资源的类中,但是这是一个复杂的想要避免b
,并且不能确保资源将及时以
的方式发布。 Thunk没有这个限制因为thunk-accepting

函数处于控制状态 - 执行不能突破''do''语句

而不首先通过thunk-accepting函数。


def get_items(thunk):#< - " thunk-accepting function"

f = acquire()

尝试:

for f in f:

thunk(i)#A-OK

终于:

f.release()


我在get_items():

打印我


即使thunks可以在某些方面使用,发电机也不能,但它们b $ b几乎不是发电机的替代品。重要的是,当使用thunk时,一个人没有下一个生成器方法的类似物:


def f():

收益89

收益率91

g = f()

g.next()#== 89

g.next()#== 91


[1]请参阅扩展函数语法。线程,
http://mail.python .org / pipermail / pyt ... 2003年2月/

[2] http://www.python.org/peps/pep-0310.html

[3] http://www.python.org/peps/pep-0288.html

解决方案

Brian Sabbey写道:

Thunk语句包含一个新关键字''do'',如下例所示。
thunk的主体是do声明中的套件;它被传递给''do'旁边出现的函数。 thunk作为函数的第一个参数被插入,让人联想到作为方法的第一个参数插入自我的方式。


将thunk作为最后一个

参数传递可能更有意义,而不是第一个。这样可以更容易地创建带有可选thunk的

函数,如:


def print_nums(start,end,thunk = None):

for num in xrange(start,end + 1):

如果thunk不是None:

num = thunk(num)

打印数量

print_nums(1,3)#打印1,2,3

do num print_nums(1,3) :#prints打印2,4,6

继续num * 2

因为thunk混合到他们的环境中,所以在周围''之后不能使用thunk ''声明已经完成




为什么?普通函数没有这个限制:

def foo():
... .x = 1

.... def bar():

....返回x

....返回栏

.... foo()()



1


< blockquote>

我认为你的提议非常有趣,随着时间的推移,我已经越来越多地缺少Python代码块



我会回答'thunks'和'thunks'。建议和基于套件的关键字

建议在这里。


我发现Ruby语法相当脏,因为它有很多

隐式的东西,将代码块视为与普通参数不同,

只允许传递一个代码块,需要一个proc关键字,有收益

执行一个隐式块...所有这一切,来自Python明确是

比隐含更好背景(这很有意义)简直就是

丑陋。

我喜欢你的语法但有一些评论。

我''给你一个无序的想法列表,由你做你喜欢的事情

与他们一起。


请记住,大多数问题来自于空间是

重要事情,这是恕我直言的一个非常好的主意,但阻止我们

将代码放在表达式中,例如:


func(a,b,def callback( x):

打印x




或是吗?也许这种语法可以起作用?


***************************** ***********

关于thunk的评论。


首先,我将代码块视为语言的必要条件。它们非常适用于很多常见的编程任务(比如用优雅的方式定义

中的回调):


button = create_button(" Save changes"):

do

self.save()


但是看起来你的thunk可以不接受参数,对我来说这是一个很大的缺点。在ruby中,thunk可以获取参数。简单的例子:


field = edit_field(" initial value",onsubmit = {| value | if

self.validate(value)then then else提示(价值无效

)})

[1,3,4] .each {| x | put x}


这样做的好处是thunk的接口(即它的

参数)就在你的眼前,而不是被埋在

edit_field里面的thunk调用代码。


a更复杂的随机例子:


fields [''password1 ''] = edit_field(" Enter Password")

fields [''password2''] = edit_field("'再次输入',onsubmit = {| value,

other_values | if value!= other_values [''password_1'']然后提醒(''两个

密码必须相同!)}


所以我认为thunks需要参数并返回一个值b / b
(将它们有效地用作回调)。

什么能区别于a对def()的简单修改:

将函数作为值返回,还有一个可选名称?我真的不知道
知道了,但它可能就是这样他们处理关闭s并与定义范围共享本地

变量。或者可能是因为两种函数/块没有需要

所以我们可以重用关键字def():


如果你愿意的话修改def(),你可以做,而不创建任何关键字:


#标准表格

f = def func(params):

代码


#无名代码块占用参数

func = def(params):

代码


请注意,上面两个相对于变量

" func",即。 func包含已定义的函数。实际上我发现def

funcname()是膨胀的,因为funcname = def()具有相同的功能,

但更通用。


#未命名的块没有参数

f = def:

代码


***** ********************************************** *

关于基于套件的关键字的评论。


您是否注意到这基本上是一种广义的HEREDOC语法?


我'要说明确比隐含更好,因此......


你的语法是:


做f(a,b):

a block


将块作为f的最后一个参数传递。

我不喜欢它,因为它隐藏了东西。


我会写:


f(a,b,@>,@>):

""" a very

大型多行

字符串""

def(x):< br $> b $ b打印x


这里@>是一个符号(使用你喜欢的任何东西)来表示占位符

用于下一行的内容。

缩进表示以下行确实是参数

这个功能。 :函数调用结束时,语法的其余部分是连贯的



请注意,这样就不需要做"关键字,因为匿名def()创建的代码

块与其他

参数没什么区别,在这种情况下是多行字符串。


这有很多优点。


它会使大型语句更具可读性:


而不是:

f(a,b,[由嵌套类构造函数构成的一些非常大的表达式

就像表格定义],c,d)


写道:

f(a,b,@>,c,d):

[非常大的表达式在这里]


因此,独立于代码块,这已经提高了可读性

的大型报表。

您还可以使用命名参数(各种提案):


f(a,b,c = @>,d = @>):

值c

d的值

或:


f(a,b,@ *>):

价值c

值d


f(a,b,@ **>):

c:价值c

d :值d

注意这是如何模仿多个

参数和多个命名参数的f(a,b,*)和f(a,b,**)。你喜欢它吗 ?我做。特别是

这个命名的版本,你不能迷失在param区,因为你

看到他们的名字!


现在如果你说def将定义的函数作为一个值返回,你就不需要一个do关键字。


所以,例如:


def withfile(fname,thunk,mode =" r"):

f = open(fname,mode)

thunk( f)

f.close()


然后:


withfile(" afile.txt", @>," w"):

def(f):

f.write(某事)


现在,你可能会说额外线路上的def是丑陋的,然后只写:


withfile(" afile.txt",@>," w"):def (f):

f.write(某事)


如果你真的喜欢,你可以把它作为def的同义词然后:


withfile(" afile.txt",@>," w"):do(f):

f.write(something)


两个:看起来有点奇怪,但我认为他们没问题。

''break''和''return''应该不允许在thunk中。一个


我认为应该允许返回thunk。毕竟它是一个功能

块,所以为什么放弃有用的功能?

产量也应该被允许,毕竟为什么一个thunk不是一个

发电机?这将是强大的。


def withfile(fname,thunk,mode =" r"):

f = open(fname,mode)

r = thunk(f)

f.close()

返回r

val = withfile(" ; afile.txt",@>," w"):

def(f):

f.write(某事)

返回一些东西


嗯,好像我现在没有更多的想法了。

你怎么看待这一切?

thunk在与定义它的函数相同的框架中进行评估。这个框架是可访问的:




Hm?

你的意思是像一个函数闭包,或者内部定义的局部变量

这个调用者可以看到thunk吗?

这可能会改变很多东西而且它就像是一个延续,是不是你要重新编码无堆栈?


Brian Sabbey写道:

def get_items(thunk):#< - " thunk-accepting function" ;
f =获取()
尝试:
我在f:
thunk(i)#A-OK
最后:
f.release ()

我在get_items()中打印:
打印我




好​​像你想通过以下方式解决所解决的发电机问题

操纵语法:让生成器看起来更像是,

因为父编译器不会抱怨;-)对不起,但IMO这是

hackery并且没有与良好的语言设计有关,我认为这是非常有害的。而不是让事情变得明确,它反过来又试图使Python代码更加模糊。

而且我不会注意到你的thunk的优越性其他

关于更常见技术的示例,例如装饰前和后期
后置条件和GOF命令模式。我认为这个

想法的地方是Michael Hudsons着名的字节码。


-1来自我的Python中的thunk。

Ciao,




Here is a first draft of a PEP for thunks. Please let me know what you
think. If there is a positive response, I will create a real PEP.

I made a patch that implements thunks as described here. It is available
at:
http://staff.washington.edu/sabbey/py_do

Good background on thunks can be found in ref. [1].

Simple Thunks
-------------

Thunks are, as far as this PEP is concerned, anonymous functions that
blend into their environment. They can be used in ways similar to code
blocks in Ruby or Smalltalk. One specific use of thunks is as a way to
abstract acquire/release code. Another use is as a complement to
generators.

A Set of Examples
=================

Thunk statements contain a new keyword, ''do'', as in the example below. The
body of the thunk is the suite in the ''do'' statement; it gets passed to
the function appearing next to ''do''. The thunk gets inserted as the first
argument to the function, reminiscent of the way ''self'' is inserted as the
first argument to methods.

def f(thunk):
before()
thunk()
after()

do f():
stuff()

The above code has the same effect as:

before()
stuff()
after()

Other arguments to ''f'' get placed after the thunk:

def f(thunk, a, b):
# a == 27, b == 28
before()
thunk()
after()

do f(27, 28):
stuff()

Thunks can also accept arguments:

def f(thunk):
thunk(6,7)

do x,y in f():
# x==6, y==7
stuff(x,y)

The return value can be captured

def f(thunk):
thunk()
return 8

do t=f():
# t not bound yet
stuff()

print t
==> 8

Thunks blend into their environment

def f(thunk):
thunk(6,7)

a = 20
do x,y in f():
a = 54
print a,x,y

==> 54,6,7

Thunks can return values. Since using ''return'' would leave it unclear
whether it is the thunk or the surrounding function that is returning, a
different keyword should be used. By analogy with ''for'' and ''while'' loops,
the ''continue'' keyword is used for this purpose:

def f(thunk):
before()
t = thunk()
# t == 11
after()

do f():
continue 11

Exceptions raised in the thunk pass through the thunk''s caller''s frame
before returning to the frame in which the thunk is defined:

def catch_everything(thunk):
try:
thunk()
except:
pass # SomeException gets caught here

try:
do catch_everything():
raise SomeException
except:
pass # SomeException doesn''t get caught here because it was
already caught

Because thunks blend into their environment, a thunk cannot be used after
its surrounding ''do'' statement has finished:

thunk_saver = None
def f(thunk):
global thunk_saver
thunk_saver = thunk

do f():
pass

thunk_saver() # exception, thunk has expired

''break'' and ''return'' should probably not be allowed in thunks. One could
use exceptions to simulate these, but it would be surprising to have
exceptions occur in what would otherwise be a non-exceptional situation.
One would have to use try/finally blocks in all code that calls thunks
just to deal with normal situations. For example, using code like

def f(thunk):
thunk()
prevent_core_meltdown()

with code like

do f():
p = 1
return p

would have a different effect than using it with

do f():
return 1

This behavior is potentially a cause of bugs since these two examples
might seem identical at first glance.

The thunk evaluates in the same frame as the function in which it was
defined. This frame is accessible:

def f(thunk):
frame = thunk.tk_frame

do f():
pass

Motivation
==========

Thunks can be used to solve most of the problems addressed by PEP 310 [2]
and PEP 288 [3].

PEP 310 deals with the abstraction of acquire/release code. Such code is
needed when one needs to acquire a resource before its use and release it
after. This often requires boilerplate, it is easy to get wrong, and
there is no visual indication that the before and after parts of the code
are related. Thunks solve these problems by allowing the acquire/release
code to be written in a single, re-usable function.

def acquire_release(thunk):
f = acquire()
try:
thunk(f)
finally:
f.release()

do t in acquire_release():
print t

More generally, thunks can be used whenever there is a repeated need for
the same code to appear before and after other code. For example,

do WaitCursor():
compute_for_a_long_time()

is more organized, easier to read and less bug-prone than the code

DoWaitCursor(1)
compute_for_a_long_time()
DoWaitCursor(-1)

PEP 288 tries to overcome some of the limitations of generators. One
limitation is that a ''yield'' is not allowed in the ''try'' block of a
''try''/''finally'' statement.

def get_items():
f = acquire()
try:
for i in f:
yield i # syntax error
finally:
f.release()

for i in get_items():
print i

This code is not allowed because execution might never return after the
''yield'' statement and therefore there is no way to ensure that the
''finally'' block is executed. A prohibition on such yields lessens the
suitability of generators as a way to produce items from a resource that
needs to be closed. Of course, the generator could be wrapped in a class
that closes the resource, but this is a complication one would like to
avoid, and does not ensure that the resource will be released in a timely
manner. Thunks do not have this limitation because the thunk-accepting
function is in control-- execution cannot break out of the ''do'' statement
without first passing through the thunk-accepting function.

def get_items(thunk): # <-- "thunk-accepting function"
f = acquire()
try:
for i in f:
thunk(i) # A-OK
finally:
f.release()

do i in get_items():
print i

Even though thunks can be used in some ways that generators cannot, they
are not nearly a replacement for generators. Importantly, one has no
analogue of the ''next'' method of generators when using thunks:

def f():
yield 89
yield 91

g = f()
g.next() # == 89
g.next() # == 91

[1] see the "Extended Function syntax" thread,
http://mail.python.org/pipermail/pyt...2003-February/
[2] http://www.python.org/peps/pep-0310.html
[3] http://www.python.org/peps/pep-0288.html

解决方案

Brian Sabbey wrote:

Thunk statements contain a new keyword, ''do'', as in the example below.
The body of the thunk is the suite in the ''do'' statement; it gets passed
to the function appearing next to ''do''. The thunk gets inserted as the
first argument to the function, reminiscent of the way ''self'' is
inserted as the first argument to methods.
It would probably make more sense to pass the thunk as the last
argument, not as the first. That would make it easier to create
functions with optional thunks, as in:

def print_nums(start, end, thunk=None):
for num in xrange(start, end+1):
if thunk is not None:
num = thunk(num)
print num

print_nums(1, 3) # prints 1, 2, 3

do num print_nums(1, 3): # prints 2, 4, 6
continue num * 2
Because thunks blend into their environment, a thunk cannot be used
after its surrounding ''do'' statement has finished



Why? Ordinary functions don''t have that restriction:

def foo(): .... x = 1
.... def bar():
.... return x
.... return bar
.... foo()()


1



I think your proposal is very interesting, I''ve been missing code blocks
in Python more and more as time goes by.
I''ll answer to both the ''thunks" proposal and the "suite-based keywords"
proposal here.

I find the Ruby syntax rather dirty though, because it has a lot of
implicit stuff, treats code blocks as different from normal arguments,
allows passing only one code block, needs a proc keyword, has yield
execute an implicit block... all this, coming from a Python "explicit is
better than implicit" background (which makes a lot of sense) is simply
ugly.
I like your syntax but have a few comments.
I''ll give you an unordered list of ideas, up to you to do what you like
with them.

Keep in mind that most of the problems come from the "space is
significant" thing, which is IMHO a very good idea, but prevents us from
putting code in expressions, like :

func( a,b, def callback( x ):
print x
)

or does it ? maybe this syntax could be made to work ?

****************************************
Comments on the thunks.

First of all I view code blocks as essential to a language. They are very
useful for a lot of common programming tasks (like defining callbacks in
an elegant way) :

button = create_button( "Save changes" ):
do
self.save()

However it seems your thunks can''t take parameters, which to me is a big
drawback. In ruby a thunk can take parameters. Simple examples :

field = edit_field( "initial value", onsubmit={ |value| if
self.validate(value) then do something else alert( "the value is invalid"
) } )
[1,3,4].each { |x| puts x }

This has the advantage that the interface to the thunk (ie. its
parameters) are right there before your eyes instead of being buried in
the thunk invocation code inside the edit_field.

a more complex random example :

fields[''password1''] = edit_field( "Enter Password" )
fields[''password2''] = edit_field( "Enter it again", onsubmit = {|value,
other_values| if value != other_values[''password_1''] then alert(''the two
passwords must be the same !") }

So I think it''s essential that thunks take parameters and return a value
(to use them effectively as callbacks).
What shall distinguish them from a simple alteration to def(): which
returns the function as a value, and an optional name ? really I don''t
know, but it could be the way they handle closures and share local
variables with the defining scope. Or it could be that there is no need
for two kinds of function/blocks and so we can reuse the keyword def() :

If you wish to modify def(), you could do, without creating any keyword :

# standard form
f = def func( params ):
code

# unnamed code block taking params
func = def (params):
code

Note that the two above are equivalent with regard to the variable
"func", ie. func contains the defined function. Actually I find def
funcname() to be bloat, as funcname = def() has the same functionality,
but is a lot more universal.

# unnamed block taking no params
f = def:
code

************************************************** *
Comments on the suite-based keywords.

Did you notice that this was basically a generalized HEREDOC syntax ?

I''d say that explicit is better than implicit, hence...

Your syntax is :

do f(a,b):
a block

passes block as the last parameter of f.
I don''t like it because it hides stuff.

I''d write :

f(a,b,@>,@>):
"""a very
large multi-line
string"""
def (x):
print x

Here the @> is a symbol (use whatever you like) to indicate "placeholder
for something which is on the next line".
Indentation indicates that the following lines are indeed argument for
the function. The : at the end of the function call is there for coherence
with the rest of the syntax.
Notice that, this way, there is no need for a "do" keyword, as the code
block created by an anonymous def() is no different that the other
parameter, in this case a multiline string.

This has many advantages.

It will make big statements more readable :

instead of :
f( a,b, [some very big expression made up of nested class constructors
like a form defintion ], c, d )

write :
f( a, b, @>, c, d ):
[the very big expression goes here]

So, independently of code blocks, this already improves the readability
of big statements.
You could also use named parameters (various proposals):

f( a,b, c=@>, d=@> ):
value of c
value of d

or :

f( a,b, @*> ):
value of c
value of d

f( a,b, @**> ):
c: value of c
d: value of d

Notice how this mimics f( a,b, * ) and f(a,b, ** ) for multiple
arguments, and multiple named arguments. Do you like it ? I do. Especially
the named version where you cant'' get lost in the param block because you
see their names !

Now if you say that def returns the defined function as a value, you
don''t need a do keyword.

So, for instance :

def withfile( fname, thunk, mode = "r" ):
f = open( fname, mode )
thunk(f)
f.close()

then :

withfile( "afile.txt", @>, "w" ):
def (f):
f.write( something )

Now, you may say that the def on an extra line is ugly, then just write :

withfile( "afile.txt", @>, "w" ): def (f):
f.write( something )

If you really like do you can make it a synonym for def and then :

withfile( "afile.txt", @>, "w" ): do (f):
f.write( something )

The two ":" seem a bit weird but I think they''re OK.

''break'' and ''return'' should probably not be allowed in thunks. One
I do think return should be allowed in a thunk. After all it''s a function
block, so why ditch useful functionality ?
yield should also be allowed, after all why can a thunk not be a
generator ? This would be powerful.

def withfile( fname, thunk, mode = "r" ):
f = open( fname, mode )
r = thunk(f)
f.close()
return r

val = withfile( "afile.txt", @>, "w" ):
def (f):
f.write( something )
return something

Well, it seems I have no more ideas for now.
What do you think about all this ?
The thunk evaluates in the same frame as the function in which it was
defined. This frame is accessible:



Hm ?
You mean like a function closure, or that local variables defined inside
the thunk will be visible to the caller ?
This might change a lot of things and it becomes like a continuation, are
you going to recode stackless ?


Brian Sabbey wrote:

def get_items(thunk): # <-- "thunk-accepting function"
f = acquire()
try:
for i in f:
thunk(i) # A-OK
finally:
f.release()

do i in get_items():
print i



Seems like You want to solve the addressed generator problem by
manipulating the syntax: "make generators look more function like",
because father compiler won''t complain ;-) Sorry, but IMO this is
hackery and has nothing to do with good language design and I consider
this as extremely harmfull. Instead of making things explicit it does
it the other way round and tries to make Python code more obscure.
Moreover I can''t notice the superiority of thunks in Your other
examples over more common techniques like decorators for pre- and
postconditions and the GOF command pattern. I thinks the place for such
ideas are Michael Hudsons famous bytecodehacks.

-1 for from me for thunks in Python.

Ciao,
Kay


这篇关于前PEP:简单的Thunk的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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