栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

自学Python第五天- 顺序执行、程序主入口、条件判断、循环控制、函数、命名空间和作用域

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

自学Python第五天- 顺序执行、程序主入口、条件判断、循环控制、函数、命名空间和作用域

自学Python第五天- 顺序执行、程序主入口、条件判断、循环控制、函数、命名空间和作用域
  • 顺序执行
  • 程序主入口
  • 条件判断
  • 循环控制
    • 循环的 break 和 continue
    • while 循环
    • for 循环
    • 打破外层循环
  • 函数
    • 自定义函数
    • 语法格式
    • 函数调用
    • 函数的参数
      • 形参与实参
      • 可变类型参数与不可变类型参数
      • 必须参数与选择参数(非必须参数)
      • 位置参数
      • 关键字参数
      • 默认值参数
      • 可变长度参数
      • 匿名函数
      • 参数的打包和拆包
    • 特别的函数使用方法:递归函数
  • 命名空间和作用域
    • 命名空间
    • 作用域
      • 作用域的划分
      • 使用规则
      • 作用域的形成
      • 全局变量和局部变量
      • global 和 nonlocal关键字

标识符、变量、数据类型、运算符组成了语句,多行语句就组成了程序。程序的基础就是执行方式、入口、判断和循环了。

顺序执行

python 代码执行过程中,遵循以下规则:

  • 程序按照语句顺序执行
  • 普通语句直接执行
  • 碰到函数,将函数体载入内存,并不直接执行
  • 碰到类,执行类内部的普通语句,方法只载入不执行
  • 碰到 if 、for 等控制语句,按照控制流程执行
  • 碰到 @、break、continue 等,按规定语法执行
  • 碰到函数、方法调用等,转而执行内部代码,执行完毕后继续执行原有顺序代码

python 的代码执行规则和其他语言基本一致。不同在于

  • 函数、类的定义必须在调用前载入内存,也就是说定义代码要写在调用之前。当调用时内存中没有载入就会报错。不像其他大部分语言,可以在任意地方写函数、类,均能正确调用。
  • 类内部的方法和调用顺序没有要求,因为在实例化类或调用类方法前,整个类的定义就已经加载进内存了(上一条规则)。
程序主入口

存储 python 程序代码的文件后缀是 .py ,可以通过直接运行和作为模块导入方式使用其中的代码。但是这两种方式是有区别的:

  • 直接运行:按照规则顺序执行代码
  • 导入使用:当导入时会立刻加载并执行程序主入口外的代码。
# demo1
def func_1():
	print('func_1')
def func_2():
	print('func_2')

func_1()

# 程序的主入口
if __name__ == '__main__':	# 表示程序主入口
	func_2()
# demo2
import demo1

当运行 demo1 时,查看输出结果可以发现,顺序执行了 func_1、func_2 函数。而当运行 demo2 时,查看输出结果可以发现,执行了 func_1 函数,func_2 函数并没有执行。基于这个机制,可以在作为模块被导入的文件中,不想立刻被执行的代码和调用写在主程序中。

另外,查看本文件的 name 可以看到输出值是 main ,而使用导入查看 name ,则输出的是文件或模块名。

# demo1
print(__name__)		# 以当前程序执行,输出 '__main__'
if __name__ == '__main__':
	pass
# demo2
import demo1	# 输出结果 demo1
条件判断

python 使用 if 、elif 、else 来进行条件判断。之前代码块中学到,python 在块首行以 : 结束,以缩进来表示块内容。所以 python 没有明显的块结束标识符。条件判断也可以进行嵌套使用。

件判断机制和使用方法类似于其他语言。

num_1 = int(input('请输入个整数'))
if  num_1 < 10:
	print('小于10')
elif num_1 < 30:
	print('大于等于10并小于30')
elif num_1 < 60:
	print('大于等于30并小于60')
else:
	print('大于等于60')

需注意的是,python 没有 select 、 switch 、 case 这类选择性判断。

循环控制

python 使用 while 和 for 进行循环控制。

循环的 break 和 continue

无论 while 和 for 哪种循环,都可以使用 break 和 continue 语句参与循环控制。break 和 continue 都只能写在循环体内部。

  • break 用于打破当前循环,即遇到 break 直接退出当前循环
  • continue 用于继续当前循环,即跳过该语句之后的代码,直接进入当前循环的下一次循环判断。

需要注意的是,break 和 continue 只作用于当前循环,不能作用于嵌套循环中的外层循环。

while 循环

执行到 while 循环时,判断跟随 while 的表达式是否成立(值为 True),当成立时执行循环体内的代码,然后继续判断表达式,直到表达式不成立(值为 False),则终止循环。

