Python函数的相关知识点及如何使用

函数简介(function)

  • 函数也是一个对象
  • 对象是内存中专门用来存储数据的一块区域
  • 函数可以用来保存一些可执行的代码,并且可以在需要时,对这些语句进行多次的调用
  • 创建函数:
 def 函数名([形参1,形参2,...形参n]) :
        代码块
  • 函数名必须要符号标识符的规范
    (可以包含字母、数字、下划线、但是不能以数字开头)
  • 函数中保存的代码不会立即执行,需要调用函数代码才会执行
  • 调用函数:
函数对象()
  • 定义函数一般都是要实现某种功能的

定义一个函数

def fn() :
    print('这是我的第一个函数!')
    print('hello')

打印fn

print(fn)      #<function fn at 0x03D2B618>
print(type(fn))   #<class 'function'>

print是函数对象 print()调用函数
fn是函数对象
fn()调用函数

fn()

定义一个函数,可以用来求任意两个数的和

def sum() :
    a = 123
    b = 456
    print(a + b)

sum()

函数的参数

  • 在定义函数时,可以在函数名后的()中定义数量不等的形参,
    多个形参之间使用,隔开
  • 形参(形式参数),定义形参就相当于在函数内部声明了变量,但是并不赋值
  • 实参(实际参数)
    • 如果函数定义时,指定了形参,那么在调用函数时也必须传递实参,实参将会赋值给对应的形参,简单来说,有几个形参就得传几个实参

求任意三个数的乘积

def mul(a,b,c):
    print(a*b*c)
mul(1,2,3) 

定义形参时,可以为形参指定默认值
指定了默认值以后,如果用户传递了参数则默认值没有任何作用
如果用户没有传递,则默认值就会生效

  def fn(a = 5 , b = 10 , c = 20):
    print('a =',a)
    print('b =',b)
    print('c =',c)

实参的传递方式
①位置参数
位置参数就是将对应位置的实参复制给对应位置的形参
第一个实参赋值给第一个形参,第二个实参赋值给第二个形参 。。。
②关键字参数
关键字参数,可以不按照形参定义的顺序去传递,而直接根据参数名去传递参数
fn(b=1 , c=2 , a=3)
位置参数和关键字参数可以混合使用
混合使用关键字和位置参数时,必须将位置参数写到前面
fn(1,c=30)

函数在调用时,解析器不会检查实参的类型
实参可以传递任意类型的对象

b = 123
b = True
b = 'hello'
b = None
b = [1,2,3]

不定长的参数
在定义函数时,可以在形参前边加上一个*,这样这个形参将会获取到所有的实参
它将会将所有的实参保存到一个元组中

定义一个函数,可以求任意个数字的和

def sum(*nums):
    # 定义一个变量,来保存结果
    result = 0
    # 遍历元组,并将元组中的数进行累加
    for n in nums :
        result += n
    print(result)

sum(123,456,789,10,20,30,40)

*a会接受所有的位置实参,并且会将这些实参统一保存到一个元组中(装包)

def fn(*a):
    print("a =",a,type(a))
    
fn(1,2,3,4,5)

带星号的形参只能有一个
带星号的参数,可以和其他参数配合使用

第一个参数给a,第二个参数给b,剩下的都保存到c的元组中

def fn2(a,b,*c):
	print('a =',a)
    print('b =',b)
    print('c =',c)

可变参数不是必须写在最后,但是注意,带*的参数后的所有参数,必须以关键字参数的形式传递
第一个参数给a,剩下的位置参数给b的元组,c必须使用关键字参数

def fn2(a,*b,c):
    print('a =',a)
    print('b =',b)
    print('c =',c)

如果在形参的开头直接写一个*,则要求我们的所有的参数必须以关键字参数的形式传递

def fn2(*,a,b,c):
    print('a =',a)
    print('b =',b)
    print('c =',c)
    
fn2(a=3,b=4,c=5)

*形参只能接收位置参数,而不能接收关键字参数

**形参可以接收其他的关键字参数,它会将这些参数统一保存到一个字典中
字典的key就是参数的名字,字典的value就是参数的值
**形参只能有一个,并且必须写在所有参数的最后

def fn3(b,c,**a) :
    print('a =',a,type(a))
    print('b =',b)
    print('c =',c)

参数的解包(拆包)

def fn4(a,b,c):
    print('a =',a)
    print('b =',b)
    print('c =',c)
d = {'a':100,'b':200,'c':300}

通过 **来对一个字典进行解包操作

fn4(**d)

返回值

返回值就是函数执行以后返回的结果
可以通过 return 来指定函数的返回值
可以之间使用函数的返回值,也可以通过一个变量来接收函数的返回值
return 后边跟什么值,函数就会返回什么值
return 后边可以跟任意的对象,返回值甚至可以是一个函数

def fn():
    # return 'Hello'
    # return [1,2,3]
    # return {'k':'v'}
    def fn2() :
        print('hello')

    return fn2 # 返回值也可以是一个函数

r = fn() # 这个函数的执行结果就是它的返回值

r()
#print(fn())
#print(r)

如果仅仅写一个return 或者 不写return,则相当于return None

def fn2() :
    a = 10

在函数中,return后的代码都不会执行,return 一旦执行函数自动结束

