python函数学习总结

函数

一、函数定义

python中用def关键字来定义函数

def fun(形参列表):
    语句块

二、形参,实参

形参:形式参数,在定义函数时括号中定义的参数

实参:实际参数,在调用函数时实际传入的参数

三、传参

python的传参采用的是一种“传对象引用”的方式,传参传的是对象的引用,如果传的是不可变对象,在函数中改变参数的值时,会创建新的对象,并不会改变原始对象,相当于“值传递”;如果传的时可变对象,在函数中改变参数的值时,会直接修改原始对象,相当于“传引用

#! /usr/bin/python3
# -*- congfig:utf-8 -*-
def fun(n,l):
    n += 1
    l.append(10)
    print("不可变对象-修改后的对象%s"%n)
    print("可变对象-原对象%s"%l)

if __name__ == "__main__":
    a = 1
    list1 = [1,2,3,4]
    fun(a,list1)
    print("不可变对象-原对象%s"%a)
    print("可变对象-原对象%s"%list1)

执行结果:

不可变对象-修改后的对象2
可变对象-原对象[1, 2, 3, 4, 10]
不可变对象-原对象1
可变对象-原对象[1, 2, 3, 4, 10]

四、参数类型

1、位置参数(传实参时):

比传参数

传递实参的数量和位置必须和定义时的形参一一对应

2、关键字参数(传实参时)

比传参数

采用“形参名=实参”的方式传递实参,这种方式不需要与定义时的形参位置一一对应,python会自动根据形参名匹配

注意:关键字参数必须在位置参数后面

3、默认参数(定义形参时)

非比传参数

在定义形参时就要为其设置默认值,可以传参也可以不传参,对变化较小的参数可以定义成默认参数

注意:

1、默认参数在定义时应该放在形参的右面

2、默认参数同城应该定义成不可变类型

4、可变长参数

非比传参数

可变长参数指的是参数的个数不固定

由于传实参有按位置和按关键字两种方式,所以可变长参数也有两种

4.1、*args

定义形参时在参数名前加一个“”号,通常用args表示

它把传入的元素存放在一个元祖里,不限制传入参数的个数,用作参数比较多的时候

在传实参时,可以传递多个值,也可以传入一个元祖(列表、range(x))前面加一个“*****”

#! /usr/bin/python3
# -*- congfig:utf-8 -*-
def fun(*args):
    print(args)
    print(type(args))

if __name__ == "__main__":
    a = 1
    list1 = [1,2,3,4]
    fun(1,2,3,4)
    fun(*list1)		#列表前必须加*
    fun(*range(10))

4.2、**kwargs

定义形参时在参数名前加两个“*”号,通常用**kwargs表示

它把传入的元素存放在一个字典里

在传实参时,可以传递多个值必须时k=v的形式,也可以传入一个字典前面加两个“*****”

#! /usr/bin/python3
# -*- congfig:utf-8 -*-
def fun(**kwargs):
    print(kwargs)
    print(type(kwargs))

if __name__ == "__main__":
    fun(a=1,b=2,c=3)
    dict1 = {"a":1,"b":2,"c":3}
    fun(**dict1)		#字典前必须加**

4.3、(*args,**kwargs)

(*args,**kwargs)表示可以传递任何类型任何数量的参数

5、命名关键字参数

定义形参时,在必传参数后面以“”分割,后定义的参数,必须被传值(有默认值的除外),且必须按照关键字实参的形式传递

#! /usr/bin/python3
# -*- congfig:utf-8 -*-
def fun(a,b,*,c,d):
    print(a,b,c,d)
if __name__ == "__main__":
    fun(1,2,c=3,d=4)		#c和d必须以k=v的形式传参,否则报错

6、参数的组合使用

如果一个函数中要使用多种参数

必传参数+默认参数+*args+命名关键字参数+**kwargs

五、函数的返回值 return语句

return语句用来给定函数的返回值,并结束函数

一个函数中可以有多个return语句,但最多只有一个会生效

如果函数没有return语句,则默认返会None

六、嵌套函数

函数内定义函数,就是嵌套函数

内函数只能在外函数内部调用

def one():
    def two():	#定义内函数
        pass
    two()		#调用内函数

七、命名空间和作用域

1、命名空间

命名空间:从python解释器开始执行之后,就在内存中开辟了一个空间,每当遇到一个变量的时候,就把变量名和值之间的对应关系记录下来。但是当遇到函数定义的时候解释器只是象征性的将函数名读入内存,表示知道这个函数的存在了,至于函数内部的变量和逻辑解释器根本不关心。等执行到函数调用的时候,python解释器会再开辟一块内存来存储这个函数里的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量会存储在新开辟出来的内存中。函数中的变量只能在函数的内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。

三种命名空间

  • 内置名称:Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等
  • 全局名称:模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量
  • 局部名称:函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量

命名空间的生命周期

命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束

无法从外部命名空间访问内部命名空间的对象

命名空间的加载顺序

内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)

