2016-11-15 9 views
2

私はPython 2.7を使用していますが、オブジェクトがPython 3+と互換性のあるベースストリングのサブクラスであるかどうかをチェックするコードを作成しようとしています。私はアプローチsuggested hereを追跡しようとした、その過程で私がすれば、私は例外処理でこの奇妙な動作は何ですか?

を理解していない動作を見つけました:

def foo(): 
    try: basestring 
    except NameError: 
     print "a" 
foo() 

何も起こりません。

def foo(): 
    try: basestring 
    except NameError: 
     print "a" 
     basestring=str 
foo() 

が続いて「」印刷されています。私は少しだけを除いて内部でそのコードを変更する場合

例外ブロックに何かを追加すると、例外のトリガにどのように影響するか分かりません。

私は、関数外で同じコードがチェック:

try: 
    basestring 
except NameError: 
    print("a") 
    basestring=str 

を何もが、その場合には印刷されません取得します。

答えて

3

最初のケースでは簡単です。名前basestring__builtins__.basestringで解決されます。 tryブロックによって生成された例外は存在しないため、動作は予期したとおりになるはずです。

2番目のケースでは、難しいです。関数内に名前basestringを使用すると、その名前が関数のローカル変数になります。 関数にローカルな名前は、関数定義時にで決まることに注意してください。関数の最初の行を実行するとき、Pythonは既に名前のbasestringが関数のローカル変数であることを知っています。

>>> def foo(): 
...  basestring 
...  potato 
...  errorerrorerror 
...  
>>> print foo.func_code.co_names 
('basestring', 'potato', 'errorerrorerror') 
>>> print foo.func_code.co_varnames 
() 

ラインpotatoに出NameErrorfoo()を呼び出します。比較対照下記bar()で、ラインbasestringに出NameErrorと思われる:だから

>>> def bar(): 
...  basestring 
...  potato 
...  errorerrorerror 
...  basestring = "D'Addario EXL160 Medium" 
...  
>>> print bar.func_code.co_names 
('potato', 'errorerrorerror') 
>>> print bar.func_code.co_varnames 
('basestring',) 

、発生した例外は、それはPythonでのエラーであるオブジェクトにバインドされる前に使用されている名前が原因であります。これは定義時ではなく実行時のエラーです。 3番目のケースは、最初のケースに似ています。「ローカル変数」の概念はグローバルスコープには適用されません。

+1

"**関数にローカルな名前は、関数定義時に決定されます** **" これはまさに私が逃したものです!ありがとうございました! – alvarosg

5

basestring = strを関数に追加すると、basestringがローカル変数として扱われるべきであるというpythonに伝えられます。しかし、最初の文が実行された時点で、はであり、名前はbasestring(グローバルのみ)なので、pythonはUnboundLocalErrorを生成します。

UnboundLocalErrorNameErrorから継承されているため、例外処理が発生し、aが表示されます。


あなたは核心ザラザラに興味があれば - 私たちはdisを使用して、これを引き離すことができます:fooため、basestringLOAD_FASTオペコード(手段を用いて取得されることを

import dis 

def foo(): 
    try: 
     basestring 
    except NameError: 
     print("a") 
     basestring=str 

def bar(): 
    try: 
     basestring 
    except NameError: 
     print("a") 

dis.dis(foo) 
print('--' * 20) 
dis.dis(bar) 

注意ローカル変数を探しています)。しかし、barではLOAD_GLOBALオペコードを使用してbasestringが検索されます。

関連する問題