python基本逻辑(函数)语句
author:Once Day date:2022年2月18日
本文档在于总结相关内容,零散的知识难以记忆学习。
本文档基于windows平台。
全系列文档查看:python基础_CSDN博客。
文章目录
1.基本规则
Python代码在执行过程中,遵循下面的基本原则:
- 普通语句,直接执行;
- 碰到函数,将函数体载入内存,并不直接执行
- 碰到类,执行类内部的普通语句,但是类的方法只载入,不执行
- 碰到if、for等控制语句,按相应控制流程执行
- 碰到@,break,continue等,按规定语法执行
- 碰到函数、方法调用等,转而执行函数内部代码,执行完毕继续执行原有顺序代码
这里推荐阅读参考文档:python 顺序执行 - 刘江的python教程 (liujiangblog.com)。
2. if __name__ == '__main__'
__name__
是所有模块的内置属性:
- 导入的时候,默认值为文件名,即
__name__
=filename - 直接运行时
__name__
=__main__
很明显,可以用这个值来判断导入和运行两种情况!
3.条件判断
Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块。
3.1 if /elif/else
if condition1:
statement1
elif condition2:
statement2
else:
statement3
基本结构如上,但可以拓展以及镶嵌。
编程新手推荐阅读以下文档:
3.2 match-case(python3.10)
在其他语言(比如说经典的C语言)中有一种多分支条件判断语句,即switch。
具体描述请参考其他语言选择结构,这里只上例子!
match variable: #这里的variable是需要判断的内容
case ["quit"]:
statement_block_1 # 对应案例的执行代码,当variable="quit"时执行statement_block_1
case ["go", direction]:
statement_block_2
case ["drop", *objects]:
statement_block_3
... # 其他的case语句
case _: #如果上面的case语句没有命中,则执行这个代码块,类似于Switch的default
statement_block_default
推荐阅读:PEP 622 – Structural Pattern Matching | Python.org
4.循环while、for
直接上例子,编程新手可以参考以下文档:
直接while和for循环:
while 判断条件:
statements
for <variable> in <sequence>:
<statements>
else:
<statements>
循环后接else:
for/while xxx:
xxxxxx
else:
xxxxx
循环语句可以有 else 子句;它在穷尽列表(for 循环)或条件变为假(while 循环)循环终止时被执行。
当循环被break终止时,不会执行else中的语句。
5.中断操作break,continue
注意:Python的break只能退出一层循环
break用于中断循环,即直接结束循环。
continue用于结束当前轮循环。
编程新手推荐阅读下列文档:python 循环控制 - 刘江的python教程 (liujiangblog.com)
例子:
for:
break/continue;
6.pass语句
pass 语句什么都不做。它只在语法上需要一条语句但程序不需要任何操作时使用。
>>> while True:
... pass # 等待键盘中断 (Ctrl+C)
>>> class MyEmptyClass:
... pass
7.Python函数
编程新手推荐阅读:
- Python3 函数_w3cschool
- python 函数 - 刘江的python教程 (liujiangblog.com)
- python 函数基础 - 刘江的python教程 (liujiangblog.com)
- python 参数类型 - 刘江的python教程 (liujiangblog.com)
- python 变量作用域 - 刘江的python教程 (liujiangblog.com)
本文章是总结性质,所以这些编程语言通用概念的地方会概括性描述!以节约时间精力.
7.1 函数定义
def 函数名(参数):
"""
这里是函数的说明文档,doc的位置
:param lis: 参数列表的说明
:return: 返回值的说明
"""
# 内部代码
return 表达式
注意:
- 函数的第一行语句后可以选择性地使用文档字符串—用于存放函数说明。
- 使用return结束函数。默认返回None。可以是表达式及任意对象。
注意:return是可以放在判断语句中用以快速结束函数!当然后面代码会被忽略!
def func():
return 1,2,3,....
r1,r2,r3,...=func()
注意return可以返回多个值
7.2 函数参数类型
编程新手强烈建议阅读:python 参数类型 - 刘江的python教程 (liujiangblog.com)。
下面的描述是基于对c和c++语言已经熟悉且有一定的编程经历
需要注意Python的函数参数传递的是实际对象的内存地址。
对于可变类型,相当于C语言传递指针进去!所以可修改外部变量的值。
对于不可变类型,等同于C语言传递值进去,无法影响外部变量的值。
位置形参数,要求形参和实参一一对应。
def add(a,b,c): xxxxxx add(1,2,3)#a=1,b=2,c=3
默认参数,当不提供实参时,用默认参数代替。默认参数需要在位置参数后面
def student(name, sex, age, classroom="101", tel="88880000", address="..."): pass student('mary','female',18,tel='666666','beijing') # 这是错误的参数传递方式 student("mary","female",18,tel="666666",address="beijing")
注意一切没有提供参数名的实际参数,都会当做位置参数按顺序从参数列表的左边开头往右匹配!
使用参数名传递参数时,可以不按顺序填入。
默认参数尽量指向不变的对象!,这个机制挺奇怪的!
动态参数。Python的动态参数有两种,分别是
*args
和**kwargs
,名字可以任取。注意:动态参数,必须放在所有的位置参数和默认参数后面!
def func(name, age, sex='male', *args, **kwargs): pass
*args一个星号表示接收任意个参数。调用时,会将实际参数打包成一个元组传入形式参数。如果参数是个列表,会将整个列表当做一个参数传入。
def func(*args): xxxxxx li = [1, 2, 3] func(li)#这样调用列表被当成整体传入 func(*li)#这样序列对象会将内部元素逐一作为参数传入进去。字典是把key传进去。
*kwargs两个星表示接受键值对的动态参数,数量任意。调用的时候会将实际参数打包成字典。
def func(**kwargs): xxxxxx func(k1='v1', k2=[0, 1, 2])#类似指定参数名的参数传递,但是会被收集起来,形式key=value dic = { 'k1': 'v1', 'k2': 'v2' } func(**dic)#需要双引号将字典键值对逐一传递过去。
当
*args
和**kwargs
组合起来使用,理论上能接受任何形式和任意数量的参数,*args
必须出现在**kwargs
之前.注意,*和**只是把序列和字典转变成位置参数和关键字参数,然后再进行参数收集。
所以还是要遵守位置参数和使用参数名传递参数的规则。
关键字参数,关键字参数前面需要一个特殊分隔符
*
和位置参数及默认参数分隔开来,*
后面的参数被视为关键字参数。关键字参数必须传入参数名,不然将报错!def student(name, age, *, sex): pass
有了一个
*args
参数,后面就不再需要分隔符*
了。def student(name, age=10, *args, sex, classroom, **kwargs): pass
7.3 (函数)变量作用域
作用域指的是变量的有效范围。
编程新手建议阅读:python 变量作用域 - 刘江的python教程 (liujiangblog.com)
注意下面的描述是基于对c和c++中变量作用域已经熟悉的情况!
python中没有块级作用域,if/for/while等语句内部变量对外部可见。但建议采取C语言先定义再使用的风格!
if True: x=145 print(x) #x=145 不存在块级作用域 #推荐以下编程风格 x=0 if True: x=145 print(x)
python有四层作用域,
- local局部作用域
- Enclosing 闭包函数外的函数作用域
- Global全局作用域
- Built-in内建作用域
查找顺序:Local->Enclosing->Global->Built-in
局部变量是相对的,可能被更小范围内的函数范围。
在函数内部修改外面的全局变量,要使用关键字global。注意这和访问不同!访问外部变量,无需声明也可以实现访问。
使用
nonlocal
关键字!它可以修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量。任何函数内部要被修改的变量,如果没有使用关键字,则默认为局部变量。
Python函数的作用域取决于其函数代码块在整体代码中的位置,而不是调用时机的位置。
7.4 递归函数
递归函数最好的用处就是简单化编程!
编程新手应阅读数学递归的思想,以及阅读以下文章:
递归函数的优点是定义简单,代码量少,逻辑清晰。与递归相对的是迭代(循环等),绝大多数递归问题也能用迭代法解决,但是逻辑上不如递归明确。
注意极少数问题是无法用迭代和递归解决的,因为时间及空间复杂度增长过快.(而递归主要是空间复杂度高)。
对于递归,需要注意递归深度,在Python中,通常情况下,这个深度是1000层,超过将抛出异常。
7.5 匿名函数
推荐直接阅读:python 匿名函数 - 刘江的python教程 (liujiangblog.com)
以下只是从上面文章的摘抄总结:
创建函数时,有些时候,不需要显式地定义函数,可省略命名。
Python语言使用lambda
关键字来创建匿名函数。
所谓匿名,即不再使用def
语句这样标准的形式定义一个函数。
- lambda只是一个表达式,而不是一个代码块,函数体比def简单很多。
- 仅仅能在lambda表达式中封装有限的逻辑。
- lambda 函数拥有自己的命名空间。
其形式通常是这样的:lambda 参数: 表达式
。
例如:lambda x: x * x
。它相当于下面的函数:
def f(x):
return x * x
关键字lambda表示匿名函数,冒号前面的x表示函数参数,x*x是执行代码。
匿名函数只能有一个表达式,不用也不能写return语句,表达式的结果就是其返回值。
匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数
8.Python推导式
详细阅读推荐以下文章:
注意以下内容只是从上面文章的摘抄总结:
8.1 列表推导式
一种快速生成列表的方式。其形式是用方括号括起来的一段语句。
>>> [x * x for x in [1,2,3,4,5,6]]
[1, 4, 9, 16, 25, 36]
很明显,遍历列表,把值代入表达式计算,结果排列成列表。
更直接理解,直接把表达式在列表的每个元素中计算一遍!
使用条件语句:
>>> [x * x for x in [1,2,3,4,5,6] if x%3 ==0 ]
[9, 36]
使用嵌套循环:
>>> [x * y for x in [1,2,3,4,5,6] for y in [1,10]]
[1, 10, 2, 20, 3, 30, 4, 40, 5, 50, 6, 60]
遍历+解包数据
>>> [x + y for x,y in [(1,10),[2,3],(4,5),'sh',['once','day']]]
[11, 5, 9, 'sh', 'onceday']
**只给出x和y,所以包里只能有两个元素!**否则将报错!
>>> [x + y for x,y in [(1,10),[2,3],(4,5),'shd',['once','day']]]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <listcomp>
ValueError: too many values to unpack (expected 2)
8.2 字典推导式
快速生成字典。
>>> {x: x+x for x in [2,'onceday',45]}
{2: 4, 'onceday': 'oncedayonceday', 45: 90}
8.3 集合推导式
注意没有冒号:
>>> {x+x for x in [2,'onceday',45]}
{'oncedayonceday', 90, 4}
9.迭代器
迭代:循环遍历对象的每一个元素的过程。
在Python中,list/tuple/string/dict/set/bytes都是可以迭代的数据类型。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往后遍历不能回溯,不像列表,你随时可以取后面的数据,也可以返回头取前面的数据。迭代器通常要实现两个基本的方法:iter()
和 next()
。
>>> l='onceday'
>>> it=iter(l)
>>> it
<str_iterator object at 0x000002C1507B93D0>
>>> next(it)
'o'
>>> next(it)
'n'
实现迭代器类需要实现__iter__()
和__next__()
方法。
Python的for循环本质上就是通过不断调用next()函数实现的。
迭代器对象可以使用常规 for 语句进行遍历。
推荐阅读:
10.生成器
在 Python 中,使用了 yield 的函数被称为生成器(generator)。
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值。并在下一次执行 next() 方法时从当前位置继续运行。
def fibonacci(n): # 生成器函数 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
通过圆括号可以编写生成器推导式:
>>> g=(x * x for x in [1,2,3,4])
>>> g
<generator object <genexpr> at 0x000002C150C0CC80>
生成式的值应该通过next函数来访问!但是当最后一个元素被访问后,再次访问就会抛出错误。
使用for遍历则不会抛出错误!
推荐阅读:
11.装饰器
装饰器(Decorator):从字面上理解,就是装饰对象的器件。可以在不修改原有代码的情况下,为被装饰的对象增加新的功能或者附加限制条件或者帮助输出。
装饰器的语法是将@装饰器名,放在被装饰对象上面。
@dec
def func():
pass
注意编程新手需要对函数有深入的了解!推荐直接阅读文章:
11.1 基础装饰器
装饰器的语法规则是:被装饰的函数的名字会被当作参数传递给装饰函数。装饰函数执行它自己内部的代码后,会将它的返回值赋值给被装饰的函数。
注意程序第一次读入@dev时也会执行一遍内部代码,应该是初始化全部变量(代码)部分!
def outer(func):
#全局部分,被装饰函数初始化会执行一遍
print("初始化装饰函数")
def inner():
print("准备使用函数!")
result = func()
print("使用函数结束")
return result
return inner
@outer
def f1():
print("调用函数f1......")
@outer
def f2():
print("调用函数f2......")
#输出结果
初始化装饰函数
初始化装饰函数
f1()
f2()
#输出结果
准备使用函数!
调用函数f1......
使用函数结束
准备使用函数!
调用函数f2......
使用函数结束
可以用*args和**kwargs
传进任意参数:
def outer(func):
#全局部分,被装饰函数初始化会执行一遍
print("初始化装饰函数")
def inner(name='none',age=None):
print("准备使用函数!")
result = func(name,age)
print("使用函数结束")
return result
return inner
@outer
def f1(name,age=18):
print("调用函数f1......")
print(name)
print(age)
@outer
def f2():
print("调用函数f2......")
f1('onceday')
f2()
#输出结果
初始化装饰函数
初始化装饰函数
准备使用函数!
调用函数f1......
onceday
None
使用函数结束
准备使用函数!
TypeError: f2() takes 0 positional arguments but 2 were given
可以看到,传统的固定参数形式,无法适配不同函数传递参数的多样性!
def outer(func):
#全局部分,被装饰函数初始化会执行一遍
print("初始化装饰函数")
def inner(*args,**kwargs):
print("准备使用函数!")
result = func(*args,**kwargs)
print("使用函数结束")
return result
return inner
@outer
def f1(name,age=18):
print("调用函数f1......")
print(name)
print(age)
@outer
def f2():
print("调用函数f2......")
f1('onceday')
f2()
#输出结果
初始化装饰函数
初始化装饰函数
准备使用函数!
调用函数f1......
onceday
18
使用函数结束
准备使用函数!
调用函数f2......
使用函数结束
可以看到,输出结果符合预期!
11.2 多重装饰器
可以使用多个装饰器修饰一个函数
def outer(func):
# 全局部分,被装饰函数初始化会执行一遍
print("初始化装饰函数")
def inner(*args, **kwargs):
print("准备使用函数!")
result = func(*args, **kwargs)
print("使用函数结束")
return result
return inner
def outer2(func):
# 全局部分,被装饰函数初始化会执行一遍
print("初始化装饰函数2")
def inner(*args, **kwargs):
print("准备使用函数!2")
result = func(*args, **kwargs)
print("使用函数结束2")
return result
return inner
@outer
@outer2
def f1(name, age=18):
print("调用函数f1......")
print(name)
print(age)
@outer
def f2():
print("调用函数f2......")
f1('onceday')
#输出结果
初始化装饰函数2
初始化装饰函数
初始化装饰函数#可以看到内圈的先被调用
准备使用函数!
准备使用函数!2
调用函数f1......
onceday
18
使用函数结束2
使用函数结束
11.3 装饰器函数函数
从以下代码不难看出,装饰器内部代码是逐级深入的,而且运行的时间也不一样,外层在初始化时使用,内层在调用时运行!
def outer(test,func_id):
# 全局部分,被装饰函数初始化会执行一遍
print("外层初始化装饰函数")
print(test)
print(func_id)
def midd(main_func):
# 全局部分,被装饰函数初始化会执行一遍
print("中层初始化装饰函数")
def inner(*args, **kwargs):
test(*args,**kwargs)
print("准备使用函数!"+str(func_id))
result = main_func(*args, **kwargs)
print("使用函数结束")
return result
return inner
return midd
def funt(name='none'):
print("是这个名字吗:")
print(name)
@outer(funt,1)
def f1(name, age=18):
print("调用函数f1......")
print(name)
print(age)
@outer(funt,2)
def f2():
print("调用函数f2......")
print('***********')
f1('onceday')
print('***********')
f2()
print('***********')
#输出结果
外层初始化装饰函数
<function funt at 0x000001EC27D7C700>
1
中层初始化装饰函数
外层初始化装饰函数
<function funt at 0x000001EC27D7C700>
2
中层初始化装饰函数
***********
是这个名字吗:
onceday
准备使用函数!1
调用函数f1......
onceday
18
使用函数结束
***********
是这个名字吗:
none
准备使用函数!2
调用函数f2......
使用函数结束
***********
13.基本数据结构
这部分不介绍,只推荐文档,仅供新手阅读: