Python如何区分不同的数据类型?
抱歉如果这个问题对你来说有点幼稚,但我刚开始学习Python,之前学过C++和Java。我想知道为什么我可以直接写变量,比如 id = 0
和 name = 'John'
,而不需要在前面加 int
或 string
!我猜可能是因为数字里没有 '
,但像 def increase(first, second)
这样的写法,Python是怎么知道这些参数的类型的呢?这和C++里的 int increase(int first, int second)
有什么不同呢?
5 个回答
Python使用了一种叫做“鸭子类型”的方法——如果它走起来像鸭子,外形像鸭子,叫声也像鸭子,那它就是鸭子。如果你传入一个字符串,然后想对它进行一些数字运算,那就会出错。
可以看看这里: http://en.wikipedia.org/wiki/Python_%28programming_language%29#Typing 和 http://en.wikipedia.org/wiki/Duck_typing
Python 是一种 动态类型 的语言:这意味着所有的变量都可以指向任何类型的对象。比如说,id
和 name
可以是任何东西,但它们实际指向的对象可能是 int
(整数)或 str
(字符串)。例如,0
是一个字面量,它会被解析成一个 int
对象,而 'John'
则是一个字面量,它会变成一个 str
对象。还有一些对象类型没有字面量,必须通过调用来获得(比如 frozenset
——你不能直接写出一个字面量的 frozenset,必须调用 frozenset
函数)。
因此,变量不需要声明,因为你并没有定义变量的任何特性。像 id = 0
和 name = 'John'
只是简单的赋值。
increase
返回一个 int
类型的值,因为你在这个函数里返回的就是这个;在 Python 中,没有什么强制要求它不能返回其他类型的对象。first
和 second
只有在你把它们设置成整数时,它们才是整数。
对象在某种程度上共享一个共同的接口。你可以对它们使用相同的操作符和函数,如果它们支持某个特定的操作,那就可以正常工作。使用不同类型但行为相似的对象互换使用是一种常见且推荐的技巧,这被称为 鸭子类型。举个例子,如果某个函数需要一个 file
对象,你可以传入一个 cStringIO.StringIO
对象,它支持与文件相同的方法(比如 read
和 write
),但它是完全不同的类型。这有点像 Java 的接口,但不需要任何正式的使用方式,你只需要定义合适的方法即可。
你提到的那些字面量对象当然会带着它们自己的类型,所以当一个名字和这个对象绑定时,类型的问题就不存在了——对象总是有类型的,而名字没有类型——它只是把这个责任交给了它绑定的对象。
在 def increase(first, second):
这行代码里,没有什么“推理”的过程——名字 increase
绑定到了一个函数对象上,名字 first
和 second
被记录为参数名,并且在调用 increase
时,会根据情况绑定到不同类型的对象上。
假设函数体是 return first + second
——当你调用 increase('foo', 'bar')
时,它会很高兴地返回 'foobar'
(这里的加法是交给对象处理的,而这些对象在这个例子中是字符串),而如果稍后你调用 increase(23, 45)
,它也会很高兴地返回 68
——同样是把加法交给了在调用时绑定的对象,这次是整数。如果你用不兼容的类型来调用,就会出现异常,因为加法操作无法理解这种情况——这没什么大不了的!