python基础教程_学习笔记7:条件、循环、其它语句

时间:2021-08-28 18:40:43

条件、循环、其它语句

printimport

随着更加深入地学习python,可能会出现这种感觉:有些自以为已经掌握的知识点,还隐藏着一些让人惊讶的特性。

 

使用逗号输出

打印多个表达式,只要将这些表达式用逗号隔开即可:

>>> print "age:",28

age: 28

参数之间都插入了一个空格符。

 

如果在结尾加上逗号,那么接下来的语句会与前一条语句在同一行打印:

print "Hello,",

print "World!"

结果:

Hello, World!

把某件事作为另一件事导入

从模块导入函数的时候,可以使用:

import somemodule

from somemodule import somefunction

from sommodule import somefunction,anotherfunction,yetanotherfunction

from somemodule import *

其中,只有确定自己想要从给定的模块导入所有功能时,才应该使用最后一个版本。

 

如果两个模块都有open函数,应该怎么做呢?

只需使用第一种方式导入,然后像下面这样使用函数:

module1.open(...)

module2.open(...)

 

但还有另外的选择:可以在语句末尾增加一个as语句,在该子句后给出名字,或为整个模块提供别名

>>> import math as foobar

>>> foobar.sqrt(4)

2.0

也可以为函数提供别名:

>>> from math import sqrt as foobar

>>> foobar(4)

2.0

对于open函数,可以像下面这样使用:

from module1 import open as open1

from module2 import open as open2

 

赋值魔法

序列解包

多个赋值操作可以同时进行:

>>> x,y,z=1,23,456

>>> print x,y,z

1 23 456

用它交换两个(或多个)变量:

>>> x,y=y,x

>>> print x,y

23 1

 

>>> x,y,z=y,z,x

>>> print x,y,z

1 456 23

事实上,这里所做的事情叫做序列解包或可迭代解包——将多个值的序列解开,然后放到变量的序列中

>>> values=1,2,3

>>> values

(1, 2, 3)

>>> x,y,z=values

>>> print x,y,z

1 2 3

当函数或者方法返回元组(或者其他序列或可迭代对象)时,这个特性尤其有用。假设需要获取(和删除)字典中的任意的键-值对,可以使用popitem方法,这个方法将键值对作为元组返回,那么这个元组可以直接赋值到两个变量中:

>>> people={'name':'signjing','age':'28','weight':'72'}

>>> x,y=people.popitem()

>>> print x,y

age 28

>>> x,y=people.popitem()

>>> print x,y

name signjing

>>> x,y=people.popitem()

>>> print x,y

weight 72

它允许函数返回一个以上的值并且打包成元组,然后通过一个赋值语句很容易进行访问。所解包的序列中的元素数量必须和放置在赋值符号=左边的变量数量完全一致,否则python会在赋值时引发异常:

>>> x,y=1,3,4

 

Traceback (most recent call last):

  File "<pyshell#27>", line 1, in <module>

    x,y=1,3,4

ValueError: too many values to unpack

>>> x,y,z=2,9

 

Traceback (most recent call last):

  File "<pyshell#28>", line 1, in <module>

    x,y,z=2,9

ValueError: need more than 2 values to unpack

 

链式赋值

链式赋值是将同一个值赋给多个变量的捷径。

x=y=somefunction()

和下面语句的效果是一样的:

y=somefunction()

x=y

注意:上面的语句和下面的语句不一定等价:

x=somefunction()

y=somefunction()

 

增量赋值

将表达式运算符放置在赋值运算符=的左边,这种写法叫做增量赋值,对于*/%等标准运算符都适用:

>>> x=5

>>> x+=3

>>> x*=2

>>> x/=4

>>> x

4

 

对于其他数据类型也适用(只要二元运算符本身适用于这些数据类型即可):

>>> s='too'

>>> s+='many'

>>> s*=2

>>> s

'toomanytoomany'

 

语句块

语句块是在条件为真(条件语句)时执行或执行多次的一组语句。在代码前放置空行来缩进语句即可创建语句块。

 

块中的每行都需要缩进相同的量。

 

很多语言使用特殊单词或者字符(比如begin{)来表示一个语句块的开始,用另外的单词或字符(如end})表示语句块的结束。

python中,冒号(:)用来标识语句块的开始,块中的每一个语句都是缩进的(缩进量相同)。当回退到和已经闭合的块一样的缩进量时,就表示当前块已经结束了。

 

条件和条件语句

布尔变量

下面的值在作为布尔表达式时候,会被解释看做假(False):

False None 0 “” () [] {}

