Ecco qualcosa che funziona un po 'come variabili speciali di Lisp, ma si adatta un po' meglio in Python.
_stack = []
class _EnvBlock(object):
def __init__(self, kwargs):
self.kwargs = kwargs
def __enter__(self):
_stack.append(self.kwargs)
def __exit__(self, t, v, tb):
_stack.pop()
class _Env(object):
def __getattr__(self, name):
for scope in reversed(_stack):
if name in scope:
return scope[name]
raise AttributeError("no such variable in environment")
def let(self, **kwargs):
return _EnvBlock(kwargs)
def __setattr__(self, name, value):
raise AttributeError("env variables can only be set using `with env.let()`")
env = _Env()
Si può usare in questo modo:
with env.let(bufsize=8192, encoding="ascii"):
print env.bufsize # prints 8192
a() # call a function that uses env.bufsize or env.encoding
Gli effetti della env.let
durano per tutta la durata del blocco with
.
Si noti che se si utilizzano thread, si vorrà sicuramente un diverso _stack
per ogni thread. Potresti usare threading.local per implementarlo.
fonte
2010-01-04 20:49:34
Congratulazioni! Grazie al tuo duro lavoro, il mondo della programmazione ha ancora una soluzione in più che farà strada nei cuori di numerose applicazioni critiche! – yfeldblum
E dopotutto, le "variabili speciali" di Lisp non sono così terribili, vero? Sono come le variabili di ambiente in bash. Ciò che è terribile sono le lingue in cui l'ambito dinamico è l'impostazione predefinita. Fortunatamente non molti di quelli sono rimasti. –
Sono contento che la maggior parte dei linguaggi reali non utilizzi l'ambito dinamico ... eppure ho scritto una tonnellata di Emacs Lisp, che lo fa; e mi sembra assolutamente naturale. (Emacs Lisp ha di recente ottenuto l'opzione lessicale come opzione, e non mi sono nemmeno preoccupato di usarlo :-) – offby1