python 的 while 循环支持 else 方法。else 接在 while 的循环体外,当 while 循环正常结束时(即 while 判断表达式为 False 时),执行 else 内的代码。如果是被 break 结束循环时,则不执行 else 。

while 循环也可以进行嵌套。

loop = 0
str1 = input('是否终止循环?Y/N/C:').upper()
while str1 != 'Y':
    if str1 == 'N':
        loop += 1
        print(f'第{loop}次循环')
        str1 = input('是否终止循环?Y/N/C:').upper()
        continue
    elif str1 == 'C':
        print('取消循环')
        break
    else:
        print('输入错误')
    str1 = input('请重新输入?Y/N/C:').upper()
else:
    print(f'收到指令,终止循环。共循环{loop}次')
for 循环

python 中的 for 循环不能在循环判断前进行自增(除非在循环体内进行显式赋值),只是简单的类似于 whlie 的进行表达式判断。不过 for 循环可以结合 in 用于遍历可迭代的对象。for 循环也有 else 从句,可以在循环正常结束时执行。

这里需要注意了,如果不想在循环体内显式将判断变量自增,则可以使用 in range() 的方法。

range([start_number=0,]end_number) 将生成一个整数列表,其内容为从 **start_number(默认值为0) ** 到 end_number - 1 的 end_number - start_number - 1 个整数。简单说,生成的整数从 start 到 end ,只是遵循左闭右开的原则,没有 end 这个数。当 start 为默认值或 0 时,则生成共 end 个数的索引号。

所以当使用 for i in range(10): 这个循环时,i 就遍历了 0 到 9 。形成了 VB 中 For i = 0 to 9 或 C# 中 for(i=0,i<10,i++) 的循环。

# for 嵌套循环最常用的示例:九九乘法表
for i in range(1, 10):
    for j in range(1, i + 1):
        print(f'{j} * {i} = {j * i}', end='  ')
    print('')
"""
1 * 1 = 1  
1 * 2 = 2  2 * 2 = 4  
1 * 3 = 3  2 * 3 = 6  3 * 3 = 9  
1 * 4 = 4  2 * 4 = 8  3 * 4 = 12  4 * 4 = 16  
1 * 5 = 5  2 * 5 = 10  3 * 5 = 15  4 * 5 = 20  5 * 5 = 25  
1 * 6 = 6  2 * 6 = 12  3 * 6 = 18  4 * 6 = 24  5 * 6 = 30  6 * 6 = 36  
1 * 7 = 7  2 * 7 = 14  3 * 7 = 21  4 * 7 = 28  5 * 7 = 35  6 * 7 = 42  7 * 7 = 49  
1 * 8 = 8  2 * 8 = 16  3 * 8 = 24  4 * 8 = 32  5 * 8 = 40  6 * 8 = 48  7 * 8 = 56  8 * 8 = 64  
1 * 9 = 9  2 * 9 = 18  3 * 9 = 27  4 * 9 = 36  5 * 9 = 45  6 * 9 = 54  7 * 9 = 63  8 * 9 = 72  9 * 9 = 81  
"""
打破外层循环

因为嵌套循环时,内层循环不能直接 break 和 continue 外层循环,所以一般会进行曲线处理:添加外层判断标志。

flag = False 	# 循环控制标志
for i in range(1, 10):		# 正常循环,i 会循环10次
	if flag == True:		# 判断循环控制标志
		break
    for j in range(1, i + 1):
        if i == 4:			# 达到想打断外层循环的条件
        	flag = True		# 循环控制标志
        	break			# 打断内层循环
        print(f'{j} * {i} = {j * i}', end='  ')

    print('')
函数

函数是组织好的,可重复使用的,用来实现单一或相关联功能的代码段。其作用就是提高应用的模块性和代码的复用性。

自定义函数

自定义函数必须遵循以下规则

  • 函数代码块以 def 关键词开头,后接函数标识符名称、圆括号()和冒号 :
  • 圆括号里可以放入参数
  • 函数内容以缩进表示
  • return [表达式] 可以结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None
  • return 可以有多个返回值,以逗号相隔,返回一个元组
  • return 不是必须的
语法格式

函数的定义语法格式如下

def 函数名(参数列表):
    函数体

默认情况下,参数值和参数名称是按函数声明中定义的顺序匹配起来的。

函数调用

函数只有在调用时才会执行,可以直接调用执行或通过另一个函数调用执行。函数调用的格式为:

[变量名=]函数名(参数列表)
函数的参数 形参与实参
  • 形参就是函数定义中的参数,没有实际的值,通过赋值才有意义,相当于变量
  • 实参就是调用函数时传入的参数,是一个实际存在的参数

即函数定义时,使用形参作为变量使用,而在调用时,将实参传入函数给形参赋值。形参和实参变量名可以不一样,只是进行了赋值行为。

