IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> Python 3 快速入门 —— 流程控制与函数 -> 正文阅读

[Python知识库]Python 3 快速入门 —— 流程控制与函数

本文假设你已经有一门面向对象编程语言基础,如?Java?等,且希望快速了解并使用?Python?语言。本文对重点语法和数据结构以及用法进行详细说明,同时对一些难以理解的点进行了图解,以便大家快速入门。一些较偏的知识点在大家入门以后根据实际需要再查询?官方文档?即可,学习时切忌胡子眉毛一把抓。同时,一定要跟着示例多动手写代码。学习一门新语言时推荐大家同时去刷?leetcode?,一来可以快速熟悉新语言的使用,二来也为今后找工作奠定基础。推荐直接在网页上刷?leetcode?,因为面试的时候一般会让你直接在网页编写代码。?leetcode?刷题路径可以按我推荐的方式去刷。以下代码中,以?>>>?和?...?开头的行是?交互模式?下的代码部分,?>??开头的行是?交互模式?下的输入,其他行是输出。?python?代码中使用?#?开启行注释。

编程前菜

>>> a, b = 0, 1
... while a < 10:
...    print(a, end=', ')
...    a, b = b, a+b     # 多重赋值,右表达式在赋值前就已经求值了
...    
0, 1, 1, 2, 3, 5, 8,     # Fibonacci series

如上为典型的?python?代码块,?python?中的代码行无需以?;?结尾,控制块以缩进标识开始和结束。?python?中的比较操作符与?C?和?Java?类似,需要注意的是:?==?比较两个引用所指对象的值是否相同,要比较两个引用是否指向同一个对象需要使用?is?关键字,也可以通过?id?方法查看两个引用所指对象的id是否相同来判断。

>>> a = [1, 2, 3]
... b = [1, 2, 3]
... print('a = b:', a == b)
a = b: True          # a, b 中元素的 个数相同 且 值依次相等

>>> a is b
False				 # a, b 没指向同一个对象

>>> c = a
>>> c is a			 # a, c 指向同一个对象
True
>>> id(c)
2827535985280
>>> id(a)
2827535985280		 # c, a 所指对象id相同,故指向同一对象

流程控制

if 语句

Python?中的?if?语句包含:?if?、?elif?以及?else?子句,?elif?等同于?C?或?Java?中的?else if?:

>>> x = int(input("input a digit: "))
... if a < 0:
...     print("Negative")
... elif a == 0:
...     print("Zero")
... else:
...     print("Positive")
...
input a digit: >? 10
Positive

for 和 while 语句

Python?中的?for?语句通常用来遍历列表和字符串等容器,它不能像?C?和?Java?中那样通过在for语句中添加条件判断和变量递增规则来控制for循环的次数:

>>> digits = [1, 2, 3]
... for x in digits:        # 遍历list
...     print(x, end=", ")
...     
1, 2, 3, 

>>> s = "python"
... for ch in s:            # 遍历字符串
...     print(ch, end=" ")
...     
p y t h o n

由于?Python?中?for?语句的这种“缺陷”,我们如何像?C?和?Java?那样在?for?语句中利于下标去遍历?list?呢?首先我们可以利用?while?循环:

# while中根据下标遍历list
>>> digits = [1, 2, 3]
>>> i = 0
... while i < len(digits):
...     print(digits[i], end=" ")
...     i = i + 1
...     
1 2 3 

# while中根据下标修改list
>>> digits = [1, 2, 3]
>>> i = 0
... while i < len(digits):
...     if digits[i] == 2:
...         digits[i] = 8
...     i = i + 1
...     
>>> print(digits)
[1, 8, 3]

其次,我们还可以利用?range()?函数和?enumerate()?函数:

# 使用range,以0为起点,len为终点(不包含),以1为步长创建下标序列
>>> digits = [1, 2, 3]
... for i in range(len(digits)):
...     print(digits[i], end=" ")
...     
1 2 3 

>>> digits = [1, 2, 3]
... for i in range(len(digits)):
...     if digits[i] == 2:
...         digits[i] = 8
... print(digits)
[1, 8, 3]

# 使用enumerate,创建枚举序列,可以同时取出位置索引和对应的值
>>> digits = [1, 2, 3]
... for i, v in enumerate(digits):
...     print(i, v)
...     
0 1
1 2
2 3

>>> digits = [1, 2, 3]
... for i, v in enumerate(digits):
...     if v == 2:
...         digits[i] = 8
... print(digits)
[1, 8, 3]