换句话说,也就是标准值FalseNone、所有类型的数字0(包括浮点数、长整型和其它类型)、空序列(比如空字符串、元组和列表)以及空的字典都为假。其它的一切都解释为真,包括特殊值True

标准的真值为TrueFalse。事实上,TrueFalse只不过是10的“华丽”说法而已。

>>> True

True

>>> False

False

>>> True==0

False

>>> True==1

True

>>> False==0

True

>>> False==1

False

>>> False+True+23

24

 

布尔值TrueFalse属于布尔类型,bool函数可以用来(和liststr以及tuple一样)转换其它值。

>>> bool('I think ,therefore I am')

True

>>> bool(42)

True

>>> bool(0)

False

>>> bool('')

False

>>> bool(False)

False

>>> bool(())

False

>>> bool({})

False

>>> bool([])

False

 

因为所有值都可以用作布尔值,所以几乎不需要对它们进行显式转换(可以说python会自动转换这些值)。

 

注意:尽管[]””都是假植(也就是说bool([])==bool(“”)==False),它们本身并不相等。对于其他不同类型的假值对象也是如此(例如,()!=False)

 

条件执行和if语句

if语句可以实现条件执行,如果条件判定为真,则后面的语句块执行,如果条件为假,语句块就不会被执行。

name=raw_input("Please input a name: ")

if name.endswith("Bob"):

        print "Hello,Bob!"

 

如果用户输入了以Bob结尾的名字,则打印出问候语。

else语句

else子句(之所以叫子句,是因为它不是独立的语句,而只能作为if语句的一部分)可以增加一种选择。

 

name=raw_input("Please input a name: ")

if name.endswith("signjing"):

        print "Hello,signjing!"

else:

        print "Hello,someone!"

如果第1个语句块没有被执行,则转入第2个语句块。

elif语句

如果需要检查多个条件,就可以使用elif,它是“else if”的简写,也是ifelse子句的联合使用——也就是具有条件的else子句。

 

num=input("Please input a num: ")

if num>0:

        print "num > 0"

elif num<0:

        print "num < 0"

else:

        print "num = 0"

嵌套代码块

if语句里可以嵌套使用if语句:

num = input("Please input a num: ")

if num > 0:

        if num >5:

                print "num > 5"

        elif num > 3:

                print "num >3 and num <= 5"

        else:

                print "num <= 3 and num > 0"

elif num < 0:

        if num < -10:

                print "num < -10"

        elif num < -4:

                print "num < -4 and num >= -10"

        else:

                print "num >= -4 and num < 0"

else:

        print "num = 0"

更复杂的条件

比较运算符

表达式 描述

x==y x等于y

x<y x小于y

x>y x大于y

x>=y x大于等于y

x<=y x小于等于y

x!=y x不等于y

x is y xy是同一个对象

x is not y xy是不同的对象

x in y xy容器的成员

x not in y x不是y容器的成员

 

比较不兼容类型

理论上,对于相对大小的任意两个对象xy都是可以使用比较运算符比较的,并且都会得到一个布尔值结果。但是只有在xy是相同或者近似类型的对象时,比较才有意义。

 

python中比较运算和赋值运算一样是可以连接的——几个运算符可以连在一起使用:

>>> a=5

>>> 0<a<8

True

>>> 0<a<3

False

>>> 0<a>3

True

 

相等运算符

想要知道两个东西是否相等,应该使用相等运算符,即两个等号==

>>> "abc"=="abc"

True

>>> "abc"=="Abc"

False

 

单个相等运算符是赋值运算符,是用来改变值的,不能用来比较。

 

is:同一性运算符

这个运算符比较有趣,它看起来和==一样,但事实上却不同:

>>> x=y=[1,2,3]

>>> z=[1,2,3]

>>> x==y

True

>>> x is y

True

>>> x == z

True

>>> x is z

False

 

xz相等却不等同,因为is运算符是判定同一性而不是相等性。

xy被绑定到同一个列表上,而变量z被绑定在另外一个具有相同数值和顺序的列表上。它们的值可能相等,但却不是一个对象。

 

in:成员资格运算符

之前说明过了,此处略;

 

字符串和序列比较

字符串可以按照字母顺序排列进行比较。

>>> "a" < "b"

True

>>> "abc" < "ab"

False

注意:实际的顺序可能会因为使用不同的locale而和上面的例子有所不同

其他的序列也可以以相同的方式进行比较,不过比较的不是字符而是元素的其它类型:

>>> [1,2,4]>[1,2,3]

True

>>> [1,2,[2,'a']]<[1,2,[3,4]]

True

 

布尔运算符

and运算符,连接两个布尔值,且在两者都为真时返回真,否则返回假。

