python学习笔记8

一、python中的函数

函数是组织好的可重复使用的,用来实现单一或相关功能的代码段。

函数能提高应用的模块性,和代码的重复利用率

函数的结构:

# 函数基本结构
def 函数名(参数):
	函数体
# 函数示例
# 下面是一个求字符串列表长度的函数
def len_func(s): # len_func是函数名,s是函数的输入参数
    count = 0
    for i in s: # 循环遍历所求对象
        count += 1 # 用count对长度进行计数
    return count # 返回长度值

一般来说,要求函数名具有描述性。

函数调用方法:函数名+()

# 在定义了上述len_func函数的基础上进行调用
li = [1,2,3,34,56,7]
num = len_func(li) # 这里赋给num的是函数返回的count值
print(num) # 6

函数的返回值:在上面定义的函数中,函数返回了return语句后面的变量值。事实上,python中函数的返回值正式由return语句控制的,注意当函数运行过程中执行了一次return语句后,函数直接跳出,不在执行后续语句。

# 示例函数
def test_1():
    print('hello',end=',')
    print('world')
test_1() # 正常情况下输出 hello,world
# 当加入return语句时
def test_2():
    print('hello',end=',')
    return
    print('world')
test_2() # 此时函数输出 hello,
# 知识因为函数执行到return语句后就跳出函数了,print('world')并没有执行

当返回的数有多个时,会将数据存放在一个元组里返回给执行者

# 多个返回值的情况
def test_3():
    return 'abc',[1,2,3],{'name':'Lieve'}
s = test_3()
print(s,type(s)) # ('abc', [1, 2, 3], {'name': 'Lieve'}) <class 'tuple'>
# 此时可以利用元组的拆包性质将数据赋值给多个变量
s1,s2,s3 = test_3()
print(s2,type(s2)) # [1, 2, 3] <class 'list'>
# 此时变量数据类型是数据原本的类型

函数的参数:在前面定义的函数中,len_func和test_1函数在调用的时候,一个在括号里输入了变量而另一个没有,这个输入的变量就叫做函数的参数。由于函数是封装好的功能,所以传入参数就是为了将其对应的函数功能盘活。

函数的参数又实参和形参。其中函数执行传入的参数是实际参数,函数定义时接收的参数是形式参数。

从函数实参的角度出发:

  1. 位置参数:从左到右,实际参数与形式参数按照顺序一一对应。
  2. 关键字参数:关键字与相应参数一一对应,但是并不一定要按照顺序输入。
  3. 混合参数:上面两者都有。但是此时位置参数一定要在关键字参数前面。

从形参的角度出发:

  1. 位置参数:与实参的位置参数是一种,与之一一对应。
  2. 默认值参数:在定义函数的时候,给参数设置了常用的默认值,当实际参数没有默认值参数赋值时按照默认值运行。如需修改,需要在函数调用时对参数进行赋值。
    默认参数的陷阱:对于可变(不可哈希)数据类型的默认参数
def func(name,alist=[]):
    alist.append(name)
    return alist
res_1 = func('Lieve')
print(res_1) # ['Lieve']	
res_2 = func('Luo')
print(res_2) # ['Lieve', 'Luo']
# 这里alist这个默认参数被修改了

# 函数的默认参数是可变的数据类型时,调用这个函数时如果默认参数没有传入
# 则始终使用的是同一个数据
def func_test(a,list_1=[]):
    list_1.append(a)
    return list_1
# 默认参数list_1没有传入数据时,默认为[]
print(func_test(10)) # [10]
# list_1传入数据时,优先使用传入数据
print(func_test(20,[100])) # [100,20]
# list_1再次没有传入数据时,使用的是之前引用过的[10]
print(func_test(30)) # [10,30]
#相当于下面程序的操作
li_1 = []
li_1.append(10)
print(li_1) # [10]
li_2 = [100]
li_2.append(20)
print(li_2) # [100,20]
li_1.append(30)
print(li_1) # [10,30]
  1. 万能参数:一种是可以接受所有位置参数的万能参数(形参)。这种参数需要在参数名称前加上*,形如
