120

Pythonのネストされたクラスのスコープを理解しようとしています。これが私のサンプルコードです:

class OuterClass:
    outer_var = 1
    class InnerClass:
        inner_var = outer_var

クラスの作成が完了せず、エラーが発生します。

<type 'exceptions.NameError'>: name 'outer_var' is not defined

試してみてもうまくいきinner_var = Outerclass.outer_varません。私は得る:

<type 'exceptions.NameError'>: name 'OuterClass' is not defined

outer_varから静的にアクセスしようとしていますInnerClass

これを行う方法はありますか?

4

7 に答える 7

105
class Outer(object):
    outer_var = 1

    class Inner(object):
        @property
        def inner_var(self):
            return Outer.outer_var

これは、他の言語で機能する同様のものとまったく同じではなく、 へのアクセスをスコープする代わりにグローバル ルックアップを使用しますouter_var。(名前がバインドされているオブジェクトを変更するOuterと、このコードは次に実行されるときにそのオブジェクトを使用します。)

代わりに、実際にはインスタンス属性であるため、すべてのInnerオブジェクトに への参照を持たせたい場合:Outerouter_var

class Outer(object):
    def __init__(self):
        self.outer_var = 1

    def get_inner(self):
        return self.Inner(self)
        # "self.Inner" is because Inner is a class attribute of this class
        # "Outer.Inner" would also work, or move Inner to global scope
        # and then just use "Inner"

    class Inner(object):
        def __init__(self, outer):
            self.outer = outer

        @property
        def inner_var(self):
            return self.outer.outer_var

クラスのネストは Python ではあまり一般的ではなく、クラス間の特別な関係を自動的に意味するものではないことに注意してください。入れ子にしないほうがいいです。Outer(必要に応じて、クラス属性を に設定することもできInnerます。)

于 2009-11-19T18:58:53.827 に答える
45

私はあなたが簡単にできると思います:

class OuterClass:
    outer_var = 1

    class InnerClass:
        pass
    InnerClass.inner_var = outer_var

あなたが遭遇した問題はこれによるものです:

ブロックは、ユニットとして実行される Python プログラム テキストの一部です。ブロックとは、モジュール、関数本体、およびクラス定義です。
(...)
スコープは、ブロック内の名前の可視性を定義します。
(...)
クラス ブロックで定義された名前のスコープは、クラス ブロックに限定されます。メソッドのコード ブロックには拡張されません。関数スコープを使用して実装されるため、これにはジェネレータ式が含まれます。これは、以下が失敗することを意味します。

   class A:  

       a = 42  

       b = list(a + i for i in range(10))

http://docs.python.org/reference/executionmodel.html#naming-and-binding

上記の意味:
関数本体はコード ブロックであり、メソッドは関数であり、クラス定義に存在する関数本体から定義された名前は関数本体に拡張されません。

あなたのケースでこれを言い換える
と、クラス定義はコードブロックであり、外部クラス定義に存在する内部クラス定義から定義された名前は内部クラス定義に拡張されません。

于 2011-12-03T09:26:51.033 に答える
20

ネストされたクラスを使用しない方が良いかもしれません。ネストする必要がある場合は、これを試してください:

x = 1
class OuterClass:
    outer_var = x
    class InnerClass:
        inner_var = x

または、ネストする前に両方のクラスを宣言します。

class OuterClass:
    outer_var = 1

class InnerClass:
    inner_var = OuterClass.outer_var

OuterClass.InnerClass = InnerClass

(この後、del InnerClass必要に応じてできます。)

于 2009-11-19T19:19:33.470 に答える
3

最も簡単な解決策:

class OuterClass:
    outer_var = 1
    class InnerClass:
        def __init__(self):
            self.inner_var = OuterClass.outer_var

明確にする必要がありますが、それほど手間はかかりません。

于 2013-12-27T19:51:34.263 に答える
1

Python では変更可能なオブジェクトは参照として渡されるため、外側のクラスの参照を内側のクラスに渡すことができます。

class OuterClass:
    def __init__(self):
        self.outer_var = 1
        self.inner_class = OuterClass.InnerClass(self)
        print('Inner variable in OuterClass = %d' % self.inner_class.inner_var)

    class InnerClass:
        def __init__(self, outer_class):
            self.outer_class = outer_class
            self.inner_var = 2
            print('Outer variable in InnerClass = %d' % self.outer_class.outer_var)
于 2016-07-18T13:37:22.653 に答える
0
class c_outer:
    def __init__(self, name:str='default_name'):
        self._name = name
        self._instance_lst = list()
        self._x = self.c_inner()

    def get_name(self):
        return(self._name)

    def add_inner_instance(self,name:str='default'):
        self._instance_lst.append(self.c_inner(name))

    def get_instance_name(self,index:int):
        return(self._instance_lst[index].get_name())


    class c_inner:
        def __init__(self, name:str='default_name'):
            self._name = name
        def get_name(self):
            return(self._name)


outer = c_outer("name_outer")

outer.add_inner_instance("test1")
outer.add_inner_instance("test2")
outer.add_inner_instance("test3")
inner_1 = outer.c_inner("name_inner1")
inner_2 = outer.c_inner("name_inner2")
inner_3 = outer.c_inner("name_inner3")

print(outer.get_instance_name(index=0))
print(outer.get_instance_name(1))
print(outer._instance_lst[2]._name
print(outer.get_name())
print(inner_1.get_name())
print(inner_2.get_name())

test1 test2 test3 name_outer name_inner1 name_inner2 name_inner3

于 2021-10-05T06:59:19.773 に答える