or运算符,连接两个布尔值,且在两者都为假时返回假,否则返回真。

not运算符,连接一个布尔值,当连接的布尔值为真时返回假,为假时返回真。

 

短路逻辑

x and y需要两个变量都为真时才为真,如果x为假,则x and y立即返回false,而不需计算y的值。同理,x or y只要有一个为真则为真,如果x为真,则x or y直接返回True,而不需计算y的值。这样,避免了无用地执行代码,可以作为一种技巧使用。

断言

if语句有个非常有用的近亲,其工作方式多少有点像下面这样(伪代码):

if not condition:

crash program

这样做是因为与其让程序在晚些时候崩溃,不如在错误条件出现时直接让它崩溃。一般来说,你可以要求某些条件必须为真。语句中使用的关键字为assert

>>> age=10

>>> assert 0<age<102

>>> age=-2

>>> assert 0<age<102

 

Traceback (most recent call last):

  File "<pyshell#39>", line 1, in <module>

    assert 0<age<102

AssertionError

 

如果需要确保程序中的某个条件一定为真才能让程序正常工作的话,assert语句就有用了,可以在程序中置入检查点:

条件后可以添加字符串(用逗号把条件和字符串隔开),用来解释断言:

>>> assert 0<age<102, 'make age right'

 

Traceback (most recent call last):

  File "<pyshell#42>", line 1, in <module>

    assert 0<age<102, 'make age right'

AssertionError: make age right

循环

while循环

用来在任何条件为真的情况下重复执行一个代码块。

i=5

while i>0:

        print i

        i-=1

结果:

5

4

3

2

1

 

for循环

list1=list('signjing')

for l in list1:

        print l

结果:

s

i

g

n

j

i

n

g

 

numbers=[1,2,3,4]

for n in numbers:

        print n

结果:

1

2

3

4

 

迭代(循环的另一种说法)某个范围的数字是很常见的,有个内建的函数可供使用:

for n in range(1,5):

        print n

结果:

1

2

3

4

 

range函数的工作方式类似于分片,包含下限,不包含上限,如果希望下限为0,则可以只提供上限。

 

提示:

如果能使用for循环,就尽量不使用while循环。

循环遍历字典元素

一个简单的for语句就能循环字典的所有键,就像处理序列一样:

d={'x':1,'y':2,'z':3}

for key in d:

        print key,d[key]

结果:

y 2

x 1

z 3

 

for循环的一大好处就是可以在循环中使用序列解包:

d={'x':1,'y':2,'z':3}

for key,value in d.items():

        print key,value

结果:

y 2

x 1

z 3

 

一些迭代工具

python中迭代序列(或其它可迭代对象)时,一些函数非常有用。有些函数位于itertools模块,还有些python的内建函数也十分有用。

并行迭代

程序可以同时迭代两个序列:

names=['anne','beth','damon']

ages=[13,19,21]

for i in range(len(names)):

        print names[i],'is',ages[i],'years old.'

结果:

anne is 13 years old.

beth is 19 years old.

damon is 21 years old.

 

内建的zip函数可以用来进行并行迭代,把两个序列“压缩”在一起,然后返回一个元组的列表:

names=['anne','beth','damon']

ages=[13,19,21]

for name,age in zip(names,ages):

        print name,"is",age,"years old."

结果:

anne is 13 years old.

beth is 19 years old.

damon is 21 years old.

 

zip函数可以作用于任意多的序列。关于它很重要的一点是zip可以应付不等长的序列:当最短的序列“用完”的时候就会停止:

>>> zip(range(5),xrange(100))

[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]

>>> zip(range(5),xrange(2))

[(0, 0), (1, 1)]

 

编号迭代

有些时候想要迭代序列中的对象,同时还要获取当前对象的索引。

暂略;

 

翻转和排序迭代

reversedsorted,同列表的reversesort方法类似,但作用于任何序列或可迭代对象上,不是原地修改对象,而是返回翻转或排序后的版本:

>>> sorted([4,3,6,8,3])

[3, 3, 4, 6, 8]

>>> sorted('hello,world!')

['!', ',', 'd', 'e', 'h', 'l', 'l', 'l', 'o', 'o', 'r', 'w']

>>> list(reversed('hello,world!'))

['!', 'd', 'l', 'r', 'o', 'w', ',', 'o', 'l', 'l', 'e', 'h']

>>> ''.join(reversed('hello,world'))

'dlrow,olleh'

跳出循环

break

结束循环可以使用break语句。

for i in range(5):

        print i

        if i > 2:

                break

        print "--"

结果:

0

--