我们还可以使用?for?语句来遍历字典:

# 遍历字典对象的key
>>> cities = {"chengdu": "A", "mianyang": "B", "guangyuan": "H"}
... for k in cities:
...     print(k, end=" ")
...     
chengdu mianyang guangyuan 

# 遍历字典对象时同时根据key遍历value
>>> cities = {"chengdu": "A", "mianyang": "B", "guangyuan": "H"}
... for k in cities:
...     print(k, cities[k], sep=": ")
...     
chengdu: A
mianyang: B
guangyuan: H

# 调用字典对象的items方法后可同时遍历key和value
>>> cities = {"chengdu": "A", "mianyang": "B", "guangyuan": "H"}
... for k, v in cities.items():
...     print(k, v, sep=": ")
...     
chengdu: A
mianyang: B
guangyuan: H

注意:上诉for语句中申明变量在循环结束后依然存在,而列表、元组等推导表达式中则不会:

>>> for x in [1, 2, 3]:
...     print(x)
...     
1
2
3
>>> print(x)
3

由于一般不推荐在遍历数据集合时直接修改原数据集合来获取我们想要的数据集合,这样不安全且不够灵活。推荐在遍历原数据集合时根据条件创建一个新的数据集合,而这正是?Python?语言中?for?语句的强大之处。

列表推导式

列表推导式创建列表,列表推导式的方括号内包括:?一个表达式,后面为一个?for?子句,然后是零个或多个?for?或?if?子句?。

