2013-12-20 69 views
3

我很驚訝,這個代碼給出了後續的錯誤(Python的2.7.3):可能實現嵌套類定義的繼承嗎?

class Foo(object): 
    class Bar(object): 
     pass 
    class Baz(object): 
     class InnerBar(Bar): 
      pass 

結果:

Enthought Python Distribution -- www.enthought.com 
Version: 7.3-2 (64-bit) 

Python 2.7.3 |EPD 7.3-2 (64-bit)| (default, Apr 11 2012, 17:52:16) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-44)] on linux2 
Type "credits", "demo" or "enthought" for more information. 
Hello 
>>> class Foo(object): 
...  class Bar(object): 
...   pass 
...  class Baz(object): 
...   class InnerBar(Bar): 
...    pass 
... 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 4, in Foo 
    File "<stdin>", line 5, in Baz 
NameError: name 'Bar' is not defined 

我懷疑的是,這與的具體執行做相當於Bar = type(...)class作業,但即便如此,爲什麼BarBaz內關閉?

有沒有辦法來解決這個這個精確的一種實現的(如,我不想Foo威力內放鬆約束BarFoo內部定義的普通class,而其他類的類內想從Bar繼承

我想到的特殊用例是模仿一些數據庫結構來創建一個更加面向對象的設計,以反映數據服務項目中的模式,其中大部分代碼是自動生成的Python,派生自一個在XSD上執行檢查的程序,因此在類中定義的類是仿效XSD複雜性某些事情的一種自然方式但是有額外的能力可以說出他們是什麼時候是其他複雜類型的孩子,等等。這就是爲什麼我猶豫要在Foo以外的地方拉一門課以備後續繼承。

回答

3

這裏沒有關閉。在執行嵌套代碼時,類的主體是而不是父範圍。

至於在嵌套範圍代碼而言,只有全局和局部範圍存在,Foo類身體可訪問的命名空間。

Naming and Binding documentation

如果在功能塊出現的定義,範圍延伸到包含在限定一個內的任何塊,除非包含塊引入了對名稱不同的結合。在類塊中定義的名稱範圍僅限於該類塊

強調我的。

工作,在這裏是使用嵌套函數產生的涵蓋範圍可以訪問:

class Foo(object): 
    def produce_nested_scope(): 
     class Bar(object): 
      pass 
     class Baz(object): 
      class InnerBar(Bar): 
       pass 
     return Bar, Baz 
    Bar, Baz = produce_nested_scope() 
    del produce_nested_scope 

演示:

>>> class Foo(object): 
...  def produce_nested_scope(): 
...   class Bar(object): 
...    pass 
...   class Baz(object): 
...    class InnerBar(Bar): 
...     pass 
...   return Bar, Baz 
...  Bar, Baz = produce_nested_scope() 
...  del produce_nested_scope 
... 
>>> Foo.Bar 
<class '__main__.Bar'> 
>>> Foo.Baz 
<class '__main__.Baz'> 
+0

我仍然不確定爲什麼記錄的過程沒有完全發生在''Foo'的套件執行正在進行的本地名稱空間內的'Bar'和'Baz' *。在'Foo'是一個綁定名稱之前,爲'Foo'開發的任何本地namepsace,在*那個*名稱空間中,爲什麼Bar'的所有套件都不會完成,那麼'Bar'綁定在*那*命名空間),然後執行所有'Baz'套件(包括'InnerBar',它可以*查找一個命名空間級別來查找'Bar',因爲'Bar'已經綁定在*那個*命名空間中),然後'Foo'完成並受到約束?我錯過了什麼? – ely

+0

@EMS:啊,我今天缺乏咖啡因。我以爲你在'Foo'裏面用'Foo'。我誤讀了。不,類名稱空間不是用於查找其他名稱的**範圍。找不到'Bar',因爲'Foo'套件不是父範圍。 –

1

這是一個可怕的黑客:

class Foo(object): 
    def hack(dest): 
     class Bar(object): 
      pass 
     class Baz(object): 
      class InnerBar(Bar): 
       pass 

     dest.update(locals()) 
    hack(locals()) 
>>> Foo.Bar 
<class '__main__.Bar'> 
>>> Foo.Baz.InnerBar 
<class '__main__.InnerBar'>