Fil*_*und 19 python go deferred
如何实现像deferpython中的语句一样工作的东西?
Defer将函数调用推送到堆栈.当包含defer语句的函数返回时,在defer语句首先位于内部的范围内,逐个弹出并执行deferred函数调用.延迟语句看起来像函数调用,但在弹出之前不会执行.
去举例说明它是如何工作的:
func main() {
fmt.Println("counting")
var a *int
for i := 0; i < 10; i++ {
a = &i
defer fmt.Println(*a, i)
}
x := 42
a = &x
fmt.Println("done")
}
Run Code Online (Sandbox Code Playgroud)
输出:
counting
done
9 9
8 8
7 7
6 6
5 5
4 4
3 3
2 2
1 1
0 0
Run Code Online (Sandbox Code Playgroud)
去用例的例子:
var m sync.Mutex
func someFunction() {
m.Lock()
defer m.Unlock()
// Whatever you want, with as many return statements as you want, wherever.
// Simply forget that you ever locked a mutex, or that you have to remember to release it again.
}
Run Code Online (Sandbox Code Playgroud)
jfs*_*jfs 17
要模拟defer fmt.Println(*a, i)示例,您可以使用contextlib.ExitStack:
#!/usr/bin/env python3
from contextlib import ExitStack
from functools import partial
print("counting")
with ExitStack() as stack:
for i in range(10):
a = i
stack.callback(partial(print, a, i))
x = 42
a = x
print("done")
Run Code Online (Sandbox Code Playgroud)
counting
done
9 9
8 8
7 7
6 6
5 5
4 4
3 3
2 2
1 1
0 0
Run Code Online (Sandbox Code Playgroud)
可以轻松模拟互斥锁的情况:
def some_function(lock=Lock()):
with lock:
# whatever
Run Code Online (Sandbox Code Playgroud)
Python的with语句与Go的延迟具有相似的目的.
Python中类似的代码是:
mutex = Lock()
def someFunction():
with mutex:
# Whatever you want, with as many return statements
# as you want, wherever. Simply forget that you ever
# locked a mutex, or that you have to remember to
# release it again.
Run Code Online (Sandbox Code Playgroud)
我在那里做了一个(与2.x兼容):
@defers_collector
def func():
f = open('file.txt', 'w')
defer(lambda: f.close())
defer(lambda : print("Defer called!"))
def my_defer():
recover()
defer(lambda: my_defer())
print("Ok )")
panic("WTF?")
print("Never printed (((")
func()
print("Recovered!")
Run Code Online (Sandbox Code Playgroud)
来源defers_collector是:
# Go-style error handling
import inspect
import sys
def panic(x):
raise Exception(x)
def defer(x):
for f in inspect.stack():
if '__defers__' in f[0].f_locals:
f[0].f_locals['__defers__'].append(x)
break
def recover():
val = None
for f in inspect.stack():
loc = f[0].f_locals
if f[3] == '__exit__' and '__suppress__' in loc:
val = loc['exc_value']
loc['__suppress__'].append(True)
break
return val
class DefersContainer(object):
def __init__(self):
# List for sustain refer in shallow clone
self.defers = []
def append(self, defer):
self.defers.append(defer)
def __enter__(self):
pass
def __exit__(self, exc_type, exc_value, traceback):
__suppress__ = []
for d in reversed(self.defers):
try:
d()
except:
__suppress__ = []
exc_type, exc_value, traceback = sys.exc_info()
return __suppress__
def defers_collector(func):
def __wrap__(*args, **kwargs):
__defers__ = DefersContainer()
with __defers__:
func(*args, **kwargs)
return __wrap__
Run Code Online (Sandbox Code Playgroud)
一个延迟部分的灵感来自于实施@DenisKolodin 答案是可以作为的一部分pygolang,2:
wc = wcfs.join(zurl) ? wc = wcfs.join(zurl)
defer(wc.close) ? try:
? ...
... ? ...
... ? ...
... ? finally:
? wc.close()
Run Code Online (Sandbox Code Playgroud)
小智 5
对jfs 答案的补充ExitStack在装饰器的帮助下进一步推动了这个想法:
@with_exit_stack
def counting(n, stack):
for i in range(n):
stack.callback(print, i)
@with_exit_stack
def locking(lock, stack):
stack.enter_context(lock)
# whatever
Run Code Online (Sandbox Code Playgroud)
with_exit_stack定义如下:
import functools
import contextlib
def with_exit_stack(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
with contextlib.ExitStack() as stack:
return func(*args, **kwargs, stack=stack)
return wrapper
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7931 次 |
| 最近记录: |