Python强类型?

我遇到过说Python是强类型语言的链接。

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

bob = 1 bob = "bob" 

我认为强类型语言在运行时不接受类型转换。 也许我有一个错误的(或太简单)强/弱类型的定义。

那么,Python是强类型还是弱类型?

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,类型完全不相交,只有受控的重载类型可以通过类型类来实现。

有一些重要的问题,我认为所有现有的答案已经错过了。


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

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

在一个32位整数的小端平台上,这使i成为一个数组0x646362610x00676665 。 实际上,你甚至可以把指针本身转换为整数(具有合适的大小):

 intptr_t i = (intptr_t)&sz; 

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

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

*当然现代操作系统使用虚拟内存和页面保护,所以我只能覆盖我自己的进程的内存,但没有任何关于C本身提供这种保护,任何人谁曾经编码,如经典的Mac OS或Win16可以告诉你。

传统的Lisp允许类似的骇客; 在一些平台上,双字浮动和反单元是相同的类型,你可以通过一个函数来期待另一个,它会“工作”。

今天的大多数语言都不如C和Lisp那么弱,但是其中许多语言仍然有点漏洞。 例如,任何OO语言都有一个未经检查的“downcast”,*这是一个类型泄漏:你基本上告诉编译器“我知道我没有给你足够的信息来知道这是安全的,但我很确定它是,“当一个类型系统的全部重点是编译器总是有足够的信息来知道什么是安全的。

*检查downcast不会使语言的类型系统更弱,只是因为它将检查移动到运行时。 如果是这样,那么子类型多态(又名虚拟或全动态函数调用)将是类型系统的相同的违反,我不认为有人想这样说。

在这个意义上,很少有“脚本”语言是弱的。 即使在Perl或Tcl中,也不能取一个字符串,而只是把它的字节解释为一个整数。但是值得注意的是,在CPython中(对许多其他语言的解释器也是如此),如果你真的执着,可以使用ctypes加载libpython ,将对象的id转换为POINTER(Py_Object) ,强制类型系统泄漏。 这是否会使类型系统变弱取决于你的使用情况 – 如果你正在试图实现一个语言上受限制的执行沙箱来确保安全,你必须处理这些类型的转义…

*你可以使用像struct.unpack这样的函数来读取字节,并用“C如何表示这些字节”来构建一个新的int,但这显然不是泄漏; 即使是Haskell也可以。


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

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

而动态语言,这是非常模糊的。 Python或Perl中没有“需要float的函数”这样的东西。 但是有一些重载的函数会对不同的类型做不同的事情,并且有一种强烈的直觉,例如,将字符串添加到别的东西上就是“需要字符串的函数”。 从这个意义上说,Perl,Tcl和JavaScript似乎做了很多隐式转换( "a" + 1给你"a1" ),而Python做的更少( "a" + 1引发异常,但是1.0 + 1确实给你2.0 *)。 为什么不应该有一个接受一个字符串和一个整数的+ ,当有明显的其他功能,比如索引,呢?

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


最后,还有另一个完全正交的“强”与“弱”打字的定义,其中“强”意味着强大/灵活/表现力。

例如,Haskell可以让你定义一个类型,它是一个数字,一个字符串,这种类型的列表,或者一个从字符串到这种类型的映射,这是一种完美的方式来表示任何可以从JSON解码的东西。 没有办法在Java中定义这种类型。 但至少Java有参数(泛型)类型,所以你可以编写一个函数来获取T的List,并知道这些元素是T类型的; 其他语言,比如早期的Java,就迫使你使用对象列表并向下转换。 但是至少Java可以让你用自己的方法创建新的类型; C只能让你创建结构。 BCPL甚至没有这个。 等到装配,只有类型是不同的位长度。

所以,从这个意义上讲,Haskell的类型系统比现代的Java更强大,比早期的Java更强大,比C的强于BCPL。

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

*实际上,Haskell不会让你这样做; 如果您调用不在空列表上使用起始值的reduce函数,则会出现错误。 但是它的类型系统是足够强大的,你可以使这个工作,Python的不是。

您将“强类型”与“动态类型”混淆。

我不能通过添加字符串'12'来改变1的类型,但是我可以选择存储在一个变量中的类型,并在程序运行期间改变它。

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

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

也许你正在考虑在程序执行期间类型不能改变的静态类型语言,并且在编译期间发生类型检查以检测可能的错误。

这个SO问题可能是有趣的: 动态类型语言与静态类型语言和这个维基百科关于类型系统的文章提供了更多的信息

它已经被回答了几次,但是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

一个Python变量存储一个到目标对象的无类型引用,表示值。

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

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

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

“强打字”一词没有明确的定义。

因此,这个词的使用取决于你在说谁。

我不认为任何语言,其中变量的类型不明确声明,或静态类型为强类型。

强类型不仅仅是阻止转换(例如,“自动”从一个整数转换为一个字符串)。 它排除了分配(即,改变变量的类型)。

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

Foo = 1 Foo =“1”

在强类型语言中,程序员可以“依靠”一个类型。

例如,如果一个程序员看到这个声明,

UINT64 kZarkCount;

他或她知道20行后,kZarkCount仍然是一个UINT64(只要它出现在同一个块),而不必检查干预代码。

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' 

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

 >>> 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 } 
 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 cx = 10 #add an attribute x inital value 10 cy = 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 ty = 6 # set ty to a number ry = 7 # set ry to a number print(f(r,t)) # call function designed to operate on testme objects ry = "I am ry" # redefine ry to be a string print(f(r,t)) #POW!!!! not good.... 

上述情况会在很长一段时间内在大系统中造成不可维护代码的噩梦。 调用它你想要的,但“动态”改变变量类型的能力是一个坏主意……

Interesting Posts