以下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 :(得分:6)
在Python中,一切都是对象 - 某种类型的实例。例如。 1
是int
类型的实例,def foo(): pass
创建对象foo
,它是类型function
的实例(对于类 - 对象,由{{{ 1}}语句是类型class
)的实例。鉴于此,
type
和
class Foo:
string = "foo1"
class Foo:
string = "foo2"
BTW,可以使用a = 1
a = 2
函数执行类定义(是的,有类型type
和内置函数type
):
type
所以类和函数不是一些不同类型的数据,尽管可以使用特殊语法来创建它们的实例。
另请参阅相关的Data Model部分。
答案 1 :(得分:1)
如果您将类视为当前命名空间的“types dictionary”中的元素,则第二个定义将替换第一个定义,如预期的那样:
>>> 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
指向内存中的不同类),并且它是最后一个占优势的。
答案 2 :(得分:1)
Foo类实际上是在脚本中进一步重新定义的(脚本由解释器从上到下读取)。
class Foo:
string = "foo1"
class Foo:
string = "foo2"
f = Foo()
print f.string
打印“foo2”
答案 3 :(得分:1)
从概念上讲,这只是重新命名。它与此没有什么不同:
x = 1
x = 2
我相信你不会希望这是一个错误。
答案 4 :(得分:1)
在编译语言和一些解释语言中,定义,声明和执行之间存在明确的分离。但在python中它更简单。只有声明!
Python EXECUTES 您的脚本/程序/模块一旦被调用。将def
和class
视为“语法糖”可能会有所帮助。例如。 class是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__)
归结为使用最新的“声明”覆盖名称Foo
和bar
。所以这只是从python-pov的预期工作 - 但可能不是你想要的! ; - )
所以对于具有不同背景的开发人员而言,这也是一个典型错误:
def some_method(default_list = []):
...
default_list在这里是一个单身人士。每次对some_method
的调用都使用相同的default_list
,因为list-object是在第一次执行时创建的。
Python不会进入函数体,但只在开始解析时才执行签名/头部。