Python是强类型的吗?

时间:2012-07-04 12:16:01

标签: python strong-typing weak-typing

我遇到过一些链接,说Python是一种强类型语言。

但是,我认为在强类型语言中你不能这样做:

bob = 1
bob = "bob"

我认为强类型语言在运行时不接受类型更改。也许我对强/弱类型的定义错误(或过于简单)。

那么,Python是一种强类型还是弱类型的语言?

11 个答案:

答案 0 :(得分:314)

Python是强有力的,动态类型的。

  • 键入意味着值的类型不会以意外方式更改。只包含数字的字符串不会神奇地变成一个数字,就像Perl中可能发生的那样。每次类型更改都需要明确转换。
  • 动态类型意味着运行时对象(值)具有类型,而不是静态类型,其中变量具有类型。

至于你的例子

bob = 1
bob = "bob"

这是有效的,因为变量没有类型;它可以命名任何对象。在bob=1之后,您会发现type(bob)返回int,但在bob="bob"之后,它会返回str。 (注意type是一个常规函数,因此它会计算其参数,然后返回值的类型。)

将此与C的旧方言进行对比,这些方言是弱的,静态类型的,因此指针和整数几乎可以互换。 (在许多情况下,现代ISO C需要转换,但默认情况下我的编译器对此仍然宽容。)

我必须补充一点,强类型和弱类型更像是一个连续统一体而非布尔选择。 C ++具有比C更强的类型(需要更多转换),但类型系统可以通过使用指针强制转换来破坏。

动态语言(如Python)中类型系统的强度实际上取决于其原语和库函数如何响应不同类型。例如,+被重载,因此它适用于两个数字两个字符串,但不是字符串和数字。这是在实现+时做出的设计选择,但从语言的语义开始并不是必需的。实际上,当您在自定义类型上重载+时,可以将其隐式转换为数字:

def to_number(x):
    """Try to convert x to a number."""
    if x is None:
        return 0
    # more special cases here
    else:
        return float(x)  # works for numbers and strings

class Foo(object):
    def __add__(self, other):
        other = to_number(other)
        # now do the addition

(我所知道的唯一一种完全强类型的语言,也就是严格类型,是Haskell,其中类型完全不相交,只有通过类型类才可以控制形式的重载。)

答案 1 :(得分:48)

我认为所有现有答案都遗漏了一些重要问题。


弱类型意味着允许访问底层表示。在C中,我可以创建一个指向字符的指针,然后告诉编译器我想将它用作指向整数的指针:

char sz[] = "abcdefg";
int *i = (int *)sz;

在具有32位整数的小端平台上,这会使i成为数字0x646362610x00676665的数组。实际上,您甚至可以将指针自身转换为整数(大小合适):<​​/ p>

intptr_t i = (intptr_t)&sz;

当然,这意味着我可以在系统中的任何地方覆盖内存。*

char *spam = (char *)0x12345678
spam[0] = 0;

*当然现代操作系统使用虚拟内存和页面保护,所以我只能覆盖自己的进程内存,但是C本身并没有提供这样的保护,正如任何编码过的人,比如Classic Mac OS或Win16都可以告诉你。

传统的Lisp允许类似的hackery;在某些平台上,双字浮点数和缺点单元格是相同的类型,你可以将一个传递给一个期望另一个的函数,它将会工作&#34;。

今天的大多数语言并不像C和Lisp那样弱,但其中许多语言仍然有些漏洞。例如,任何具有未选中&#34; downcast&#34;,*类型泄漏的OO语言:您实际上是在告诉编译器&#34;我知道我没有给出你有足够的信息知道这是安全的,但我很确定它是,&#34;当类型系统的整个要点是编译器总是有足够的信息来知道什么是安全的。

*检查向下转换并不会使语言类型系统变弱,只是因为它将检查移动到运行时。如果确实如此,那么子类型多态(也称为虚拟或全动态函数调用)将违反类型系统,我不认为有人想这么说。

很少&#34;脚本编写&#34;语言在这个意义上很弱。即使在Perl或Tcl中,你也不能取一个字符串,只是把它的字节解释为一个整数。*但是值得注意的是在CPython中(对于许多语言的许多其他解释器也是如此),如果你和#39;非常执着,您可以使用ctypes加载libpython,将对象id投放到POINTER(Py_Object),并强制使用类型系统泄漏。这是否会使类型系统变弱取决于您的使用案例 - 如果您尝试实施一个语言内限制执行沙箱以确保安全性,那么您必须处理这些类型的逃逸......

