Python基础教程3--条件和循环

本文主要介绍Python的条件、循环语句相关知识,通过条件和循环,我们就可以编写程序逻辑。

赋值魔法

最简单的的赋值操作,也有一些特殊的技巧

  • 序列解包/递归解包: 将多个值的序列解开,然后放到变量的序列中,从而一次进行多个赋值操作,更形象点表示如下:
                            
                                >>> values = 1, 2, 3
                                >>> values
                                (1, 2, 3)
                                >>> x, y, z = values
                                >>> x
                                1
                                >>> z
                                3
                            
                        

    可以简写成

                            
                                >>> x, y, z = 1, 2, 3
                                >>> x
                                1
                                >>> z
                                3
                            
                        

    可以简化交换两个变量的操作(不需要中间变量)

                            
                                >>> x = 1
                                >>> y = 2
                                >>> x, y = y, x         # 变量交换
                                >>> x
                                2
                                >>> y
                                1
                            
                        

    当函数/方法返回元组时,这个特性非常有用,通过一个赋值语句就可以很容易的对返回的值进行访问。

                            
                                >>> ph_dict = {'zht': '10000', 'lz': '10086'}
                                >>> key, value = ph_dict.popitem()
                                >>> key
                                'lz'
                                >>> value
                                '10086'
                            
                        

    请注意,解包的序列中的元素数量必须要和放置在赋值符号(=)左边的变量数量完全一致,否则会引发异常

                            
                                >>> x, y, z = 1, 2              # 数量不一致,引发异常
                                ValueError: not enough values to unpack (expected 3, got 2)
                                >>> x, y = 1, 2, 3
                                ValueError: too many values to unpack (expected 2)
                            
                        

    还有一个解包特性就是,可以像函数的位置参数列表一样,使用星号(*),将其余参数收集到一个变量中

                            
                                >>> x, y, *rest = 1, 2, 3, 4, 5, 6      # 在x和y被赋值以后,将其它参数都收集到rest列表中
                                >>> x
                                1
                                >>> y
                                2
                                >>> rest                                # 其它参数列表
                                [3, 4, 5, 6]
                            
                        

    其中星号变量可以放在开头或中间的位置

                            
                                >>> *rest, y, z = 1, 2, 3, 4, 5, 6      # 第一个位置
                                >>> rest
                                [1, 2, 3, 4]
                                >>> x, *rest, y = 1, 2, 3, 4, 5, 6      # 中间位置
                                >>> rest
                                [2, 3, 4, 5]
                            
                        
  • 链式赋值: 是将同一个值赋给多个变量的捷径操作,从右向左对变量进行逐个赋值。
                            
                                >>> x = y = func()
                            
                        

    与以下语句效果一样(从右向左赋值)

                            
                                >>> y = func()
                                >>> x = y
                            
                        

    请注意,链式赋值和以下语句不一定等价

                            
                                >>> y = func()  # 如果func返回当前时间,两次返回的时间会不一致
                                >>> x = func()
                            
                        
  • 增量赋值: 将运算符(+-*/%)放在赋值运算符=的左边的写法
                            
                                >>> x = 2
                                >>> x += 1              # 等价于x = x + 1
                                >>> x
                                3
                                >>> x *= 2              # 等价于x = x * 2
                                >>> x
                                6
                                >>> str1 = 'java'       # 对于其他类型也试用
                                >>> str1 += 'script'
                                >>> str1
                                'javascript'
                                >>> str1 *= 2
                                >>> str1
                                'javascriptjavascript'
    
                            
                        

语句块

语句块是条件为真(条件语句)或者执行多次(循环语句)时执行的一组语句。

  • Python通过冒号(:)标识语句块的开始
  • 通过在代码前放置空格的方式来创建语句块,同一块中的每行都应该有相同的缩进。
  • 当回退到和已经闭合的块一样的缩进时,就表示当前块已经结束。
  • Python不允许空的语句块,如果只是想加一个占位符,后续再实现相关逻辑,可以使用pass语句。

