Python FreshMan

★☆ Python新手的Blog ☆★
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

从C#到Python —— 2 运算符、表达式和流程控制

Posted on 2010-03-05 13:47  闫小勇  阅读(8163)  评论(10编辑  收藏  举报

本章介绍Python的运算符、表达式、程序流程控制语句以及异常处理语句,在这方面,Python和C#是非常类似的,我们仅需要注意它们之间的一些细微差异。另外,在本章我还会简要介绍Python语言中的两项有趣功能——列表内涵和动态表达式,虽然它们严格来说属于函数部分的内容,不过我觉得还是放在表达式一章比较合适。

2.1  运算符和表达式

无论使用什么语言,我们编写的大多数代码(逻辑行)都包含表达式。一个表达式可以分解为运算符和操作数,运算符的功能是完成某件事,它们由一些数学运算符号或者其他特定的关键字表示;运算符需要数据来进行运算,这样的数据被称为操作数。例如,2 + 3是一个简单的表达式,其中+是运算符,2和3是操作数。

2.1.1  算术运算符与算术表达式

算术运算符是程序设计语言最基本的运算符。Python提供的算术运算符除了+、-、*、/、%(求余)之外,还提供了两种C#中未提供的运算符:求幂(**)和取整除(//)。下面我们通过一段代码来理解这两个算术运算符:

1 #-*-coding:utf-8-*-
2  x = 3.3
3 y = 2.2
4 a = x**y
5  print a
6  #输出13.827086118,即3.3的2.2次幂,在C#中可用Pow方法实现幂运算
7  b = x//y
8  print b
9  #输出1.0,取整除返回商的整数部分
10  c = x/y
11  print c
12  #输出1.5,注意体会普通除与取整除的区别

2.1.2  赋值运算符与赋值表达式

赋值就是给一个变量赋一个新值,除了简单的 = 赋值之外,Python和C#都支持复合赋值,例如x += 5,等价于 x = x + 5。

Python不支持C#中的自增和自减运算符,例如x++这种语句在Python中会被提示语法错误。C#程序员可能用惯了这种表达方式(要不为什么叫C++++呢),在Python中,请老老实实的写x += 1就是了。

2.1.3  逻辑运算符与逻辑表达式

Python的逻辑运算符与C#有较大区别,Python用关键字and、or、not代替了C#语言中的逻辑运算符&&、||和! ,此外Pyhton中参与逻辑运算的操作数不限于布尔类型,任何类型的值都可以参与逻辑运算,参见1.2.2节(布尔类型)的讨论。

用逻辑运算符将操作数或表达式连接起来就是逻辑表达式。与C#一样,Python中的逻辑表达式是“短路”执行的,也就是说只有需要时才会进行逻辑表达式右边值的计算,例如表达式 a and b 只有当a为True时才计算b。思考一下,if (0 and 10/0): 这条语句会引发除数为零的异常吗?

此外还要注意:在Python 中,and 和 or 所执行的逻辑运算并不返回布尔值,而是返回它们实际进行比较的值之一。下边是一个例子:

1 print 'a' and 'b'
2  #输出b
3  print '' and 'b'
4  #输出空串

2.1.4  关系运算符与关系表达式

关系运算实际上是逻辑运算的一种,关系表达式的返回值总是布尔值。Python中的比较操作符与C#是完全一样的,包括==、!=、>、<、>=和<=共6种。

除了基本的变量比较外,Python的关系运算符还包括身份运算符is。在Python中,is用来检验两个对象在内存中是否指向同一个对象(还记得“一切数据皆对象吗,一切命名皆引用”吗?)。注意Python中is的含义和C#有所不同,在C#中,is 操作符被用于动态地检查运行时对象类型是否和给定的类型兼容。例如,运算e is T ,其中e 是一个对象,T 是一个类型,返回值是一个布尔值,它表示e是否能转换于 T 类型。

2.1.5  三元运算符

三元运算符是C/C++/C#一系语言所特有的一类运算符,例如,对表达式b? x: y,先计算条件b,然后进行判断,如果b的值为true,则计算并返回x的值,否则计算并返回y的值。

在Python中,提供了专门的逻辑分支表达式来模拟C系中的三元运算,我们也可以在一行语句中完成三元运算,例如

print '偶数' if x % 2 == 0 else '奇数'

2.1.6  运算符的优先级

你期待我列一个很长的表嘛?自己去查好伐,我就不浪费博客园的存储空间了。总之一句话:搞不清楚用括号!

2.2  流程控制语句

2.2.1  条件语句

Python用if,elif,else三个关键字进行条件判断,与C#唯一的区别就是用elif取代了else if,少打两个字,其它都一样。此外别忘了在if等语句后加 : 哦!

如果一个流程控制分支下不做任何事情,记得写一句pass语句,不然Python会报错。例如:

1 if 0:
2 pass #神经啊!这种例子用来说明什么?

在Python中没有switch语句,你可以使用if..elif..else语句来完成同样的工作。如果你觉得繁琐,可以试试dict实现方式,下边是个例子,分别对比了两种实现方式。

1 # 类C#伪码,根据输入的不同参数选择程序的不同行为
2  switch(x):
3 case "1":
4 print 'one'; break;
5 case "2":
6 print 'two'; break;
7 default:
8 print 'nothing!'
9
10  # 使用 if 替代
11  if x =='1':
12 print 'one'
13  elif x=='2':
14 print 'two'
15  else:
16 print 'nothing!'
17
18  # 使用dict
19  numtrans = {
20 1: 'one',
21 2: 'two',
22 ...
23 }
24 try:
25 print numtrans[x]
26 except KeyError:
27 print 'nothing!'
28
29 # 也可以在分支中使用方法(函数)
30 def print_one():
31 print 'one'
32 def print_two():
33 print 'two'
34 numtrans = {
35 1:print_one,
36 2:print_two,
37 }
38
39 try:
40 numtrans[x]() #注意名字+括号就可以执行方法了,这个实际上很牛X的。
41 except KeyError:
42 print 'nothing!'

从上面的语句可以看到,dict用一种更优雅的方式模拟了switch选择,集合lambda函数,还可以进一步实现更加复杂的逻辑分支语句。关于lambda函数的使用,我们到下一章再学习。

2.2.2  循环

Python支持两种循环语句——while循环和for循环,不支持C#中的do-while循环。Python的while循环和C#基本一致,此处我们着重比较两种语言中for循环的区别。

说的简单一点,Python中的for语句相当于C#中的foreach语句,它常用于从集合对象(list、str、tuple等)中遍历数据。例如:

1 for i in [1,2,3,4,5]:
2 print i

这与C#中的foreach语法基本是一样的,下边是C#中的对应代码:

1 IEnumerable<int> numbers = Enumerable.Range(0, 5);
2 foreach( int i in numbers)
3 Console.WriteLine(i);

如何实现类似C#中for(int i = 0; i < 10; i++)这种for循环呢?答案是使用range或xrange对象,见下边的代码:

1 # range(10)也可以用xrange(10)代替
2 for i in range(10):
3 print i
4 #等价于以下C#语句
5 #for(int i = 0; i<10;i++)
6 # Console.WriteLine(i);

内建函数range([i,]j[,stride])建立一个整数列表,列表内容为k(i <= k < j)。第一个参数i和第三个参数stride是可选的,默认值分别为 0 和 1。内建函数xrange([i,]j[,stride])与 range 有相似之处,但xrange返回的是一个不可改变的XRangeType对象。这是一个迭代器,也就是只有用到那个数时才临时通过计算提供值。当 j 值很大时,xrange能更有效地利用内存。

Python中的while和for循环中支持break和continue语句。break语句用于立刻中止循环,continue语句用于直接进入下一次循环(忽略当前循环的剩余语句)。break和continue语句在C#与Python中的用法是一致的,只用于语句所在的当前循环。如果需要退出一个多重循环,应该使用异常,因为Python中没有提供goto语句。

最后,Python中的循环还支持else语句,它只在循环正常完成后运行(for和while循环),或者在循环条件不成立时立即运行(仅while循环),或者迭代序列为空时立即执行(仅for循环)。如果循环使用break语句退出的话,else语句将被忽略。下面的代码用于说明else在循环中的应用(引自《精要参考(第二版)》,有修改)。

1 # while-else
2 while i < 10:
3 i = i + 1
4 else:
5 print 'Done'
6 # for-else
7 for a in s:
8 if a == 'Foo':
9 break
10 else:
11 print 'Not found!'

2.2.3  异常

Python和C#一样支持异常处理,利用try/except/finally结构,可以很方便的捕获异常,同时可以用raise语句手动抛出异常(上述四个异常处理的关键字分别对应C#中的try/catch/finally/throw)。通过except,您可以将try标示的语句中出现的错误和异常捕获,except可以接受参数作为要捕获的异常,如果想要捕获多个异常,可以使用元组(tuple)作为参数。没有参数的except被认为是捕获所有异常。而finally则用来在最后执行一定要运行的代码,例如资源回收。下面是一个简单的例子,来说明Python中的异常处理方式:

1 try:
2 f = open('thefile.txt')
3 s = f.readline()
4 ...
5 except IOError, (errno, strerror):
6 print "I/O error(%s): %s" % (errno, strerror)
7 except ValueError:
8 print "Could not convert data to an integer."
9 except:
10 print "Unexpected error:", sys.exc_info()[0]
11 raise
12 finally:
13 f.close()

最后说明一点,Python的try也支持else语句。如果有一些代码要在try没有发生异常的情况下才执行,就可以把它放到else中(这一点与finally不同,finally分支无论如何都会被执行)。

关于异常处理我们就简单介绍到这里,若需了解更多关于Python异常处理类、内建异常类型、自定义异常等内容,可以参考《Python精要参考(第二版)》。

2.3  列表内涵

列表内涵(List Comprehensions,也译作“列表推导式”)是Python最强有力的语法之一,常用于从集合对象中有选择地获取并计算元素,虽然多数情况下可以使用for、if等语句组合完成同样的任务,但列表内涵书写的代码更简洁(当然有时可能会不易读)。

列表内涵的一般形式如下,我们可以把[]内的列表内涵写为一行,也可以写为多行(一般来说多行更易读)。

[表达式 for item1 in 序列1  ...  for itemN in 序列N  if 条件表达式]

上面的表达式分为三部分,最左边是生成每个元素的表达式,然后是for 迭代过程,最右边可以设定一个if 判断作为过滤条件。

列表内涵的一个著名例子是生成九九乘法表:

s = [(x, y, x*y) for x in range(1, 10) for y in range(1,10) if x>=y]

列表内涵可能放在函数编程一章更合适,因为它可以统一实现map和filter等高阶函数(下一章介绍)。不过我还是倾向于将它看为一种组合的流程控制语句,而且我个人感觉它与C#中的LINQ有点神似(当然LINQ更强大,可以处理数据库和XML)。下面是两个例子,一个用LINQ实现,一个用Python的列表内涵实现。

1 //C#中用LINQ找出10以内的偶数
2 var s = from x in Enumerable.Range(0, 10) where x % 2 == 0 select x;

 

1 #Python中用列表内涵模拟以上LINQ语句
2 s = [x for x in range(0, 10) if x % 2 == 0]

当然上边的例子很简单,实际上我们可以用列表内涵完成更复杂的程序设计任务,而且效率一般会比使用for、if等的组合语句高(因为中间省略了一些列表的生成和赋值过程)。Python 2.5 之后,列表内涵进行了进一步的扩展,如果一个函数接受一个可迭代对象作为参数,那么可以给它传递一个不带中括号的列表内涵,这样就不需要一次生成整个列表,只要将可迭代对象传递给函数。

当然,列表内涵也不能滥用,可能会严重影响代码可读性,一个典型的反面例子见我的另一篇文章《学习Python列表内涵:一行代码搞定双倍超立方数计算》,这是初学者作品,谢绝效仿啊:)

