2012-03-17 50 views
2

以下Python代码正常执行而不引发异常:为什么Python不会在命名空间碰撞时产生错误?

class Foo: 
    pass 

class Foo: 
    pass 

def bar(): 
    pass 

def bar(): 
    pass 

print(Foo.__module__ + Foo.__name__) 

但显然,也有__main__.Foo__main__.bar多个实例。为什么Python遇到这种名称空间冲突时不会引发错误?既然它没有提出错误,它究竟做了什么?第一类__main__.Foo被第二类__main__.Foo所取代?

+0

要分配一个变量两次是错误的? – JBernardo 2012-03-17 14:59:32

+0

但是,它不仅仅是分配一个变量吗?它使用每个新的类定义创建新类型。 – Channel72 2012-03-17 15:00:20

+0

那又如何?它创建了第二个类对象,然后它分配名称/“变量”Foo来引用该类对象,而不是之前引用的对象。模块是一系列语句(大部分类似于函数),'class' /'def'只是语句。 – delnan 2012-03-17 15:02:51

回答

6

在Python中,一切都是某种类型的对象 - 实例。例如。 1int类型的一个实例,def foo(): pass创建对象foofunction类型的一个实例(用于相同的类 - 对象,通过class语句创建的类型是type的实例)。 (是,存在键入type和内置鉴于这一点,有没有

class Foo: 
    string = "foo1" 

class Foo: 
    string = "foo2" 

a = 1 
a = 2 

BTW之间差(在名称结合机构的水平),可以使用type函数来执行类定义-in功能type):

Foo = type('Foo',(), {string: 'foo1'}) 

因此类和函数是不是一些不同种类的数据,虽然SPECI al语法可用于创建它们的实例。

另请参阅相关Data Model部分。

1

第二个定义替换第一个,预期,如果你认为在班作为当前命名空间的“类型辞典”元素:

>>> class Foo: 
...  def test1(self): 
...    print "test1" 
... 
>>> Foo 
<class __main__.Foo at 0x7fe8c6943650> 
>>> class Foo: 
...  def test2(self): 
...    print "test2" 
... 
>>> Foo 
<class __main__.Foo at 0x7fe8c6943590> 
>>> a = Foo() 
>>> a.test1() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: Foo instance has no attribute 'test1' 
>>> a.test2() 
test2 
>>> 

在这里,你可以清楚地看到的“定义” Foo更改(Foo指向内存中的不同类别),并且它是最后一个流行的。

1

Foo类被有效地重新定义在脚本之后(脚本被解释器从上到下读取)。

class Foo: 
    string = "foo1" 

class Foo: 
    string = "foo2" 

f = Foo() 
print f.string 

打印 “foo2的”

1

概念这只是重新绑定一个名字。这是没有什么不同:

x = 1 
x = 2 

我敢肯定,你不会希望这是一个错误。

1

在编译和某些解释语言中,在定义,声明和执行之间存在明确的分离。但在Python中它更简单。只是声明!

Python EXECUTES只要它被调用,你的脚本/程序/模块。看到defclass为“语法糖”可能会有所帮助。例如。类是围绕Foo = type("class-name", (bases), {attributes})的便利包装。

所以Python执行:

class Foo #equivalent to: Foo = type("class-name", (bases), {attributes}) 
class Foo 
def bar 
def bar 

print(Foo.__module__ + Foo.__name__) 

其归结为覆盖名Foobar了最新的 “宣言”。所以这只是按照python-pov的意图工作 - 但可能并非如你所愿! ;-)

所以这也是一个典型的错误与不同背景的开发人员产生误解:

def some_method(default_list = []): 
    ... 

default_list这里是一个单身。每次调用some_method时都使用相同的default_list,因为列表对象是在第一次执行时创建的。

Python不会进入函数体,但只会在开始解析时执行签名/头。