命名空间的查找流程

  • 系统每次执行一个函数时,就会创建新的局部命名空间
  • 局部命名空间代表一个局部环境,其中包含函数参数的名称和在函数体内被赋值的变量名称
  • 解析名称时,解释器将首先搜索局部命名空间,如果没有找到匹配的名称,就会搜索全局命名空间
  • 如果在全局命名空间未找到,则搜索内置命名空间。如果仍然找不到,就会引发NameError异常

2、作用域

作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域

全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效

局部作用域:局部名称空间,只能在局部范围内生效

3、局部变量,全局变量

局部变量:在局部作用域内定义的变量(函数内部定义

全局变量:在函数外定义的变量(python文件内一般顶格定义的变量)

4、不同作用域的变量访问原则

  • 内部作用域可以访问外部作用域的变量,但不能对外部作用域的变量重新赋值(函数内可以获取到外部变量的值,但不能重新赋值)
  • 外部作用域无法访问内部作用域的变量

5、global、nonlocal

global:在函数中通过global关键字声明某个变量时全局变量,可以在函数内对全局变量重新赋值

nonlocal:在嵌套函数中,内部函数要重新对外部函数中的变量赋值,需要先用nonlocal关键字声明

#! /usr/bin/python3
# -*- congfig:utf-8 -*-

a = 1   #定义全局变量a

def func():
    print(a)    #访问全局变量a
    global a    #声明a是全局变量
    a = 2   #修改全局变量a
    
if __name__ == "__main__":
    print(a)
    func()
    print(a)
#! /usr/bin/python3
# -*- congfig:utf-8 -*-

def one():
    a = 1   #定义外部函数变量a
    def two():
        print(a)    #访问外部函数变量a
        nonlocal a  #声明a时外部函数变量
        a += 1      #为外部函数变量a重新赋值
        print(a)
    
    two()       #调用内部函数
    print(a)

if __name__ == "__main__":
    one()

八、高价函数

一个函数可以作为参数传递给另一个函数,或者一个函数的返回值为另一个函数(若返回值是该函数本身,则为递归),满足任一条件则为高价函数

1、参数为函数

#! /usr/bin/python3
# -*- congfig:utf-8 -*-

def func(l):     #传入一个列表
    for i in l:
        print(i)

def test(fun,l):
    fun(l)

if __name__ == "__main__":
    test(func,[1,2,3,4,5,6])

2、返会值为函数

#! /usr/bin/python3
# -*- congfig:utf-8 -*-

def func(l):     #传入一个列表
    for i in l:
        print(i)

def test():
    return func

if __name__ == "__main__":
    list1 = [1,2,3,4,5,6]
    a = test()
    a(list1)

九、闭包

  • 在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为
  • 内部函数对外部函数作用域里变量的引用(非全局变量),则称内部函数为闭包

形成闭包的条件:

  • 必须有一个嵌套函数(函数内部的函数)
  • 内部函数必须引用外部函数中定义的变量
  • 外部函数必须返回内部函数
#! /usr/bin/python3
# -*- congfig:utf-8 -*-

def one(l):
    a = 1
    def two():
        #nonlocal a,l    如果内函数内要对外函数的变量重新赋值,则需要用nonlocal声明
        s = a * l
        print(s)
    return two

if __name__ == "__main__":
    l = 10
    fun = one(l)
    fun()

十、装饰器

装饰器的本质:是一个闭包函数

装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展

一个装饰器

#! /usr/bin/python3
# -*- congfig:utf-8 -*-
import time
def times(fun):
    def inter(*args,**kwargs):
        starttime = time.time()
        print("%s开始执行"%fun.__name__)
        res = fun(*args,**kwargs)
        stoptime = time.time()
        print("%s执行结束"%fun.__name__)
        print("%s的执行时间为%2f"%(fun.__name__,stoptime-starttime))
        return res
    return inter

@times
def test(a,b):
    print(a + b)

if __name__ == "__main__":
    test(3,5)

多个装饰器修饰一个函数

#! /usr/bin/python3
# -*- congfig:utf-8 -*-

def test1(fun):
    def inner(*args,**kwargs):
        print("第一个装饰器开始")
        res = fun(*args,**kwargs)
        print("第一个装饰器结束")
        return res

    return inner

def test2(fun):
    def inner(*args,**kwargs):
        print("第二个装饰器开始")
        res = fun(*args,**kwargs)
        print("第二个装饰器结束")
        return res
    return inner

@test1	#test1(test2(fun))
@test2	#test2(fun)
def test(a,b):
    print(a + b)

if __name__ == "__main__":
    test(3,5)

多个装饰器装饰一个函数,装饰器从下到上依次执行

十一、匿名函数 lambda

  • python使用lambda来创建匿名函数
  • lambda时一个表达式,比def简单很多,只能封装有限的逻辑
  • lambda有自己的命名空间,lambda表达式不能使用golbal和nonlocal(不能使用外部局部变量和全局变量)

语法:

lambda 参数列表 : 表达式(返回值)
>>> f = lambda x : x ** 2
>>> f(10)
100
#! /usr/bin/python3
# -*- congfig:utf-8 -*-

def test(l):
    f = map(lambda x: x ** 2,l)
    for i in f:
        print(i)

if __name__ == "__main__":
    test(range(10))
原文地址:https://www.cnblogs.com/jingxindeyi/p/13511220.html