2.4  动态表达式

先布置一个思考题:在C#语言中,如果需要在文本框中输入1+2(或更复杂的数学表达式)后计算它的值,你会怎么做呢?

不怕大家笑,我在用C#解决这个问题的时候,是自己做了一个表达式解析器…………,虽然只能计算加减乘除的简单组合,但也着实费了我好大力气。后来才开始使用各种各样的第三方Parse组件,msscript等。现在我们有了Python,要完成这个任务可以说是非常简单,简单到你不敢相信:只要用内置的eval()函数,就可以计算并返回任意有效表达式的值。例如:

1 str = '1+2'
2 print eval(str)

你还可以试验更复杂的表达式,是不是很Powerful的一项功能?

除了eval函数之外,Python还提供了exec语句将字符串str当成有效Python代码来执行,看下面的例子:

1 #exec.py
2 exec 'a=100'
3 print a

另外还有execfile函数,它用来执行一个外部的py文件。上一个例子存为exec.py后,运行下边的代码就知道是怎么回事了:

1 execfile(r'c:\exec.py')

最后提醒,默认的eval(),exec,execfile()所运行的代码都位于当前的名字空间中,eval(), exec,和execfile()函数也可以接受一个或两个可选字典参数作为代码执行的全局名字空间和局部名字空间,具体可以参考Python的手册,我就不啰嗦了。