请注意,不同的缩进代表不同的语句块,在编码过程中很可能会出现因为缩进导致的逻辑问题。

下面是一个语句块示例

                
                    score = int(input('What is your score?'))
                    if score >= 60:                 # 块1开始
                        if score >= 90:               # 块1-1开始
                            print('excellent')        # 块1-1结束
                        elif score >= 80:             # 块1-2开始
                            print('good')             # 块1-2结束
                        else:                         # 块1-3开始
                            print('pass')             # 块1-3结束
                                                    # 块1结束
                    else:                           # 块2开始
                        print('fail')               # 块2结束
                
            

到目前为止,讲到的程序示例都是一条一条顺序执行的,接下来介绍让程序选择是否执行或者选择执行多次。

条件

布尔值和条件真假

讲条件语法之前,我们先看下什么是条件,既然是条件,就分真值和假值。

标准的布尔值只有True和False两个,而我们这里讲的条件,除了标准布尔值,还有其他值也可以被解释成真值和假值。

以下值作为条件时,会被解释器看作假值:

False None 0 '' () {} []

请注意,这几个值,在条件中使用都表示假值,但是这几个值相互之间都不相等,None == 0 结果为 False。

其他值在条件中都会被解释成真值,也可以把真值和假值理解为:"有些东西"和"没有东西"。

                
                    >>> bool(1)
                    True
                    >>> bool(0)
                    False
                    >>> bool('')
                    False
                    >>> bool('hello')
                    True
                
            

因为所有值都可以用作布尔值,所以几乎不需要进行显示转换,Python会自动转换。

比较运算符

除了一般的真假值,用在条件中最基本的运算符就是比较运算符了,它们用来比较其他对象,并返回True/False,比较运算符如下表所示

表达式 描述 注意项
x == y x等于y 两个值相等,并不代表是同一个值,比如x=[1,2],y=[1,2],虽然x==y为True,但是x并不是y,请参考x is y。
x != y x不等于y 同上
x < y x小于y 除了数字,像字符串,列表都可以进行比较,比如'a'<'b'为True,[1,2]>[2,1]为False
x > y x大于y 同上
x >= y x大于等于y 同上
x <= y x小于等于y 同上
x is y x和y是同一对象 请注意,is是判定同一性而不是相等性,例如x=[1,2],y=[1,2],虽然x==y为True,但是x和y并不是同一个对象,
对于简单数据类型(数字/字符串/布尔/None),如果两个值相等则表示同一对象,如果x='a',y='a',x is y为True
对于复杂数据类型(列表/元组/字典/集合/对象),只有指向同一内存地址引用才是True
x is not y x和y是不同的对象 同上
x in y x是y容器的成员 请参考序列
x not in y x不是y容器的成员 同上

比较运算和赋值一样,几个运算符是可以连接在一起使用的,比如 60< score <=80

布尔运算符和三元运算符

以上布尔值和比较运算符都是一个条件,但我们经常会遇到需要检查多个条件的情况,比如,检查用户输入的数字是否位于1-10之间,一个方法是可以通过嵌套if/else实现

                
                    num = int(input('Enter a number between 1 and 10: '))
                    if num > 0:
                        if num <= 10:
                            print('Great!')
                        else:
                            print('Wrong!')
                    else:
                        print('Wrong!')
                
            

虽然以上方法没问题,但是方法略显笨拙,需要打印两次Wrong,有一种简洁的实现方法如下

                
                    num = int(input('Enter a number between 1 and 10: '))
                    if num > 0 and num <= 10:
                        print('Great!')
                    else:
                        print('Wrong!')
                
            

上例中使用到的and运算符就是所谓的布尔运算符(又称逻辑运算符),一共有三个布尔运算符and,or和not,它们可用于连接两个布尔值。

  • and: 只有当两者都为真时,结果才会真,否则结果为假
  • or: 两者只要有一个为真,则结果为真,否则结果为假
  • not: 取反操作