1

--

2

--

3

 

continue

continue语句用的要少很多,它让当前的迭代结束,“跳”到下一轮循环的开始。基本意思是:跳过剩余的循环体,但不结束循环。当循环体很大而且很复杂时,会很有用。

for i in range(5):

        print i

        if i > 2:

                continue

        print "--"

结果:

0

--

1

--

2

--

3

4

while True/break习语

while True实现了一个永远不会自己停止的循环,但在循环体内部的if语句中加入条件,在条件满足时调用break语句。这样,就可以在循环内部任何地方而不是只在开头终止循环。

 

尽管应该小心在代码中频繁使用break语句,但这个特殊的技术用得非常普遍。

循环中的else子句

当在循环体内部使用break语句时,通常是因为找到了某物或某事发生了,在跳出时做一些事情是简单的,但有些时候想要在没有跳出之前做些事情。可以在循环中增加一个else语句——仅在没有调用break时执行。

for i in range(5):

        print i

        if i > 6:

                break

        print "--"

else:

        print "I'm here"

结果:

0

--

1

--

2

--

3

--

4

--

I'm here

 

forwhile循环中都可以使用continuebreak语句和else子句。

列表推导式——轻量级循环

列表推导式是利用其它列表创建新列表的一种方法。工作方式类似于for循环。

>>> [x*x for x in range(1,6)]

[1, 4, 9, 16, 25]

可以增加判断条件:

>>> [x*x for x in range(1,6) if x%2==0 ]

[4, 16]

可以增加更多的for语句:

>>> [x*y for x in range(1,3) for y in (2,5)]

[2, 5, 4, 10]

也可以和if语句联合使用:

>>> [x*y for x in range(1,11) for y in range(1,9) if x%3==0 if y%4==0 ]

[12, 24, 24, 48, 36, 72]

 

注意:for循环部分和if语句部分之间都没有标点符号。

三人行

什么都没发生

有些时候,程序什么事情都不用做:

>>> pass

>>> 

 

name=raw_input("Please input a name: ")

if name == 'signjing':

        print "I'm signjing"

elif name == 'sj':

        pass

else:

        print "unknown"

执行:

Please input a name: signjing

结果:

I'm signjing

 

执行:

Please input a name: sj

 

如果将pass行注释:

if name == 'signjing':

        print "I'm signjing"

elif name == 'sj':

        #pass

else:

        print "unknown"

执行报错:

  File "pass.py", line 6

    else:

       ^

IndentationError: expected an indented block

使用del删除

一般来说,python解释器(以其无穷的智慧)自动删除那些不再使用的对象。另一种方法是使用del语句,它不仅会移除一个对象的引用,也会移除那个名字本身。

>>> x=['hello','world']

>>> y=x

>>> y[1]='python'

>>> x

['hello', 'python']

>>> del x

>>> y

['hello', 'python']

 

事实上,python中是没有办法删除值的,因为值不再使用时,python解释器会负责内存的回收。

使用execeval执行和求值字符串

有些时候会动态地创造python代码,然后将其作为语句执行或作为表达式计算,这近似于“黑暗魔法”——在此之前,一定要慎之又慎,仔细考虑:

 

exec

执行一个字符串的语句是exec

>>> exec "print 'hello'"

hello

但使用简单形式的exec语句绝不是好事。很多时候可以给它提供命名空间——可以放变量的地方。

 

>>> from math import sqrt

>>> exec "sqrt = 1"

>>> sqrt(4)

 

Traceback (most recent call last):

  File "<pyshell#70>", line 1, in <module>

    sqrt(4)

TypeError: 'int' object is not callable

可以通过in <scope>来实现,其中<scope>就是起到放置代码字符串命名空间作用的字典。

>>> from math import sqrt

>>> scope={}

>>> exec "sqrt = 1" in scope

>>> sqrt(4)

2.0

>>> scope['sqrt']

1

可见,潜在的破坏性代码并不会覆盖sqrt函数,原来的函数能正常工作,而通过exec赋值的变量sqrt只在它的作用域内有效。

 

注意,如果需要将scope打印出来的话,能看到其中包括很多东西,因为内建的__builtins__字典自动包含所有的内建函数和值:

>>> len(scope)

2

>>> scope.keys()

['__builtins__', 'sqrt']

 

eval

eval(用于“求值”)是类似于exec的内建函数。

exec语句会执行一系列的python语句,而eval会计算python表达式,并返回结果值。

exec语句并不返回任何对象,因为它本身就是语句。

>>> eval(raw_input("Enter an arithmetic expression: "))

Enter an arithmetic expression: 2*6+8

20