python函数进阶_函数参数,函数嵌套,作用域,递归,内置函数

161 阅读12分钟

目录

1.函数的参数

1.1 位置参数

1.2 关键字参数

1.3 默认参数

1.4 可变参数 

2.函数的嵌套

3.命名空间

3.1名称空间的访问

 3.2命名空间的加载顺序

3.3命名空间的查找顺序

4.作用域

5.全局变量和局部变量

6.global和nonlocal关键字

7.命名空间和作用域的关系

8.递归函数

 9.内置函数

1.abs()函数

2.max()函数

3.map()函数

4.filter()函数

5.zip()函数


1.函数的参数

在python中函数参数的定义方式有一下4中方式。

1)位置参数

2)关键字参数:

3)默认参数:

4)可变参数(*args,**kwargs):


1.1 位置参数

在我们在传参的时候,实参传递的顺序按照形参定义的顺序进行传递的传参方式。
实参和形参位置一一对应

def sum(num1,num2):
    print(num1+num2)

sum(1,2)

1.2 关键字参数

我们在传参的时候,以形参等于实参的形式忽略形参定义的顺序进行传参的传参方式。 

def sum(num1,num2):
    print(num1)
    print(num2)
    print(num1+num2)

sum(num2 = 2,num1 = 4)

关键字参数和位置参数同时使用:

关键字参数必须在位置参数后面定义。

def sum(num1,num2):
    print(num1)
    print(num2)
    print(num1+num2)

sum(2,num2 = 4)

1.3 默认参数

是在我们定义参数时候,我们给形参一个默认值,在我们调用函数的时候,如果不给有默认值的形参传参,会自动采用默认值。

当某个值变化小的时候,我们就可以使用默认参数。

def user_xx(name,age,gender = '男'):
    print('姓名:{},年龄:{},性别:{}'.format(name,age,gender))

user_xx('赵四',23)
user_xx('翠花',21,'女')

#输出:
#姓名:赵四,年龄:23,性别:男
#姓名:翠花,年龄:21,性别:女

注意:

函数定义的时候,默认参数、位置参数同时使用的时候,默认参数必须放在位置参数的后面

 函数参数顺序:

               位置参数、*args、默认参数、**kwargs

def func(a,*args,b =12,**kwargs):
    print(a)                    #输出--->zs                        
    print(args)                #输出--->('cc',)
    print(b)                    #输出--->s
    print(kwargs)           #输出--->{'c': 3214}

func('zs','cc',b='s',c = 3214)

1.4 可变参数 

 如果函数中的参数过多,我们定义起来非常的麻烦,调用起来也非常的麻烦,因此python给我们提供了可变参数类型。能处理比当初声明时更多的参数,会将传入的参数变成元组(*args)或者字典(**kwargs)

(1)元组参数 *args

通过给形参前面添加*使参数变成一个元组,所有传递的参数变成元组的元素

注意: args参数名称可以任意命名,但是一般我们叫他 args。

def func(*aa):
    print(aa)             #输出--->(1, 32, 4, 325, 43)
    print(aa[0], aa[1])         #输出--->1 32


func(1, 32, 4, 325, 43)

* 具有打散序列的功能:

tup = (1, 2, 3, 4) 
print(*tup)             #输出--->1 2 3 4
lst = ['1', 'a', 98]
print(*lst)             #输出--->1 a 98

def func(a,b,c):
    print(a,b,c)          

tup = (1,2,32)
func(*tup)               #输出--->1 2 32

(2)字典参数 **kwargs

通过给形参前面添加**使参数变成一个字典,所有传递的参数变成字典的键值对,这里传参要求键等于值的形式。

**kwargs结果类型是字典,传递值是以key=value方式传入

def func(**kwargs):
    print(kwargs)      #{'name': 'zs', 'age': 18, 'tell': 121243}

#func(1,2,3)    #报错,kwargs只能接受关键字参数
func(name = 'zs',age = 18,tell = 121243)

** 具有打散字典的功能

def func(name,age):
    print(name,age)

dic = {'name':'张三','age':10} 
func(**dic)                 #输出--->张三 10

注意事项:**kwargs必须放在*args后面。

函数参数总结:

定义函数时参数的顺序: 位置参数,元组参数,默认参数,字典参数。


2.函数的嵌套

在函数内部调用其他函数

def fun1():
    print('11111')
    def fun2():
        print('22222')

fun1()            #输出--->11111    不执行fun2的函数体
                                            

综合案例:

def fun1():
    print('11111')
    def fun2():
        print('22222')

fun1()

def fun1():
    print('fun1....')


def fun2():
    fun1()
    print('fun2....')