可变类型参数与不可变类型参数

可变类型和不可变类型作为参数传入函数,在使用中会有不同:

  • 不可变类型参数内容的对象是不可变的,即使形参和实参变量名一致,当有改变时只是变量指针改变了,对象本身不会发生改变。类似于其他语言的传值
  • 可变类型参数其内部对象是可变的,即使形参和实参变量名不同,指向的也是同一个可变类型的对象。所以无论在哪里将对象进行更改都会对对方造成影响。类似于其他语言的传址
必须参数与选择参数(非必须参数)

必须参数是与选择参数相对应的,不是选择参数就是必须参数。选择参数遵循以下规则

  • 定义时以方括号 [] 包围
  • 定义时根据所在位置和需要,有分隔参数用的逗号 ,

即定义选择参数时,将 [] 把可不使用的部分包围起来。调用时可以不使用 [] 表示的实参,但是一旦使用,则必须按照 [] 定义的格式使用。

def func_test1([param1,] param2)
	pass
func_test1(a)	# 不使用选择参数,实参 a 传递给 param2
func_test1(a,b)	# 使用选择参数,a 传递给 param1, b 传递给 param2

需注意的是,如果没有传递必须参数则会报错。

位置参数

位置参数就是实参传入时位置于形参一一对应,而不论变量名。

def func_test1(param1,param2,param3)
	pass
# 按照位置对应关系将实参传递给形参,即 a->param1, b->param2, c->param3
func_test1(a,b,c)	
关键字参数

以形参=实参的方式指定参数,而不论参数位置

def func_test1(param1,param2,param3)
	pass
func_test1(param3=10,param1='hello',param2=10.5)
默认值参数

用函数时,如果没有传递参数则参数会使用默认值,这种参数叫做默认值参数。默认值参数在定义时需要赋值给形参。

def func_test1(param1,param2=10)
	pass
# 即使传参时没有给默认值参数传递实参也可以,形参的值就是默认值。
func_test1('hello')
# 也可以将实参传递给默认值参数,传递的值覆盖默认值
func_test1('hello',16)
可变长度参数

可变长度参数也叫不定长参数。如果不知道具体会传递进多少个参数,或需要一个函数能处理比当初声明时更多的参数,可以使用可变长度参数。

可变长度参数语法为 一(二)个星号 " * " 加参数名称。一个星号表示此可变长参数为元组,二个星号表示此可变长参数为键值对。例:

def printinfo( arg1, *vartuple ):
   print (arg1)
   print (vartuple)
printinfo( 70, 60, 50 )		
# 输出结果
# 70
# (60, 50)
printinfo(70)
# 输出结果
# 70
# ()

可以看到传递的实参被转换成了元组进行保存和使用,即使其元素内容为空。

def printinfo( arg1, **vardict ):
   print ("输出: ")
   print (arg1)
   print (vardict)
printinfo(1, a=2,b=3)
# 输出结果
# 1
# {'a': 2, 'b': 3}

即传递的实参被转换成了字典,以键值对形式使用。

使用可变长参数时,其后有其他参数传参时会混淆,所以 python3 规定可变长参数之后的参数必须使用关键字参数。

匿名函数

Python 使用 lambda 来创建匿名函数。所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。

  • lambda 只是一个表达式,函数体比 def 简单很多。
  • lambda 的主体是一个表达式,而不是一个代码块。仅仅能在 lambda 表达式中封装有限的逻辑进去。
  • lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
  • 虽然 lambda 函数看起来只能写一行,却不等同于 VB 或 C# 等的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。

匿名函数的格式为 函数名 = lambda 位置参数 : 函数体

x = lambda a : a + 10
print(x(5))
# 输出结果
# 15
sum = lambda arg1, arg2: arg1 + arg2
print ("相加后的值为 : ", sum( 10, 20 ))
# 输出结果
# 相加后的值为 :  30

匿名函数经常用于 map() 、 filter() 等需要将函数作为参数调用的方法。

参数的打包和拆包

在使用可变长参数时,将多个实参传入给形参,形成了一个打包行为。我们也可以传递一个实参赋值给多个形参,形成拆包。

def func_1(*tu):
    return tu

def func_2(a, b, c):
    # 尽管返回的是多个变量,但是返回结果打包成元组
    return a, b, c

a, b, c = 1, 2, 3
# 传入三个变量,在函数处打包成元组
tu = func_1(1, 2, 3)
print(tu)
# 传入一个元组,在函数处拆包成变量/返回应该是多个变量,但是结果其实打包成元组
tu1 = func_2(*tu)  # 元组前加星号 * 表示可以进行拆包
print(tu1)
# 返回元组,拆包成多个变量
d, e, f = func_2(a, b, c)
print(d, e, f)