而且,这三个布尔运算符可以随意结合使用

                
                    if((cash > price) or customer_has_good_credit) and not out_of_stock:
                        give_goods()
                
            

请注意,and和or运算符采用的是惰性求值或称为短路逻辑模式,只有在需要求值时才进行求值。

举个例子,表达式x and y,如果x为假,表达式就会立即返回False,而不管y的值,如果y是一个函数,也不会被执行,就像被"短路"了一样。

这种短路逻辑可以用来实现其它编程语言中经常用到的三元运算符 result = condition_true_result if condition else condition_false_result

                
                    >>> name = 'Python'
                    >>> greeting = 'Hello ' + (name if name !='' else 'stranger')
                    >>> greeting
                    'Hello Python'

                    >>> name = ''
                    >>> greeting = 'Hello ' + (name if name !='' else 'stranger')
                    >>> greeting
                    'Hello stranger'

                
            

条件执行和if/else/elif语句

前面我们讲了条件和真假值,通过if语句,就可以实现条件执行,如果条件为真,那么后面的语句块就会被执行,如果条件为假,则语句块就不会被执行。

也可以用else子句增加一种选择,如果if后面的语句块没有被执行,就会执行else中的子句。

如果要检查多个子句,就可以用elif,它表示else if的意思。

我们通过一个示例,演示下if/else/elif的使用

                
                    score = int(input('What is your score?'))
                    if score >= 60:                 # 如果>=60,执行下面的语句块
                        if score >= 90:             # 代码块嵌套,如果>=90,结果为:excellent
                            print('excellent')
                        elif score >= 80:           # 如果不>=90,但>=80,结果为:good
                            print('good')
                        else:                       # 如果既不>=90,又不>=80,结果为:pass
                            print('pass')
                    else:                           # 如果<60,执行下面的语句块
                        print('fail')
                
            

循环

循环就是一直重复执行,直到人为停止,比如要循环打印从1-100的所有数字,通过循环语句就可以方便快捷的实现,而不用写100次的print语句。

循环主要有两种,while循环和for循环。

while循环

while语句非常灵活,可以用来在任何条件为真的情况下,重复执行一个代码块。

上述依次打印1-100数字的例子,通过while循环可以像下面这样实现

                
                    x = 1
                    while x <= 100:     # 一直循环,直到x>100结束
                        print(x)
                        x += 1
                
            

for循环

主要用于迭代一个集合(列表/字典)中的每一个元素,并执行一个代码块。

                
                    numbers = [11, 22, 33, 44, 55, 66]
                    for item in numbers:
                        print(item)

                    #依次打印出numbers中的值,11,22……
                
            

遍历列表和字典

以下是程序中经常用到的遍历列表和字典的方法

  • 遍历列表
    • 简单遍历
                                      
                                          numbers = [11, 22, 33, 44, 55, 66]
                                          for item in numbers:
                                              print(item)
      
                                          #依次打印出11/22/33/44/55/66
                                      
                                  
    • 带索引的遍历

      如果既想遍历序列中的对象,同时还要获取当前对象的索引,可以通过内建的enumerate函数实现

                                      
                                          numbers = [11, 22, 33, 44, 55, 66]
                                          for item in enumerate(numbers):                 # item是一个索引和值组成的元组 (0, 11)/(1, 22)/……
                                              print('index:',item[0],'value:',item[1])
      
                                          #依次打印出: index: 0 value: 11/index: 1 value: 22/
                                      
                                  

      当然通过赋值魔法,可以直接使用索引和对象

                                      
                                          numbers = [1, 2, 3, 4, 5, 6]
                                          for index, value in enumerate(numbers):      # 解包赋值
                                              print('index:', index, 'value:', value)
                                      
                                  
    • 并行遍历

      程序可以通过内置的zip函数同时迭代两个序列,

                                      
                                          names = ['Lucy', 'Ryder', 'Tom']
                                          ages = [18, 7, 20]
                                          for name, age in zip(names, ages):
                                              print(name, ' is ', age)
      
                                          #依次打印出: Lucy  is  18/Ryder  is  7/Tom  is  20
                                      
                                  
  • 遍历字典
    • 遍历key
                                      
                                          d = {'x': 1, 'y': 2, 'z': 3}
                                          for key in d:
                                              print(key, ":", d[key])
      
                                          #打印出x : 1/y : 2/z : 3
                                      
                                  
    • 遍历key和value

      还可以通过字典的items方法,将键值作为元组返回再遍历

                                      
                                          d = {'x': 1, 'y': 2, 'z': 3}
                                          for key, value in d.items():
                                              print(key, ":", value)
                                      
                                  