# 创建 0 - 9 的平方列表
>>> [v**2 for v in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# 验证列表推导式执行后for子句中的变量是否还存在
>>> [v**2 for v in range(10)]
... print(v)
Traceback (most recent call last):
  File "<input>", line 2, in <module>
NameError: name 'v' is not defined

# 将两个列表中不相等的元素组合起来
>>> [(x, y) for x in [1, 2, 3] for y in [1, 2, 3] if x != y]
[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
# 等价于
>>> res = []
... for x in [1, 2, 3]:
...     for y in [1, 2, 3]:
...         if x != y:
...             res.append((x, y))
... print(res)
[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]

列表推导式的第一个表达式不但可以为复杂的表达式、函数,甚至可以为?另一个列表推导式?:

>>> matrix = [
...     [1, 2, 3],
...     [4, 5, 6],
...     [7, 8, 9]
... ]
... 
# 创建matrix的转置
>>> [[row[i] for row in matrix] for i in range(3)]
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
# 等价于
>>> res = []
... for i in range(3):
...     res.append([row[i] for row in matrix])
... print(res)
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
# 又等价于
>>> res = []
... for i in range(3):
...     temp = []
...     for row in matrix:
...         temp.append(row[i])
...     res.append(temp)
... print(res)
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

与列表类似,集合、字典也都支持推导式(元组不支持):

# 集合推导式
>>> { x**2 for x in [1, 2, 1, 4]}
{16, 1, 4}

# 字典推导式
>>> { x: x**2 for x in [1, 2, 1, 4]}
{1: 1, 2: 4, 4: 16}

循环中的break、continue 与 else 语句

Python?中的循环同样支持其他语言中的?break?和?continue?语句,此外还提供了一个?else?语句:?for?循环中,当可迭代对象中的元素全部循环完毕时,或?while?循环的条件为假时,执行该子句;?break?语句终止循环时,不执行该子句。

# 可迭代对象中的元素全部循环完毕时执行else子句
>>> for x in []:
...     print(x, end=" ")
... else:
...     print("end")
...     
end

>>> for x in range(3):
...     print(x, end=" ")
... else:
...     print("end")
...     
0 1 2 end

# 使用break语句终止循环则不执行else子句
>>> for x in range(3):
...     print(x, end=" ")
...     if x == 2:
...         break
... else:
...     print("end")
...     
0 1 2

# continue不影响else子句的
>>> for x in range(3):
...     print(x, end=" ")
...     if x == 2:
...         continue
... else:
...     print("end")
...     
0 1 2 end

# while条件为假时执行else子句
>>> x = 10
... while x < 10:
...     print(x)
... else:
...     print("not in while")
...     
not in while

match语句(3.10开始支持)

match?语句类似其他语言中的?switch?语句,常用来替代多个?if?语句:

>>> status = 404
... match status:
...     case 404:  # 默认只匹配一个分支,不需要也不能加入其他语言中的break语句
...         print("Not Found!")
...     case 500:
...         print("Internal Error!")
...     case _:    # _ 类似于其他语言中的default
...         print("Not Known!")
...         
Not Found!

当我们希望多个?case?匹配同样的结果时可以使用?|?:

case 401 | 402 | 403:
    print("Not Allowed!")

match?的强大之处在于可以从值中提取子部分 (序列元素或对象属性) 并赋值给变量:

>>> point = (1, 2)
... match point:
...     case (0, 0):
...         print("Origin")
...     case (0, y):
...         print("on Y axis, y =", y)
...     case (x, 0):
...         print("on X axis, x =", x)
...     case (x, y):
...         print("x =", x, "y =", y)
...     case _:
...         print("Not Valid!")
...         
x = 1 y = 2

更多功能需要时查询文档即可:?match?语句?

Python?还支持?pass?语句,该语句不执行任何操作。语法上需要一个语句,但程序不实际执行任何动作时,可以使用该语句。该语句可以用作函数或条件子句的占位符,以便让开发者聚焦更抽象的层次。

函数

想必大家对函数都有所了解,相比其他语言,?Python?中的函数支持更丰富的传参方式。函数定义以?def?关键字开头:

>>> def printFib(n):
...     """打印 Fibonacci 数列
...     
...     :param n: 小于n
...     :return: None
...     """
...     a, b = 0, 1
...     
...     while a < n:
...         print(a, end=" ")
...         a, b = b, a + b
...
>>> printFib(10)
0 1 1 2 3 5 8
>>> print(printFib(10))
0 1 1 2 3 5 8 
None  # 默认返回值

# 通过help函数或函数的__doc__变量可以查看文档内容
>>> help(printFib)
Help on function printFib in module __main__:

printFib(n)
    打印 Fibonacci 数列
    
    :param n: 小于n
    :return: None

>>> print(printFib.__doc__)
打印 Fibonacci 数列
    
    :param n: 小于n
    :return: None

上诉代码块中?""" ... """?表示文档字符串,用来对函数用途以及函数参数、返回值进行说明。利用文档字符串可以自动生成在线文档或打印版文档,在代码中加入文档字符串是一个好习惯,详见?文档字符串?。在定义?printFib?函数时没有调用?return?语句显示返回值,但依然会默认返回?None?。

参数默认值

在定义函数时,我们可以同时为参数指定默认值,被指定默认值的参数在调用时是可选的:

>>> def area(length, width = None):
...     """计算长方形面积
...     
...     :param length: 长
...     :param width: 宽,默认为None;省略时计算以length为边长的正方形面积
...     :return: 长方形面积
...     """
...     if width is None:
...         width = length
...     return length * width
... 
>>> print(area(4, 3))
12
>>> print(area(4))
16

注意:形参的默认值只在函数定义时计算一次,如果参数的默认值是可变类型,那么函数的多次调用就可能会相互影响。例如下面的函数会累积后续调用时传递的参数:

>>> def f(a, l=[]):
...     l.append(a)
...     return l
... 
>>> print(f(1))
[1]
>>> print(f(2))
[1, 2]

# 推荐如下方式解决
>>> def f(a, l=None):
...     if l is None:
...         l = []
...     l.append(a)
...     return l
... 
>>> print(f(1))
[1]
>>> print(f(2))
[2]

关键字传参

默认情况下,?Python?中调用函数时可以按函数定义时形参的位置次序依次传入参数,也可以按关键字(形参名=形参值)的方式传入参数(无需按函数定义时形参的顺序传递),还可以两者混用,但?关键字传参必须在位置传参之后?:

# 还是使用前面一个小节(参数默认值)的 area 函数
# 关键字传参,未按定义顺序
>>> print(area(width=2, length=4))
8

# 位置传参和关键字传参混用
>>> print(area(8, width=4))
32

# 关键字传参在位置传参之前,报错
>>> print(area(length=1, 2))
  File "<input>", line 1
    print(area(length=1, 2))
                          ^
SyntaxError: positional argument follows keyword argument

可变参数

在我们定义函数时,不确定调用函数时会传入多少个参数的情况下,可以使用可变参数来匹配,可变参数以?*?开头,匹配的结果以元组的形式存放。比如:计算多个数的和或乘积:

>>> def calc(base, *args, operation="+"):
...     match operation:
...         case "+":
...             for i in args:
...                 base += i
...             return base
...         case "*":
...             for i in args:
...                 base *= i
...             return base
...         case _:
...             return "error"
...
# 传参时,10 匹配给base;1, 2, 3匹配给可变参数args;operation为默认值,
# 想要覆盖 operation 默认值必须使用关键字传参,否则会匹配给可变参数
>>> print(calc(10, 1, 2, 3))
16

# 传参时,10 匹配给base;1, 2, 3匹配给可变参数;operation通过关键字传参改为*
>>> print(calc(1, 1, 2, 3, operation="*"))
6

# 关键字传参不能位于位置传参之前
>>> print(calc(base = 0, 1, 2, 3))
  File "<input>", line 1
    print(calc(base = 0, 1, 2, 3))
                                ^
SyntaxError: positional argument follows keyword argument

关键字参数

通过前面的讲解,我们已经知道调用函数时可以通过关键字传参。当我们传递的关键字参数不能被函数中定义的形参完全匹配时,我们可以通过关键字参数来获取剩余未匹配的变量,关键字参数以?**?开头,匹配的结果以字典存放。

>>> def calc(base, *args, operation="+", **others):
...     if len(others) > 0:
...         print("invalid: more keyword arguments:", others)
...         return None
...     match operation:
...         case "+":
...             for i in args:
...                 base += i
...             return base
...         case "*":
...             for i in args:
...                 base *= i
...             return base
...         case _:
...             return "error"
...

>>> print(calc(1, 1, 2, 3, operation="*"))
6

>>> print(calc(1, 1, 2, 3, operation="*", otherOne = 12, otherTwo = 13))
invalid: more keyword arguments: {'otherOne': 12, 'otherTwo': 13}
None

提示:?位置参数必须在关键字参数之前?。很容易理解,因为前面已经讲过:位置传参必须在关键字传参之前。

特殊参数?/?和?*

默认情况下,?Python?中调用函数时可以按函数定义时形参的位置次序依次传入参数,也可以按关键字(形参名=形参值)的方式传入参数(无需按函数定义时形参的顺序传递),还可以两者混用。为了让代码易读、高效,可以通过?/?和?*?两个特殊参数限制调用函数时参数的传递方式:

def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
      -----------    ----------     ----------
        |                |                |
        |       位置传参或关键字传参        关键字传参
        |                                
         -- 位置传参

由图易知:?/?以前的参数只能通过位置次序依次传参,?/?以后的参数可以通过位置次序或关键字的方式传参,?*?以后的参数只能通过关键字的方式传参。特殊参数可以两个同时出现,也可以只有一个,或者一个也没有(默认)。示例如下:

>>> def f(pos_only, /, standard, *, kwd_only):
...     print(pos_only, standard, kwd_only)
...
# 正确传参
>>> f(1, 2, kwd_only=3)
1 2 3
>>> f(1, standard=2, kwd_only=3)
1 2 3

# 错误传参
>>> f(pos_only=1, 2, kwd_only=3)
  File "<input>", line 1
    f(pos_only=1, 2, kwd_only=3)
                               ^
SyntaxError: positional argument follows keyword argument
>>> f(1, 2, 3)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: f() takes 2 positional arguments but 3 were given

解包实参列表

简单来说,如果在调用函数时,我们的实参已经存放在了列表、元组或字典中,我们就可以通过?*?将元组、列表中的值按位置传参的方式传入函数,可以通过?**?将字典中的值按关键字传参的方式传入函数:

# 定义函数
>>> def add(x, y):
...     return x + y
... 

# 直接传入报错
>>> args = (3, 4)
... print(add(args))
Traceback (most recent call last):
  File "<input>", line 2, in <module>
TypeError: add() missing 1 required positional argument: 'y'

# 解包tuple
>>> args = (3, 4)
... print(add(*args))
7

# 解包list
>>> args = [3, 4]
... print(add(*args))
7

# 解包dict
>>> args = {"x": 1, "y": 2}
... print(add(**args))
3

# args元素个数与add所需参数个数不一致,报错
>>> args = [3, 4, 7]
... print(add(*args))
Traceback (most recent call last):
  File "<input>", line 2, in <module>
TypeError: add() takes 2 positional arguments but 3 were given

Lambda 表达式

通常我们可以在需要匿名函数的地方使用?lambda?表达式,他不过是一种语法糖。例如对?list?的元素进行排序:

先调用?help(list.sort)?看看?sort?函数的定义:

>>> help(list.sort)
Help on method_descriptor:

# self 参数类似于其他类中的this;key和reverse必须使用关键字传参
sort(self, /, *, key=None, reverse=False)
    # 默认升序,返回None
    Sort the list in ascending order and return None.
    # 该排序方法会修改list且是稳定性排序
    The sort is in-place (i.e. the list itself is modified) and stable (i.e. the
    order of two equal elements is maintained).
    # key要求传入一个方法,sort方法执行时,每个元素会被依次传入该方法并根据返回值进行排序
    If a key function is given, apply it once to each list item and sort them,
    ascending or descending, according to their function values.
    # 是否切换为降序排序
    The reverse flag can be set to sort in descending order.

弄清楚定义后,我们现在对?[(7, 9), (5, 6), (3, 4), (6, 5)]?分别按每个元组的第一个元素排序、第二个元素排序、两个元素之和进行排序:

使用非匿名函数:

>>> def f(x):
...     return x[0]  # 按每个元组的第一个元素排序
... a = [(7, 9), (5, 6), (3, 4), (6, 5)]
... a.sort(key=f)
... print(a)
[(3, 4), (5, 6), (6, 5), (7, 9)]

>>> def f(x):
...     return x[0]
... a = [(7, 9), (5, 6), (3, 4), (6, 5)]
... a.sort(key=f, reverse=True)  #按每个元组的第一个元素 降序 排序
... print(a)
[(7, 9), (6, 5), (5, 6), (3, 4)]

>>> def f(x):
...     return x[1]  # 按每个元组的第二个元素排序
... a = [(7, 9), (5, 6), (3, 4), (6, 5)]
... a.sort(key=f)
... print(a)
[(3, 4), (6, 5), (5, 6), (7, 9)]

>>> def f(x):
...     return x[0] + x[1]  # 按每个元组的两个元素之和排序
... a = [(7, 9), (5, 6), (3, 4), (6, 5)]
... a.sort(key=f)
... print(a)
[(3, 4), (5, 6), (6, 5), (7, 9)]

使用?lambda?表达式就无需提前定义函数且写法非常简单:

>>> a = [(7, 9), (5, 6), (3, 4), (6, 5)]
... a.sort(key= lambda x: x[0])
... print(a)
[(3, 4), (5, 6), (6, 5), (7, 9)]

>>> a = [(7, 9), (5, 6), (3, 4), (6, 5)]
... a.sort(key= lambda x: x[0], reverse=True)
... print(a)
[(7, 9), (6, 5), (5, 6), (3, 4)]

>>> a = [(7, 9), (5, 6), (3, 4), (6, 5)]
... a.sort(key= lambda x: x[1])
... print(a)
[(3, 4), (6, 5), (5, 6), (7, 9)]

>>> a = [(7, 9), (5, 6), (3, 4), (6, 5)]
... a.sort(key= lambda x: x[0] + x[1])
... print(a)
[(3, 4), (5, 6), (6, 5), (7, 9)]

函数注解

由于?Python?不需要指定变量类型,在给编码带来方便的同时会给他人调用函数带来一定的麻烦,因为这样不方便调用者弄清楚形参类型以及返回值类型。于是,函数注解的作用便显现出来:定义函数时可通过函数注解给形参以及函数返回值加上数据类型说明。例如,我们要定义一个计算两数之和的函数:

# 该函数未限制入参类型,既可以传入int型,也可以传入str型
>>> def add(x, y):
...     return x + y
... print(add(1, 2))
... print(add("1", "2"))
3
12

# 加上函数注解,你以为就可以限制入参了吗?
>>> def add(x: int, y: int) -> int:
...     return x + y
...
# 并没有什么用,只起到建议和提示的作用
>>> print(add("1", "2"))
12

# 使用help函数查看
>>> help(add)
Help on function add in module __main__:

add(x: int, y: int) -> int

# 打印函数的 __annotations__ 成员变量查看
>>> print(add.__annotations__)
{'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>}

# 如果你在给出参数类型说明的同时希望为其赋默认值,默认值可以是一个表达式,如:int = 1*10
>>> def add(x: int, y: int = 1) -> int:
...     return x + y
... 
>>> print(add(1))
2

# help可以看到默认值
>>> help(add)
Help on function add in module __main__:

add(x: int, y: int = 1) -> int

#  打印__annotations__ 变量不显示默认值
>>> print(add.__annotations__)
{'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>}

如果对你有帮助记得点赞、关注、转发哦

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-12-04 13:24:11  更:2021-12-04 13:24:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 2:39:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码