需注意的是,打包和拆包的元组需加 * ,表示进行打包/可拆包。并且在函数中不能引起歧义。如上例中,如果 d, e, f = func_1(a, b, c) 就会出错。

特别的函数使用方法:递归函数

函数直接或间接调用函数本身,则该函数为递归函数。

def get_nums(num):
	if num > 1:
		return num * get_nums(num - 1)
	else:
		return 1

res = get_nums(4)
print(res)

需要注意的是,递归必须自己设置结束条件,即在函数中不再调用自身。否则将一直调用自身成为死循环。

另能够使用递归实现的都能用循环实现。递归效率低,但是代码简单。循环效率高,但是代码实现稍复杂。

命名空间和作用域 命名空间

命名空间(Namespace)是从名称到对象的映射,大部分的命名空间都是通过 Python 字典来实现的。命名空间提供了在项目中避免名字冲突的一种方法。各个命名空间是独立的,没有任何关系的,所以一个命名空间中不能有重名,但不同的命名空间是可以重名而没有任何影响。

一般有三种命名空间:

  • 内置名称(built-in names), Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等。
  • 全局名称(global names),模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
  • 局部名称(local names),函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)

命名空间查找顺序:

假设我们要使用变量 a,则 Python 的查找顺序为:局部命名空间 -> 全局命名空间 -> 内置命名空间。如果找不到,则放弃查找并引发一个 NameError 异常: NameError: name ‘a’ is not defined。 即名称没有被定义。

命名空间的生命周期:

命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束。因此,我们无法从外部命名空间访问内部命名空间的对象。

# var1 是全局名称
var1 = 5
def some_func():
 
    # var2 是局部名称
    var2 = 6
    def some_inner_func():
 
        # var3 是内嵌的局部名称
        var3 = 7
作用域

作用域就是一个 Python 程序可以直接访问命名空间的正文区域。在一个 python 程序中,直接访问一个变量,会从内到外依次访问所有的作用域直到找到,否则会报未定义的错误。程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。

作用域的划分

Python 的作用域一共有4种,分别是:

  • L(Local):局部作用域,是最内层,包含局部变量,比如一个函数/方法内部。
  • E(Enclosing):嵌套的父级函数的局部作用域,也叫闭包函数作用域。包含了非局部(non-local)也非全局(non-global)的变量。例如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数B,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
  • G(Global):全局作用域,当前脚本的最外层,比如当前模块的全局变量。
  • B(Built-in):内建作用域,包含了系统固定的变量/关键字等,比如 int() 等。
使用规则

规则顺序: L –> E –> G –> B。在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。

g_count = 0  # 全局作用域
def outer():
    o_count = 1  # 闭包函数外的函数中
    def inner():
        i_count = 2  # 局部作用域

内置作用域是通过一个名为 builtin 的标准模块来实现的,但是这个变量名自身并没有放入内置作用域内,所以必须导入这个文件才能够使用它。在Python3.0中,可以使用以下的代码来查看到底预定义了哪些变量:

>>> import builtins
>>> dir(builtins)
作用域的形成

Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问,如下代码:

>>> if True:
...  msg = 'Hello World!'
... 
>>> msg
'Hello World!'
>>> 
全局变量和局部变量

定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。如下实例:

total = 0 # 这是一个全局变量
def sum( arg1, arg2 ):
    #返回2个参数的和."
    total = arg1 + arg2 # total在这里是局部变量.
    print ("函数内是局部变量 : ", total)
    return total
#调用sum函数
sum( 10, 20 )
print ("函数外是全局变量 : ", total)
# 输出结果:
# 函数内是局部变量 :  30
# 函数外是全局变量 :  0
global 和 nonlocal关键字

当内部作用域想修改外部作用域的变量时,就要用到 global 和 nonlocal 关键字了。

num = 1
def fun1():
    global num  # 需要使用 global 关键字声明
    print(num) 
    num = 123
    print(num)
fun1()
print(num)
# 输出结果:
# 1
# 123
# 123

即使用了 global 关键字,在函数内部同局部变量一样直接操作全局变量 num

同样,使用 nonlocal 声明变量 num 是外部的闭包函数内的变量

def outer():
    num = 10
    def inner():
        nonlocal num   # nonlocal关键字声明
        num = 100
        print(num)
    inner()
    print(num)
outer()
# 输出结果:
# 100
# 100

另需注意的是,在局部作用域找不到的变量是可以根据顺序从上级查找的,也就是说这样是可以的:

a = 100
def test_1()
	print(f'a = {a})

但是这样的方式只能使用,并不能进行修改,因为未声明 global 和 nonlocal 。例

a = 10
def test():
	# 错误的使用方式。a 作为局部变量未定义,作为全局变量未声明 global
    a = a + 1	
    print(a)
test()
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/951610.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号