*您可以使用像struct.unpack这样的函数来读取字节并构建一个新的int&#34; C将如何表示这些字节&#34;,但很明显没有漏;甚至Haskell允许这样做。


与此同时,隐式转换与弱型或漏型系统实际上是不同的。

每种语言,甚至是Haskell,都具有将整数转换为字符串或浮点数的功能。但是有些语言会自动为你做一些转换 - 例如,在C中,如果你调用一个需要float的函数,并且你在int中传递它,它就会为你转换。这肯定会导致例如意外溢出的错误,但它们与弱类型系统中的错误不同。而且C在这里真的没有任何弱点;你可以在Haskell中添加一个int和一个float,或者甚至将一个float连接到一个字符串,你只需要更明确地做它。

使用动态语言,这非常模糊。没有&#34;一个想要浮动的功能&#34;在Python或Perl中。但是有重载函数可以使用不同类型执行不同的操作,并且具有强烈的直观感觉,例如,将字符串添加到其他内容是&#34;需要字符串&#34;的函数。从这个意义上说,Perl,Tcl和JavaScript似乎做了很多隐式转换("a" + 1给你"a1"),而Python做得少很多("a" + 1引发异常,但是1.0 + 1确实为您提供了2.0 *)。很难将这种意义理解为正式术语 - 为什么不应该有一个带有字符串和int的+,当有明显的其他功能(如索引)时呢?

*实际上,在现代Python中,可以用OO子类型来解释,因为isinstance(2, numbers.Real)是真的。我不认为2是Perl或JavaScript中字符串类型的实例有任何意义......虽然在Tcl中,它实际上是,因为所有是字符串的实例。


最后,还有另一个完全正交的定义&#34; strong&#34; vs.&#34;弱&#34;打字,在哪里&#34;强&#34;意味着强大/灵活/富有表现力。

例如,Haskell允许您定义一个类型,包括数字,字符串,此类型的列表,或从字符串到此类型的映射,这是表示可以从中解码的任何内容的完美方式JSON。没有办法在Java中定义这样的类型。但至少Java具有参数(通用)类型,因此您可以编写一个函数,该函数采用List of T并知道元素是T类型的;其他语言,如早期Java,强迫您使用对象列表和向下转换。但至少Java允许您使用自己的方法创建新类型; C只允许您创建结构。 BCPL甚至没有这个。依此类推到汇编,其中唯一的类型是不同的位长。

因此,从这个意义上说,Haskell的类型系统比现代Java更强大,它比早期的Java更强大,后者比C更强,后者更强大。而不是BCPL的。

那么,Python在哪里适合该频谱?这有点棘手。在许多情况下,鸭子打字可以让你模拟你在Haskell中可以做的一切,甚至是你可以做的一些事情。确定,错误是在运行时而不是编译时捕获的,但它们仍然被捕获。但是,有些情况下鸭子打字是不够的。例如,在Haskell中,您可以告诉一个空的int列表是一个int列表,因此您可以决定减少该列表上的+应返回0 *;在Python中,空列表是一个空列表;没有类型信息可以帮助您决定减少+应该做什么。

*事实上,Haskell并不允许你这样做;如果你调用的reduce函数没有在空列表中取一个起始值,则会出现错误。但它的类型系统足够强大,你可以使这项工作,并且Python不是。

答案 2 :(得分:31)

您将'strongly typed''dynamically typed'混淆。

我无法通过添加字符串1来更改'12'的类型,但我可以选择存储在变量中的类型,并在程序运行时更改它。

动态类型的反面是静态类型;变量类型的声明在程序的生命周期内不会改变。强类型的反面是弱打字; 的类型可以在程序的生命周期内更改。

答案 3 :(得分:24)

根据这篇wiki Python文章,Python是动态和强类型的(也提供了一个很好的解释)。

也许您正在考虑 statically typed 语言,其中类型在程序执行期间无法更改,并且在编译期间发生类型检查以检测可能的错误。

这个问题可能很有意思:Dynamic type languages versus static type languages这篇关于Type Systems的维基百科文章提供了更多信息

答案 4 :(得分:13)

TLDR;

Python的输入是动态,因此您可以将int变量更改为字符串

x = 'somestring'
x = 50

Python输入,因此您无法合并类型:

'x' + 3 --> TypeError: cannot concatenate 'str' and 'int' objects

在弱类型的Javascript中会发生这种情况......

 'x'+3 = 'x3'

关于类型推断

Java强制您显式声明对象类型

int x = 50

Kotlin使用推理来实现它int

x = 50

但由于两种语言都使用静态类型,因此无法从x更改int。两种语言都不允许动态更改,如

x = 50
x = 'now a string'

答案 5 :(得分:8)

已经有几次回答,但Python是一种强类型语言:

>>> x = 3
>>> y = '4'
>>> print(x+y)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'

JavaScript中的以下内容:

var x = 3    
var y = '4'
alert(x + y) //Produces "34"

这是弱打字和强打字之间的区别。弱类型会自动尝试从一种类型转换为另一种类型,具体取决于上下文(例如Perl)。强类型从不隐式转换。

您的困惑在于误解了Python如何将值绑定到名称(通常称为变量)。

在Python中,名称没有类型,因此您可以执行以下操作:

bob = 1
bob = "bob"
bob = "An Ex-Parrot!"

名字可以绑定任何东西:

>>> def spam():
...     print("Spam, spam, spam, spam")
...
>>> spam_on_eggs = spam
>>> spam_on_eggs()
Spam, spam, spam, spam

进一步阅读:

https://en.wikipedia.org/wiki/Dynamic_dispatch

和稍微相关但更高级:

http://effbot.org/zone/call-by-object.htm

答案 6 :(得分:6)

Python变量存储对表示该值的目标对象的无类型引用。

任何赋值操作都意味着将无类型引用赋值给指定的对象 - 即通过原始和新的(计数)引用共享对象。

值类型绑定到目标对象,而不是绑定到参考值。当执行具有该值的操作(运行时间)时,完成(强)类型检查。

换句话说,变量(技术上)没有类型 - 如果想要精确的话,根据变量类型进行思考是没有意义的。但引用会自动解除引用,我们实际上会考虑目标对象的类型。

答案 7 :(得分:6)

术语&#34;强类型&#34;没有明确的定义。

因此,该术语的使用取决于您与谁说话。

我不考虑任何语言,其中变量的类型既没有显式声明,也没有静态类型强类型。

强类型并不会阻止转换(例如,&#34;自动&#34;从整数转换为字符串)。它排除了分配(即改变变量的类型)。

如果以下代码编译(解释),则语言不是强类型的:

Foo = 1 Foo =&#34; 1&#34;

在强类型语言中,程序员可以依靠&#34;一种类型。

例如,如果程序员看到声明,

UINT64 kZarkCount;

并且他或她知道20行之后,kZarkCount仍然是UINT64(只要它出现在同一个块中) - 无需检查干预代码。

答案 8 :(得分:0)

我认为,这个简单的例子应该解释强类型和动态类型之间的差异:

>>> tup = ('1', 1, .1)
>>> for item in tup:
...     type(item)
...
<type 'str'>
<type 'int'>
<type 'float'>
>>>

的java:

public static void main(String[] args) {
        int i = 1;
        i = "1"; //will be error
        i = '0.1'; // will be error
    }

答案 9 :(得分:0)

我刚刚发现了一种精巧的记忆方式:

  

动态/静态类型的表达式;强/弱类型的值。

答案 10 :(得分:-4)

class testme(object):
    ''' A test object '''
    def __init__(self):
        self.y = 0

def f(aTestMe1, aTestMe2):
    return aTestMe1.y + aTestMe2.y




c = testme            #get a variable to the class
c.x = 10              #add an attribute x inital value 10
c.y = 4               #change the default attribute value of y to 4

t = testme()          # declare t to be an instance object of testme
r = testme()          # declare r to be an instance object of testme

t.y = 6               # set t.y to a number
r.y = 7               # set r.y to a number

print(f(r,t))         # call function designed to operate on testme objects

r.y = "I am r.y"      # redefine r.y to be a string

print(f(r,t))         #POW!!!!  not good....

上述将在很长一段时间内在大型系统中造成难以维护的代码的噩梦。称之为你想要的,但“动态”改变变量类型的能力只是一个坏主意......