2.5  小结

本章简要比较了Python与C#在运算符、表达式、程序流程控制语句等方面的异同,要点如下:

(1) Python的算术运算符除了+、-、*、/、%之外,还有求幂(**)和取整除(//);
(2) Python支持复合赋值(x+=1),但不支持C#中的自增和自减运算符(如x++);
(3) Python用and、or、not代替了C#语言中的逻辑运算符&&、||和!,同时and、or所执行的逻辑运算不返回布尔值,而是返回实际比较值之一;
(4) Python的选择语句包括if、elif和else,记得后边加冒号;Python中没有switch,但可以用if-elif-else或dict完成相同的任务模拟;
(5) Python的循环语句有while、for,它们都支持else语句;注意Python的for相当于C#中的foreach语句,同时可以用for + range对象模拟C#中的常规for循环;
(6) 两种语言的异常处理语句基本一致,不同的是Python的异常处理也支持else。

进一步阅读的参考:

本章比较简单,没什么资料好推荐给大家的,多数Python语法类书籍都会对运算符、表达式和流程控制语句进行详细的讲解,“百度一下,你就知道”!。不过我还是建议你试一下Python中的列表内涵和动态表达式,两个很pythonic的功能。

 

本章初稿完成于北京->石家庄的D4565次列车上。出差在外,旅途上写写blog消磨时间也是不错滴:) 当然时间仓促,手头资料也有限,如果有不恰当之处,请留言批评!

 

2010-3-5