def fun3():
    fun2()
    print('fun3....')


fun3()                   


#输出结果:
'''
fun1...
fun2...
fun3...

'''

3.命名空间

Python的命名空间的本质是一个字典,用来记录变量名称和值。字典的key是变量的名称,字典的value对于的是变量的值。

例如 {‘name’:’zs’,’age’:10}

命名空间一共分为三种:局部命名空间、全局命名空间、内置命名空间

(1)局部空间:

每个函数都有自己的命名空间,叫做局部空间,它记录了函数的变量,包括函数的参数         和局部定义的变量

(2)全局空间:

每个模块拥有它自已的命名空间,叫做全局命名空间,它记录了模块的变量,包括函数、     类、其它导入的模块。

(3)内置名称空间:

任何模块均可访问它,它存放着内置的函数和异常。

input,print,str,list,tuple...


3.1名称空间的访问

局部名称空间使用 locals() 函数来访问

全局命名空间的访问使用globals()函数访问。

局部命名空间、 全局命名空间:

def func(c):
    a = 1
    b = 5
    ret = locals()
    print(ret)  # 局部命名空间{'b': 5, 'a': 1, 'c': 30}


func(30)

ret = globals()
print(ret)  #获取全局变量  输出{'__name__': '__main__', '__doc__': ...}很多内置变量的名称

 3.2命名空间的加载顺序

内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)当函数返回结果 或 抛出异常时,被删除。每一个递归调用的函数都拥有自己的命名空间。


3.3命名空间的查找顺序

当使用某个变量的时候,先从局部命名空间中找,如果能找到则停止搜索,如果找不到在去全局名称空间中查找,如果找到则停止搜索,如果找不到则到内置名称空间中查找,如果找不到则报错。

嵌套函数的情况:

     1、先在当前 (嵌套的或 lambda) 函数的命名空间中搜索

     2、然后是在父函数的命名空间中搜索

     3、接着是模块命名空间中搜索

     4、最后在内置命名空间中搜索

注意:自己的变量名称不要和内置变量名称相同,否则不能使用内置中同名的方法

4.作用域

作用域指的是变量在程序中的可应用范围。

作用域按照变量的定义位置可以划分为4类即LEGB:

Local(函数内部)局部作用域。

Enclosing(嵌套函数的外层函数内部)嵌套作用域(闭包)。

Global(模块全局)全局作用域。

Built-in(内建)内建作用域。

Python搜索4个作用域[本地作用域(L)之后是上一层结构中def或者lambda的本地作用域(E),之后是全局作用域(G)最后是内置作用域(B)(即python的内置类和函数等)]

并且在第一处能够找到这个变量名的地方停下来。如果变量名在整个的搜索过程中都没有找到,Python就会报错。

注意:

在python中,模块(module),类(class)、函数(def、lambda)会产生新的作用域,其他代码块是不会产生作用域的,也就是说,类似条件判断(if…..else)、循环语句(for x in data)、异常捕捉(try…catch)等的变量是可以全局使用的。

5.全局变量和局部变量

在函数中定义的变量称为局部变量,只在函数内部生效,

在程序一开始定义的变量称为全局变量,全局变量的作用域是整个程序。

            输出:  ls

全局变量是不可变数据类型,函数无法修改全局变量的值

a = 1

def func(b):
    b = 2
    print(b)          #   2


func(a)
print(a)                #   1

全局变量是可变数据类型,函数可以修改全局变量的值

a = [1, 2, 3, 4]


def func(b):
    b.append(65)
    print(b)           #[1,2,3,4,65]


func(a)
print(a)            #[1,2,3,4,65]

6.global和nonlocal关键字

global关键字可以将局部变量变成一个全局变量。

格式: global 变量名称

a = 10
print(id(a))

def func():
    global a        #申明a为全局变量a
    # print(id(a))    #id相同
    a = 20         #修改a的值   开辟新空间
    print(a)            #输出  20


func()
print(a)            #输出 20

nonlocal关键字可以修改外层(非全局)变量。

def outter():
    name = 'zs'
    print(id(name))

    def inner():
        nonlocal name  # 和outter中是同一变量
        print(id(name))
        name = '赵四'  # 重新开辟空间
        print(name)        #输出:'赵四'

    inner()
    print(name)      #输出'赵四'


outter()

7.命名空间和作用域的关系

命名空间定义了在某个作用域内变量名和绑定值之间的对应关系,命名空间是键值对的集合,变量名与值是一一对应关系。作用域定义了命名空间中的变量能够在多大范围内起作用。

8.递归函数

如果一个函数在内部调用自身本身,这个函数就是递归函数。

在使用递归时,需要注意以下几点:

(1).自己调用自己。

(2).必须有一个明确的递归结束条件,称为递归出口。

递归函数输出3,2,1:

def print_num(num):
    print(num)
    if num == 1:
        return
    num = num - 1
    print_num(num)
    print('------>')


print_num(3)
'''
输出结果:
3
2
1
------>
------>

'''

递归函数求阶乘:

def jiecheng(num):
    if num == 1:
        return 1
    return num * jiecheng(num - 1)


ret = jiecheng(4)
print(ret)

递归函数查找数字:

def search_num(number, start, end):      #number为需要查找的数字,start、end分别为开始结束数字
    if number == start:
        return start
    else:
        middle = (start + end) // 2
        if middle <= number:
            return search_num(number, middle, end)
        else:
            return search_num(number, start, middle)


ret = search_num(3, 1, 4)
print(ret)

 9.内置函数

1.abs()函数

求数字的绝对值

abs()     #求绝对值
ret = abs(-10)
print(ret)  # 输出--->10

2.max()函数

max(iterable, key, default) 求迭代器的最大值,其中iterable 为迭代器,max会for i in … 遍历一遍这个迭代器,然后将迭代器的每一个返回值当做参数传给key=func 中的func(一般用lambda表达式定义) ,然后将func的执行结果传给key,然后以key为标准进行大小的判断。

#简单使用max()函数
ret = max(1, 23, 44, 32, 12)
print(ret)  # 输出--->44
lst = [2, 3, 41, 31]
print(max(lst))  # 输出--->41
lst = [22, -55, 2, 11]
print(max(lst, key=abs))  # 使用key关键字指定比较规则,取绝对值后比较

列表中嵌套字典,根据'price'比较,返回最大值的所有信息 

lst = [
    {'name': 'zxb', 'price': 35},
    {'name': 'wxw', 'price': 55},
    {'name': 'lxb', 'price': 30}

]


def max_price(dic):
    return dic['price']


ret = max(lst, key=max_price)
print(ret)                     #输出:{'name': 'wxw', 'price': 55}

3.map()函数

有两个参数,第一个参数是一个函数,第二个参数是可迭代的内容。

函数会依次作用在可迭代内容的每一个元素上进行计算,然后返回一个新的可迭代内容。

求 lst 中每一个元素的平方值:

lst = [1, 3, 4]


def square(num):
    num2 = num ** 2
    return num2


ret = map(square, lst)   #返回一个迭代器
print(ret)  
for i in ret:
    print(i)       #for循环遍历输出迭代器里内容

ret = list(map(square,lst))           
print(ret)                     #转换为列表数据类型,直接输出

 4.filter()函数

filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。

该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进判,

然后返回 True 或 False,最后将返回 True 的元素放到新列表中。


lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def odd_number(num):           #定义odd_number方法,返回所有奇数
    if num % 2 == 1:
        return num

ret = filter(odd_number, lst)       #用filter函数,返回以奇数组成的新列表
for i in ret:
    print(i)

5.zip()函数

zip函数接受任意多个可迭代对象作为参数,将对象中对应的元素打包成一个tuple,

然后返回一个可迭代的zip对象.这个可迭代对象可以使用循环的方式列出其元素

若多个可迭代对象的长度不一致,则所返回的列表与长度最短的可迭代对象相同。

a = [1, 2, 3]
b = ['a', 'b', 'c']
ret = zip(a, b)
for i in ret:
    print(i)
#输出:
    (1, 'a')
    (2, 'b')
    (3, 'c')


tu1 = (('a'), ('b'))
tu2 = (('c'), ('d'))
ret = zip(tu1, tu2)
for i in ret:
    print(i)        
#输出:   
        ('a', 'c')
        ('b', 'd')

若多个可迭代对象的长度不一致,则所返回的列表与长度最短的可迭代对象相同 

 zip() 函数
 lst1 = [1,2,3]
 lst2 = ['a','b','c','d'] 
 s = zip(lst1,lst2)
 for i in s:
     print(i)

输出结果:

小练习:

要求:   [('a'), ('b')]       [('c'), ('d')]   ---->   [{'a': 'c'}, {'b': 'd'}]

第一种方法:zip()函数

lst = []
tup1 = [('a'), ('b')]
tup2 = [('c'), ('d')]
s = zip(tup1, tup2) 
print(s)       # 输出结果:('a', 'c')('b', 'd')

第二种方法: map()函数

def func(tup):  # 该函数返回两个字典
     return {tup[0]: tup[1]}

tup1 = [('a'), ('b')]
tup2 = [('c'), ('d')]
ret = map(func, s)
for i in ret:
    print(i)
    lst.append(i)
print(lst)