>>Hello,world!,说明你已经成功编写了第一个Python程序,congratulations!上面的“HelloWorld”几乎是学习任何一门新语言的必经之路,正如提出这个程序的SimonCozens所说:“它是编程之神的传统咒语,可以帮助你更好的学" />
现在你可以打开IDLE或PythonWin,新建一个py为扩展名的Python脚本文件,输入以下内容:
代码1:第一个Python程序
1 print "Hello, world!"
保存并运行它,如果输出 >>> Hello, world! ,说明你已经成功编写了第一个Python程序,congratulations!
上面的“Hello World”几乎是学习任何一门新语言的必经之路,正如提出这个程序的Simon Cozens所说:“它是编程之神的传统咒语,可以帮助你更好的学习语言”。
为了比较Python和C#在编码风格等方面的差异,下边给出一个稍复杂些的“Hello, world”程序以及它的C#对照版本。
代码2:唐僧版的Hello, world程序
1 # -*- coding: utf-8 -*-
2 """
3 我的第2个Python程序
4 仅为和C#作对比,谢绝效仿:)
5 """
6 import sys
7 def Main():
8 sys.stdout.write("Hello, world!\\n")
9 #下面的语句看起来很怪,一会我们再解释它是干什么滴
10 if __name__ =="__main__":
11 Main()
注意,代码2第1行# -*- coding: utf-8 -*-,是为了让Python支持中文,这个是必须的。如果你嫌麻烦,可以在IDE里作一个只包含这一行代码的模版文件,以后每次新建Python脚本的时候自动打开这个模版,这样会比较省事。
代码3:C#的对照版本
1 /*
2 我的第1001个C#程序
3 可能还不到,没写过这么多
4 */
5 using System;
6 class Program{
7 static void Main(){
8 if (1==1) //干什么?要搞SQL注入啊?
9 Console.WriteLine("Hello, world!");
10 }
11 }
0.3 认识二者最基本的差异
0.3.1 差异之一:编码风格
比较代码2、3,可以很容易看出两种语言在编码风格上的差异,下面分别来说。
(1)代码块与缩进
C#使用C/C++风格的编码形式,除了要求用{}组织代码块外,语句间的缩进可以是任意的。
Python强制所有程序都有相同的编码风格,它通过缩进来组织代码块。缩进相同的语句被认为是处于同一个代码块中,在if/else等语句及函数定义式末尾会有一个冒号,指示代码块的开始。Python这种强制缩进的做法可以省去{}或者begin/end等,使程序的结构更为清晰(有的人认为恰好相反),同时也减少了无效的代码行数。
此外需要注意,尽量使用4个空格作为Python代码的一个缩进单位,最好不使用Tab,更不要混用Tab和空格,这也算是Python的一个非强制性约定吧。
(2)语句结尾
C#语句用分号结尾,Python不用任何符号(类似BASIC)。
实际上Python也可以使用分号结尾,像这样 a = 1 ; b =2 ; c = 3 ; print a,b,c ,不过Python中这种风格多用于调试,应为你可以很容易注释掉这一行就删除了所有调试代码。
另外,当一行很长时,Python可以用 \\ 符号折行显示代码。
(3)注释方法
C#用//进行单行注释,用/* */进行多行注释;而Python用#符号进行单行注释,用三引号(可单可双)进行多行注释。
(4)条件表达式
C#的条件表达式必须要加括号,见代码3第8行;而Python的条件表达式加不加括号均可(Python程序员一般不加,C/C++/C#程序员一般会加:)
0.3.2 差异之二:入口方法
C#语言必须要有入口方法Main(),这是程序开始执行的地方。
Python语言中没有入口方法(函数),作为解释型的语言,Python代码会自动从头执行(所以在代码2中除了第8行,其它行均属于废话)。
如过你对这点不习惯,可以使用Python代码的内置属性__name__。__name__属性会根据Python代码的运行条件变化:当Python代码以单个文件运行时,__name__便等于"__main__",当你以模块形式导入使用Python代码时,__name__属性便是这个模块的名字。
当然,Python中的__name__属性并不是为了照顾C/C++/C#程序员的编程习惯而准备的,它主要目的是用于模块测试。想象一下在C#中编写一个组件或类代码时,一般还得同时编写一个调用程序来测试它。而Python中可以把二者合二为一,这就是__name__属性的真正作用。
0.3.3 差异之三:import和using
在Python写的代码2中,我们首先import sys,这是导入了Python的sys模块,然后在代码里我们可以引用sys模块中的对象stdout及它的write方法。在Python中这是必须的,否则你无法调用sys模块中的任何东西。
在C#写的代码3中,我们首先using System,这是引入System命名空间,using表明该程序正在使用给定命名空间下的名称(如Console)。对C#这是可选的,如果不事先using System,你可以在代码中使用全限定名,如System.Console.WriteLine。
简单的说,Python中的import相当于C#中的程序集引用。一个程序集可能包括一个或多个命名空间,C#中的using是用来引入命名空间的。Python如果想实现和using类似的功能,就需要用到from import语句。例如对于代码2,可以将import sys改写为from sys import *,这样在程序中就可以直接使用stdout.write了。
最后,import可以出现在代码的任何位置,只要在引用它之前出现就可以。不过为了提高程序可读性,建议还是在所有代码开头书写import。
0.4 小结
作为Python语言的入门,本章没有涉及到过多的编程细节,主要比较了C#与Python两种语言在编码风格等方面最基本的差别,要点如下:
(1)Python使用强制缩进的编码风格,并以此组织代码块;
(2)Python语句结尾不用分号;
(3)Python标明注释用#(单行)或三引号(多行);
(4)Python语言没有入口方法(Main),代码会从头到尾顺序执行;
(5)Python语言用import引入所需要的模块(关于模块和包的具体内容将在第6部分介绍,见文末目录)
以上这几点是C#程序员初学Python时最易犯错误的地方,希望引起大家注意。好了,今天就先到这里。
“一切数据是对象,一切命名是引用”。
如果你能理解这句话,说明对Python的变量与数据类型已经有了不错的认识,那么我建议你直接跳到1.4节的总结部分,看看C#与Python在变量与数据类型方面的差异就可以。如果你还有疑惑,那么就请完整的读一下这一章吧。
好,让我们开始。
1.1 变量声明和定义
1.1.1 变量声明和定义
与C#不同,Python在使用变量之前无须定义它的类型,试着运行下面的例子:
1 i = 1
2 print i
从上边我们可以看到,变量 i 在使用前并不需要定义,但是必须声明以及初始化该变量。试着运行下面的例子:
1 i = 1
2 print i + j
上面的代码会产生一个异常:“NameError: name 'j' is not defined”,Python提示变量 j 没有定义。这点和BASIC等弱类型的语言不一样。在BASIC中,执行上述代码的时候不会产生异常,你可以在EXCEL的VBA开发环境里试一下,把print改为MsgBox就可以,结果会输出 1 。这说明Python并不是一种类似BASIC的弱类型语言。
另一方面,Python与C#有一个很大的差异就是在程序运行过程中,同一变量名可以(在不同阶段)代表不同类型的数据,看看下边的例子:
1 i = 1
2 print i,type(i),id(i)
3 i = 10000000000
4 print i,type(i),id(i)
5 i = 1.1
6 print i,type(i),id(i)
变量 i 的类型在程序执行过程中分别经历了int、long和float的变化,这和静态类型语言(如C等)有很大不同。静态语言只要一个变量获得了一个数据类型,它就会一直是这个类型,变量名代表的是用来存放数据的内存位置。而Python中使用的变量名只是各种数据及对象的引用,用id()获取的才是存放数据的内存位置,我们输入的1、10000000000和1.1三个数据均会保存在id()所指示的这些内存位置中,直到垃圾回收车把它拉走(在系统确定你不再使用它的时候)。这是动态语言的典型特征,它确定一个变量的类型是在给它赋值的时候。
另一方面,Python又是强类型的,试着运行下边的例子:
1 # -*- coding: utf-8 -*-
2 i = 10; j = 'ss'
3 print i+j
4 #正确的写法是print str(i)+j,输出10ss
会产生一个异常:“TypeError: unsupported operand type(s) for +: 'int' and 'str'”。在BASIC等弱类型的语言中,上边的例子会正常运行并返回(虽然有时候是不可预期的)结果。
所以,我们说Python既是一种动态类型语言,同时也是一种强类型的语言,这点是和C#不同的地方。对于Python的这种变量的声明、定义和使用方式,C#程序员可能要花一段时间去适应,不过相信你会很快就喜欢上它,因为它让事情变得更加简单(而且不会不安全)。而且,C# 4.0 已经开始用类似的方式定义和使用变量(通过在变量名前加关键字dynamic),如果你先学了Python,将能够更快的适应C# 4.0的动态编程特征。
1.1.2 变量的命名规则
Python与C#的变量(以及函数、类等其它标识符)的命名规则基本一样,同样对大小写敏感。不一样的地方是,Python中以下划线开始或者结束的标识符通常有特殊的意义。例如以一个下划线开始的标识符(如 _foo)不能用from module import *语句导入。前后均有两个下划线的标识符,如__init__,被特殊方法保留。前边有两个下划线的标识符,如__bar,被用来实现类私有属性,这个将在“类和面向对象编程”中再说。
最后,Python的关键字不能作为标识符(这个大家都知道),不过Python的关键字比C#要少得多,可以google一下,这里就不列出了。
1.1.3 常量
Python没有常量,如果你非要定义常量,可以引入const模块(我没用过,在C#中我也很少用常量)。
1.2 简单数据类型
Python 程序中的一切数据都是对象,包括自定义对象及基本数据类型。这点和C#一样,它们都是完全面向对象的语言,所以我想C#程序员会很容易理解Python的“一切数据是对象”这个口号。
与C#不同的是,Python不区分值类型和引用类型,你可以把所有的类型都理解为C#的引用类型(当然,它们的实现方式是不一样的,这里只是一个类比)。
Python内建的数据类型有20多种,其中有些不常用到,有些即将被合并。本文将主要介绍空类型、布尔类型、整型、浮点型和字符串、元组、列表、集合、字典等9种Python内置的数据类型。
在这里,我将前4种称为“简单数据类型”,将后5种称为“高级数据类型”,实际上Python语言本身没有这种叫法,这样分类是我自己设定的,主要是为了和C#中的相关概念对照方便,希望不要误导大家。
1.2.1 空类型
空类型(None)表示该值是一个空对象,比如没有明确定义返回值的函数就返回None。空类型没有任何属性,经常被用做函数中可选参数的默认值。None的布尔值为假。
Python的None和C#中的可空类型Nullable 1.2.2 布尔类型 Python中用True和False来定义真假,你可以直接用 a = True或 a = False来定义一个布尔型变量。但在Python 2.6里,True、False以及None却都不是关键字,在Python 3.0里它们已经是关键字了,这个有点乱,我们可以不用管它,直接使用就OK了。 注意和C#不同的是,Python中True和False的首字母要大写。 最后一点,在C#中布尔类型和其他类型之间不存在标准的转换。但在Python中,None、任何数值类型中的0、空字符串''、空元组()、空列表[]、空字典{}都被当作False,其他对象均为True,这点和C++差不多,要提起注意。请思考一下,下面的Python代码会输出什么? 1 if 0: 2 print 'True' 3 else: 4 print 'False' 1.2.3 数值类型 Python拥有四种数值类型:整型,长整型,浮点类型以及复数类型。 整数类型(int)用来表示从-21474838 到 21474837之间的任意整数(在某些电脑系统上这个范围可能会更大,但绝不会比这个更小);长整数(long)可以表示任意范围的整数。实际上我们把Python的long和int理解为同一种类型就可以了,因为当一个整数超过int的范围后,Python会自动将其升级为长整型。所以,请忘掉C#中的byte、sbyte、short、ushort、int、uint、long和ulong吧,Python只有一种整数。 Python中只有位双精度浮点数,与C#中的double类型相同(注意在Python中浮点数类型名字是float而不是double),Python不支持32位单精度的浮点数。 除了整数和实数,Python还提供了C#中不支持(当然可以通过自定义类来扩展)的一种数据类型:复数(complex)。复数使用一对浮点数表示,复数z的实部和虚部分别用z.real和z.imag访问。 在数值运算中,整数与浮点数运算的结果是浮点数,这就是所谓的“提升规则”,也就是“小”类型会被提升为“大”类型参与计算。这一点与C#是一样的,提升的顺序依次为:int、long、 float、complex。 作为数值类型的最后一个问题,C#程序员需要注意的是,Python没有内建decimal类型,但可以导入decimal模块用来完成与货币处理相关的计算。 1.3 高级数据类型 1.3.1 序列(字符串、列表和元组) Python中的序列是由非负整数索引的对象的有序集合(真拗口,其实意思就是下标从0开始),它包括字符串、Unicode字符串、列表、元组、xrange对象以及缓冲区对象。后两种类型我们先不介绍,后边用到时再说明。 1.3.1.1 字符串类型 Python拥有两种字符串类型:标准字符串(str)是单字节字符序列,Unicode字符串(unicode)是双字节字符序列。 在Python中定义一个标准字符串(str)可以使用单引号、双引号甚至三引号,这使得Python输入文本比C#更方便。比如当str的内容中包含双引号时,就可以用单引号定义,反之亦然。当字符中有换行符等特殊字符时,可以直接使用三引号定义。这样就方便了很多,不用去记那些乱七八糟的转义字符。当然Python也支持转义字符,且含义和C#基本一样。不过既然有简单的东西用,谁还去自找麻烦呢? 下边是一个例子,来说明以上几点: 1 str1 = 'I am "Python"\\n' 2 str2 = "I am 'Python'\\r" 3 str3 = """ 4 I'm "Python 6 """ #你可以把html代码之类的东西直接弄进来而不需要做特殊处理 7 print str1,str2,str3 在Python中定义一个Unicode字符串,需要在引号前面加上一个字符u,例如 1 # -*- coding: utf-8 -*- 2 print u'我是派森' 这点没有C#方便,因为C#字符串默认就是Unicode的,我想Python如果要改进,应该把两种字符串合二为一,这样可以为初学者减少很多麻烦(你看网上有多少帖子是在问Python怎么支持中文?根源都在这里)。同时注意,当使用utf-8编码时,非unicode字符中一个汉字的长度是3,而使用gb2312时是2,见下边代码: 1 # -*- coding: utf-8 -*- 2 unicode = u'我' 3 str = '我' 4 print len(unicode),len(str) 5 #输出 1 3 6 7 # -*- coding: gb2312 -*- 8 unicode = u'我' 9 str = '我' 10 print len(unicode),len(str) 11 #输出 1 2 另外,Python没有C#中的字符类型,再短的文本也是字符串,这点稍微注意一下就可以,因为现在使用C#的也很少用char了吧? 最后,关于字符串的操作方法,基本上C#有的Python都有,可以看看Python手册之类的资料,我就不多说了。唯一提一点就是在Python中提取一个字符串的子串时,记得用“切片”语句(后边讲列表和元组时还会介绍),而不要再去找SubString了,见下边的例子: 1 # -*- coding: utf-8 -*- 2 str1 = u'我是派森' 3 print str1[2:4] 4 #输出 '派森' 1.3.1.2 列表(list) Python中的列表(list)类似于C#中的可变数组(ArrayList),用于顺序存储结构。 列表用符号[]表示,中间的元素可以是任何类型(包括列表本身,以实现数组),元素之间用逗号分隔。取值或赋值的时候可以像C数组一样,按位置索引: 1 # -*- coding: utf-8 -*- 2 array = [1,2,3] 3 print array[0] 4 #输出 1 5 array[0] = 'a' 6 print array 7 #输出 ['a', 2, 3] 从上边的代码中你可能发现一个有趣的事情:在Python的列表中可以混合使用不同类型的数据,像['a', 2, 3]这样,不过我不建议你这样做,我觉得没什么好处(虽然个别场合下可能会比较方便)。 另外还可以看到,列表是可变的序列,也就是说我们可以在“原地”改变列表上某个位置所存储的对象(的值)。 C#中ArrayList支持的多数操作(如追加、插入、删除、清空、排序、反转、计数等),Python中的list也都支持,同时list也支持“切片”这种操作。切片指的是抽取序列的一部分,其形式为:list[start:end:step]。其抽取规则是:从 start开始,每次加上step,直到end为止。默认的step为1;当start 没有给出时,默认从list 的第一个元素开始;当end=-1 时表示list 的最后一个元素,依此类推。一些简单的例子见下边代码: 1 # -*- coding: utf-8 -*- 2 test = ['never', 1, 2, 'yes', 1, 'no', 'maybe'] 3 print test[0:3] # 包括test[0],不包括test[3] 4 print test[0:6:2] # 包括test[0],不包括test[6],而且步长为2 5 print test[:-1] # 包括开始,不包括最后一个 6 print test[-3:] # 抽取最后3 个 字符串、列表、元组都支持切片操作,这个很方便,应该学会熟练使用它。 最后,list是Python中最基础的数据结构,你可以把它当作链表、堆栈或队列来使用,效率还不错。Python中没有固定长度数组,如果你确实很在意性能,可以导入array模块来创建一个C风格的数组,它的效率很高,这里就不详细介绍了。 1.3.1.3 元组(tuple) 元组与列表非常相似,它是用()而不是[]括起来的序列。元组比列表的速度更快,但元组是一个不可变的序列,也就是与str一样,无法在原位改变它的值。除此之外,其他属性与列表基本一致。 元组定义的方法与列表类似,不过在定义只包含一个元素的元组时,注意在后边加一个逗号。请体会以下几句语句的差异: 1 # -*- coding: utf-8 -*- 2 test = [0] #列表可以这样定义 3 print type(test) #输出 4 test = [0,] #也可以这样定义 5 print type(test) #输出 6 test = (0,) #元组可以这样定义 7 print type(test) #输出 8 test = (0) #但不能这样定义,Python会认为它是一个括号表达式 9 print type(test) #输出 10 test = 0, #也可以省略括号,但要注意与C的逗号表达式不同 11 print type(test) #输出 利用元组的这个特性,可以简化Python变量的初始化过程,如: 1 x,y,z=1,2,3 还可以很简单地进行数据交换。比如: 1 a = 1 2 b = 2 3 a,b = b,a 以上这类语句在Python中被广泛应用于变量交换、函数传值等应用,因此Python的解释器在不断对其进行优化,现在已经具备了相当高的效率。所以以上代码在Python 2.5以后的版本中,比tmp = a; a = b; b = tmp这种常规语句更快。 1.3.2 集合(set) Python中的set和C#中的集合(collection)不是一个概念,这是翻译的问题。Python中的集合是指无序的、不重复的元素集,类似数学中的集合概念,可对其进行交、并、差、补等逻辑运算。 常见集合的语法为:s = set(['a', 'b', 'c'])。不过set在Python 3.0中发生了较大的变化,创建一个集合的语法变成了:s = {1,2,3},用花括弧的方法,与后边要提到的dict类似。 如果在set中传入重复元素,集合会自动将其合并。这个特性非常有用,比如去除列表里大量的重复元素,用set解决效率很高,示例如下: 1 # -*- coding: utf-8 -*- 2 a = [11,22,33,44,11,22,11,11,22,22,33,33,33] 3 b = set(a) 4 print b 5 #输出 set([33, 11, 44, 22]) 另一个例子,找出两个list里面相同的元素(集合求交,其它类推),代码如下: 1 # -*- coding: utf-8 -*- 2 a = ["11","22","33"] 3 b = ["11","33"] 4 c = set(a)&set(b) 5 print c 6 #输出 set(['11', '33']) 想想你如果自己实现这个算法会怎么写?然后可以找两个大一点的列表,比比和set实现的效率,你就会有体会了。以后在程序里多用set吧。 目前C#的Collections中好像还没有Set,但是C++ STL里是有的,不知道C#为什么不实现这个有趣的东西。 1.3.3 字典(dict) 用过C#中Collections的人对Hashtable应该不会陌生,Python里的哈希表就是字典(dict)了。与set类似,字典是一种无序存储结构,它包括关键字(key)和关键字对应的值(value)。 C#程序员需要了解的就是,在Python中dict是一种内置的数据类型,定义方式为:dictionary = {key:value},当有多个键值对时,使用逗号进行分割。 字典里的关键字为不可变类型,如字符串、整数、只包含不可变对象的元组,列表等不能作为关键字。字典中一个键只能与一个值关联,对于同一个键,后添加的值会覆盖之前的值。 学过数据结构的人对字典的散列查找效率应该都有认识,所以我建议在可能的情况下尽量多用字典,其它的就不多写了。关于Python中dict类型(以及list、tuple、set)提供的主要方法,可以参考专门介绍Python的各种书籍,大多会提供一个详细的方法列表。 1.4 小结 本章讨论了Python中变量和数据类型的使用方法,要点如下: (1) Python是一种动态的强类型语言,在使用变量之前无须定义其类型,但是必须声明和初始化; (2) “一切命名是引用”,Python中变量名是对象的引用,同一变量名可以在程序运行的不同阶段代表不同类型的数据; (3) “一切数据是对象”,Python的所有数据类型都是对象,(相较C#)具有一致的使用方法; (4) “把问题想得更简单一点”,Python的数值类型可以说只有两种:整形和浮点,忘掉C#里的各种数值类型吧; (5) 注意区别str和unicode,Python的字符串类型有时候会让人发晕,请试着习惯它,另外不要忘了“切片”这个好工具。 (6) 多使用list, tuple, set 和 dict这几种“很Python”的数据类型,它们分别用[]、()、([])和{}定义。 好了,本章的内容我觉得已经介绍的有点过多了,我们先说到这一步,类型的操作符等内容我将在下一章《运算符、表达式和流程控制》里介绍。至于对象的深拷贝、浅拷贝等,为了不上来就把大家搞迷糊,我就不再写了。这方面的资料也很多,文末列了一些推荐读物,希望对你有所帮助。