跳出循环

一般来说循环会一直执行到条件为假或者序列元素迭代用完时,但是有时候可能想要提前结束循环,或者中断当前循环,进行新的一轮迭代。

  • break: 用于结束(跳出)循环。

    举个简单例子,遍历一个数字列表,如果有值>100,则结束遍历

                            
                                numbers = [60, 20, 130, 10]
                                for item in numbers:
                                    if item > 100:
                                        break
                                    print(item)
    
                                #打印出 60,20后停止遍历,不会继续打印其它值
                            
                        

    break经常和while True结合使用,while True实现了了一个永远不会自己停止的循环,结合if和break,可以在满足某项条件时,终止循环。

    比如一个程序接收用户输入,并打印,直到用户输入了'bye',则终止程序运行

                            
                                while True:
                                    word = input("Please enter a word: ")
                                    if word == 'bye':
                                        break
                                    print("The word is ", word)
    
                                #运行结果如下:
                                #Please enter a word: hello
                                #The word is  hello
                                #Please enter a word: hi
                                #The word is  hi
                                #Please enter a word: bye
                                #Process finished with exit code 0  #退出
                            
                        
  • continue: 用于结束当前循环,跳到下一轮循环的开始,它跳过剩余的循环体,但是不结束循环。

    比如要打印出数字列表中的偶数,如果是奇数则跳过

                            
                                numbers = [1, 2, 3, 4, 5, 6]
                                for item in numbers:
                                    if item % 2 != 0:
                                        continue        # 跳到下一个循环,而不是退出
                                    print(item)
    
                                #运行结果如下:
                                #2
                                #4
                                #6
                            
                        

循环中的else子句

当使用break跳出循环时,通常是因为找到了某个对象或者某个事件发生了。

在跳出前做一些事情很简单,但是有时想在没有跳出(比如没有发现某个对象)时做些事情,这时就可以使用else子句,它仅在没有调用break时执行

                
                    numbers = [1, 2, 3, 4, 5, 6]
                    for item in numbers:
                        if item > 100:
                            break
                        print(item)
                    else:
                        print("It's ok")    # 当所有值都<=100时,不会触发break,此时else中的子句会执行。
                
            

可以结合else子句和break/continue跳出嵌套循环

                
                    for x in range(10):
                        for y in range(10):
                            print(x * y)
                            if x * y > 50:
                                break
                        else:
                            continue  # y层循环没有break时调用,执行continue,会直接进入下一个x循环,不会执行下一行的break语句
                        break  # y层循环break时,上一行的continue语句不会被调用,会执行当前break跳出x层循环
                
            

列表推导式

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

它的语法是: x_about_value for x in alist if condition,x_about_value是通过x元素生成的值,if condition可以省略。

意思是对于alist的每个元素x,如果符合某个条件(如果省略表示都符合),则将生成的值x_about_value放到新列表中,遍历结束返回新列表。

以下代码创建一个1-9的平方组成的列表

                
                    >>> [x*x for x in range(10)]                        # range是内置函数,返回一个指定起止值的可迭代序列
                    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
                
            

也可以嵌套更多的for语句

                
                    >>> [(x, y) for x in range(3) for y in range(2)]    # 可以嵌套更多的for语句
                    [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]