def my_func(*args):
    print(args)
    print('%s,%s,%s,%s.'%args) # 这里%s的个数需要与args中元素个数一致
# 调用函数
my_func('a',[1,2,3],'b','c') 
# ('a', [1, 2, 3], 'b', 'c')
# a,[1, 2, 3],b,c.
# 这里*args代表函数参数是一个万能参数
# 它将输入的一系列位置参数聚合成一个元组赋值给args。

另一种是可以接受所有关键字参数的万能参数(形参)。这种参数需要在参数名称前加上**,形如:

def my_func_1(**kwargs):
    print(kwargs)
# 调用函数
my_func_1(a=1,b=2,c='a',d=[1,2,3])
# {'a': 1, 'b': 2, 'c': 'a', 'd': [1, 2, 3]}
# 这里**kwargs代表函数参数是一个万能参数
# 它将输入的一系列关键字参数聚合成一个元组赋值给kwargs。

形参角度参数的顺序:位置参数>>>接受位置参数的万能参数>>>关键字参数>>>仅限关键字参数>>>接收关键字参数的万能参数。

# 在函数的调用中,*表示将原本数据结构拆散。
def func_1(*args,**kwargs):
    print(args,kwargs)
func_1([1,2,3],[4,5,6]) # ([1,2,3],[4,5,6]) {}
func_1(*[1,2,3],*[4,5,6]) # (1, 2, 3, 4, 5, 6) {}
func_1({'name':'Lieve'},{'age':22}) # ({'name': 'Lieve'}, {'age': 22}) {}
func_1(**{'name':'Lieve'},**{'age':22}) # () {'name': 'Lieve', 'age': 22}

python中分为三个空间:

  1. 内置名称空间:builtins.py
  2. 全局名称空间:当前的.py文件
  3. 局部名称空间:对于定义的函数,只有在函数执行时才开辟
    三个空间的加载顺序:内置名称空间>>>全局名称空间>>>局部名称空间
    三个空间的取值顺序:就近原则,单向不可逆

python中的作用域:

  1. 全局作用域:内置名称空间,全局名称空间
  2. 局部作用域:局部名称空间(可从全局作用域获取变量,但是不能修改)
n = 1
def func_2():
    print(n)
func_2() # 1  此时局部引用了全局变量n

def func_3():
    n = 100
    print(n)
func_3() # 100  此时函数内重新定义了n
print(n) # 1  但是全局变量并没有修改

def fun_4():
    n = n+1
    print(n)
func_4() # NameError: name 'func_4' is not defined
# 当在局部作用域修改一个全局变量时
# python解释器默认你在局部作用域定义了一个新的变量
# 并且此时的修改操作是作用在这个新变量上

def func_5():
    num = 1
    def func_6():
        num += 1
        print(num)
 	print(num)
func_5() 
# UnboundLocalError: local variable 'num' referenced before assignment
# 此时内层函数也是只能调用num,不能修改

内置函数globals()、locals()

  1. globals():返回一个字典,字典里面的键值对是全局作用域里面的所有内容
  2. locals():返回一个字典,字典里面的键值对是当前作用域里面的所有内容

全局变量和局部变量的声明:

global:

  1. 局部作用域声明一个全局变量
# 一种易错情形
def func_t():
    global a
    a = 'hello'
print(a) # NameError: name 'a' is not defined
# 因为定义全局变量是函数内部的操作,所以在函数执行前这个变量并没有定义
func_t()
# 函数运行后定义了全局变量a
print(a) # hello
  1. 修改一个全局变量
n = 1
def func():
    global n # 此时函数内的n不再是局部变量而是全局变量
    n += 1
    print(n)
func() # 2

nonlocal:功能跟global类似

  1. 不能操作全局变量
  2. 局部作用域:内层函数对外层函数的局部变量进行修改