设为首页 收藏本站
查看: 1915|回复: 0

[经验分享] 从C#到Python —— 1 变量和数据类型

[复制链接]

尚未签到

发表于 2015-4-20 11:29:07 | 显示全部楼层 |阅读模式
  “一切数据是对象,一切命名是引用”。
  如果你能理解这句话,说明对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类似,比如C#可以定义Nullable i = null,与Python的空类型类似,但实现原理和用途都不一样。

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)用来表示从-2147483648 到 2147483647之间的任意整数(在某些电脑系统上这个范围可能会更大,但绝不会比这个更小);长整数(long)可以表示任意范围的整数。实际上我们把Python的long和int理解为同一种类型就可以了,因为当一个整数超过int的范围后,Python会自动将其升级为长整型。所以,请忘掉C#中的byte、sbyte、short、ushort、int、uint、long和ulong吧,Python只有一种整数。
  Python中只有64位双精度浮点数,与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",
5 you are C#
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”的数据类型,它们分别用[]、()、([])和{}定义。
  好了,本章的内容我觉得已经介绍的有点过多了,我们先说到这一步,类型的操作符等内容我将在下一章《运算符、表达式和流程控制》里介绍。至于对象的深拷贝、浅拷贝等,为了不上来就把大家搞迷糊,我就不再写了。这方面的资料也很多,文末列了一些推荐读物,希望对你有所帮助。
  
最后,在这里发一个短小的声明:从今天开始,《从C#到Python》改为一周更新一篇。因为我3月1日就开学了,马上要上课、备课和带毕业设计,所以只能利用周末来写博。为了能尽快写完这个连载,我对章节也进行了一些调整,去掉了原计划中的I/O一章,因为这部分很简单,写出来可能导致章节间不均衡。这样就只剩下了4章(表达式、函数、类和模块),我计划在1个月之内写完。如果想速成Python,推荐你去看看假正经哥哥(这名叫的!)整理的一个《Python快速参考指南》,可谓是“一图在手,江山我有”啊:)
  
  进一步阅读的参考:
  [1]关于动态语言、静态语言、强类型语言、弱类型语言的概念,可参考《深入 Python :Dive Into Python 中文版》的2.2.1.“ Python 和其他编程语言数据类型的比较”;
  [2]如果你还没接触到C# 4.0,可以看看《c# 4.0新特性一览》,我觉得C#越变越像Python了。
  [3]关于Python中各种数据类型的详细介绍,请参考《可爱的Python》一书中的PCS101“内建数据类型”和《Python 精要参考(第二版)》的第三章“类型和对象”,本章的写作也主要参考的是这两本书,在此特向原作者(及译者)致谢。
  [4]关于类型与对象的高级内容,推荐你看看《Python核心编程(中文第二版)》的第4章“Python对象”,这个有点难,好多东西我还没看懂,呵呵。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-58794-1-1.html 上篇帖子: Python调用WebService 下篇帖子: Python学习系列(一)(基础入门)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表