def fn3():
    print('hello')
    return
    print('abc')

作用域(scope)

作用域指的是变量生效的区域

b = 20 # 全局变量

def fn():
    a = 10 # a定义在了函数内部,所以他的作用域就是函数内部,函数外部无法访问
    print('函数内部:','a =',a)
    print('函数内部:','b =',b)

在Python中一共有两种作用域
全局作用域

  • 全局作用域在程序执行时创建,在程序执行结束时销毁
  • 所有函数以外的区域都是全局作用域
  • 在全局作用域中定义的变量,都属于全局变量,全局变量可以在程序的任意位置被访问

函数作用域

  • 函数作用域在函数调用时创建,在调用结束时销毁
  • 函数每调用一次就会产生一个新的函数作用域
  • 在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问

变量的查找

  • 当我们使用变量时,会优先在当前作用域中寻找该变量,如果有则使用,
    如果没有则继续去上一级作用域中寻找,如果有则使用,
    如果依然没有则继续去上一级作用域中寻找,以此类推
    直到找到全局作用域,依然没有找到,则会抛出异常
    NameError: name 'a
a = 20

def fn3():
    # a = 10 # 在函数中为变量赋值时,默认都是为局部变量赋值
    # 如果希望在函数内部修改全局变量,则需要使用global关键字,来声明变量
    global a # 声明在函数内部的使用a是全局变量,此时再去修改a时,就是在修改全局的a
    a = 10 # 修改全局变量
    print('函数内部:','a =',a)

 fn3()

命名空间(namespace)

命名空间指的是变量存储的位置,每一个变量都需要存储到指定的命名空间当中
每一个作用域都会有一个它对应的命名空间
全局命名空间,用来保存全局变量。函数命名空间用来保存函数中的变量
命名空间实际上就是一个字典,是一个专门用来存储变量的字典

locals()用来获取当前作用域的命名空间
如果在全局作用域中调用locals()则获取全局命名空间,如果在函数作用域中调用locals()则获取函数命名空间
返回的是一个字典

scope = locals() # 当前命名空间
print(type(scope))

闭包

将函数作为返回值返回,是一种高阶函数
这种高阶函数我们也称为叫做闭包,通过闭包可以创建一些只有当前函数能访问的变量
可以将一些私有的数据藏到的闭包中

  def fn():

    a = 10

    # 函数内部再定义一个函数
    def inner():
        print('我是fn2' , a)

    # 将内部函数 inner作为返回值返回   
    return inner

r是一个函数,是调用fn()后返回的函数
这个函数实在fn()内部定义,并不是全局函数
所以这个函数总是能访问到fn()函数内的变量

r = fn()    

r()

形成闭包的要件
① 函数嵌套
② 将内部函数作为返回值返回
③ 内部函数必须要使用到外部函数的变量

def make_averager():
    # 创建一个列表,用来保存数值
    nums = []

    # 创建一个函数,用来计算平均值
    def averager(n) :
        # 将n添加到列表中
        nums.append(n)
        # 求平均值
        return sum(nums)/len(nums)

    return averager

averager = make_averager()

print(averager(10))
print(averager(20))
print(averager(30))
print(averager(40))

装饰器

创建几个函数

def add(a , b):
    '''
        求任意两个数的和
    '''
    r = a + b
    return r


def mul(a , b):
    '''
        求任意两个数的积
    '''
    r = a * b
    return r    

希望函数可以在计算前,打印开始计算,计算结束后打印计算完毕

我们可以直接通过修改函数中的代码来完成这个需求,但是会产生以下一些问题
① 如果要修改的函数过多,修改起来会比较麻烦
② 并且不方便后期的维护
③ 并且这样做会违反开闭原则(OCP)
程序的设计,要求开发对程序的扩展,要关闭对程序的修改
def begin_end(old):
‘’’
用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束

def begin_end(old):
    '''
        用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束

        参数:
            old 要扩展的函数对象
    '''
    # 创建一个新函数
    def new_function(*args , **kwargs):
        print('开始执行~~~~')
        # 调用被扩展的函数
        result = old(*args , **kwargs)
        print('执行结束~~~~')
        # 返回函数的执行结果
        return result

    # 返回新函数        
    return new_function

f = begin_end(fn)
f2 = begin_end(add)
f3 = begin_end(mul)

# r = f()
# r = f2(123,456)
# r = f3(123,456)
# print(r)

向begin_end()这种函数我们就称它为装饰器
通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展
在开发中,我们都是通过装饰器来扩展函数的功能的
在定义函数时,可以通过@装饰器,来使用指定的装饰器,来装饰当前的函数
可以同时为一个函数指定多个装饰器,这样函数将会安装从内向外的顺序被装饰

def fn3(old):
    '''
        用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束

        参数:
            old 要扩展的函数对象
    '''
    # 创建一个新函数
    def new_function(*args , **kwargs):
        print('fn3装饰~开始执行~~~~')
        # 调用被扩展的函数
        result = old(*args , **kwargs)
        print('fn3装饰~执行结束~~~~')
        # 返回函数的执行结果
        return result

    # 返回新函数        
    return new_function
@fn3
@begin_end
def say_hello():
    print('大家好~~~')

say_hello()

猜你喜欢

转载自blog.csdn.net/Airuiliya520/article/details/106353487