以前の投稿で、tmp
次のようなパターンで中間変数を回避する方法について質問しました。
tmp = <some operation>
result = tmp[<boolean expression>]
del tmp
...tmp
パンダオブジェクトはどこにありますか。例えば:
tmp = df.xs('A')['II'] - df.xs('B')['II']
result = tmp[tmp < 0]
del tmp
このパターンについての私のボンネットのミツバチは、基本的に、何年にもわたって Python をプログラミングした後でも、死ぬことのない正直なレキシカル スコーピング1への憧れから来ています。Python 2では、 への明示的な呼び出しで間に合わせますdel
。
コンテキスト マネージャーを使用して、Python のレキシカル スコープを模倣できるのではないかと思います。次のようになります。
with my(df.xs('A')['II'] - df.xs('B')['II']) as tmp:
result = tmp[tmp < 0]
レキシカル スコープを模倣できるようにするために、コンテキスト マネージャ クラスには、(コンテキスト マネージャの) ' enter ' メソッドdel
によって返される値が割り当てられる呼び出しスコープ内の変数を取得する方法が必要です。
たとえば、大量のチートを使用すると、次のようになります。
import contextlib as cl
# herein lies the rub...
def deletelexical():
try: del globals()['h']
except: pass
@cl.contextmanager
def my(obj):
try: yield obj
finally: deletelexical()
with my(2+2) as h:
print h
try:
print h
except NameError, e:
print '%s: %s' % (type(e).__name__, e)
# 4
# Name error: name 'h' is not defined
もちろん、問題はdeletelexical
実際に実装することです。それはできますか?
tmp
編集: abarnert が指摘したように、周囲のスコープに既存のものdeletelexical
がある場合、それを復元しないため、レキシカル スコープのエミュレーションとはほとんど見なされません。tmp
正しい実装では、既存の変数を周囲のスコープに保存し、with ステートメントの最後でそれらを置き換える必要があります。
1たとえば、Perl では、上記を次のようにコーディングします。
my $result = do {
my $tmp = $df->xs('A')['II'] - $df->xs('B')['II'];
$tmp[$tmp < 0]
};
または JavaScript で:
var result = function () {
var tmp = df.xs('A')['II'] - df.xs('B')['II'];
return tmp[tmp < 0];
}();
編集: abarnert の投稿とコメントへの応答: はい、Python で定義できます
def tmpfn():
tmp = df.xs('A')['II'] - df.xs('B')['II']
return tmp[tmp < 0]
...そして、これは確かに今後役に立たない名前で名前空間を混乱させることを防ぎますが、今後は役に立たない名前tmp
で名前空間を混乱させることによってそうしますtmpfn
。JavaScript (および Perl も、BTW なども) では無名関数を使用できますが、Python では使用できません。いずれにせよ、JavaScript の無名関数は、レキシカル スコープを取得するためのやや面倒な方法であると考えています。それは確かに何もないよりはましであり、私はそれを頻繁に使用しますが、Perl のものほど優れているわけではありません (後者とは、Perl のdo
ステートメントだけでなく、レキシカルとダイナミックの両方でスコープを制御するために提供される他のさまざまな方法も意味します)。
2 Python プログラマーのごく一部だけがレキシカル スコープについてネズミの尻尾を与えているという事実を思い出す必要はありません。