北海道苫小牧市出身の初老PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

classの入れ子とスコープ

もう一つ、没ったコードを挙げておきます。*1

class Base(object):

    class Inner1(object): pass

    class Inner2(object):
        foo = Base.Inner1()     # ← これNG
        def do_nothing(self):
            foo = Base.Inner1() # ← こちらはOK
            print foo

Base.Inner2().do_nothing()
Traceback (most recent call last):
  File "?.py", line ?, in <module>
    class Base(object):
  File "?.py", line ?, in Base
    class Inner2(object):
  File "?.py", line ?, in Inner2
    foo = Base.Inner1()
NameError: name 'Base' is not defined

以下、予想。

Inner2クラスブロックから見えるのは、ローカルスコープとグローバルスコープだけなので、Baseクラスブロックの名前(特に"Inner1")は見えません。そのため、Inner1を参照するにはグローバルスコープを経由してBase.Inner1とする必要があります。*2

ところが、グローバルスコープに"Base"が追加されるのはBaseクラスブロックを抜けた後なので、Inner2クラスブロックを実行しているときは参照できません。メソッドからは参照ができるのは、メソッドが実行されるのはBaseクラスブロックを抜けた後だからです。


Javaでできるかやってみる

ちなみに、Javaではこうです。もちろん、普通にコンパイルできます。Inner1とInner2の定義が逆でもコンパイルできます。

public class Base{
    static private class Inner1{
    }
    static private class Inner2{
        static private final Inner1 foo = new Inner1();
    }
}

*1: もしも、2つのインナークラスの片側からもう片側の定義を参照できる方法があったら教えて下さいm(_ _)m

*2:ネストされたスコープになるのは関数の場合だけですよね??ちょっと自信なし。