函数

函数简介

函数(function)

函数是一个对象,对象是内存中专门用来存储数据的一块区域
函数可以用来保存一些可执行的代码,并且可以在需要时,对这些语句进行多次的调用

  • 创建函数语法
def 函数名([形参1,形参2,....形参n]) :
    代码块

函数名要符合标识符的规范(可以包含字母数字下划线,但是不能以数字开头)
函数中保存的代码不会立即执行,需要调用函数才会执行

  • 调用函数
def function():
    print('hello')

function()

函数的参数

在定义函数时,可以在函数名后的()中定义数量不等的形参,多个形参自检使用逗号‘,’隔开。
形参(形式参数):定义形参相当于在函数内部声明了变量,但是不赋值。
如果函数定义时指定了形参,那么在调用时必须传递实参,实参将会赋值个对应的形参。

# 定义一个求任意两个数之和的函数
def sum(a,b):
    print(a, '+' ,b,'=',a+b)

sum(10,20) # 10 + 20 = 30

在定义形参时,可以为形参指定默认值。指定默认值以后,如果传递了参数则默认值不使用;如果没有传递参数,则默认值就会生效

def function(a = 1,b = 2,c = 3):
    print('a =',a)
    print('b =',b)
    print('c =',c)
function()
# a = 1
# b = 2
# c = 3

参数的传递方式

位置参数

位置参数就是将对应位置的实参赋值给对应位置的形参

def function(a = 1,b = 2,c = 3):
    print('a =',a)
    print('b =',b)
    print('c =',c)
function('a','b','c')

关键字参数

关键字参数可以不按照形参定义的顺序去传递,而是直接根据参数名去传递参数

def function(a = 1,b = 2,c = 3):
    print('a =',a)
    print('b =',b)
    print('c =',c)
function(c = 40,a = 20)
# a = 20
# b = 2
# c = 40

位置参数和关键字参数可以混合使用,混合使用时位置参数要写在关键字参数前面

def function(a = 1,b = 2,c = 3):
    print('a =',a)
    print('b =',b)
    print('c =',c)
function(20,c=50)

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

不定长的参数

在定义函数时,可以在形参前面加上 * ,带有 * 的形参可以获取到所有的实参

# *a会接收所有的位置实参,并且会将这些实参统一保存到一个元组中(装包)
def fn(*a):
    print('a=',a,type(a))

fn() # a= () <class 'tuple'>
fn(1,2,3,4,5) # a= (1, 2, 3, 4, 5) <class 'tuple'>

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

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

sum(1,2,3,4,5,6)

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

# 第一个参数给a,第二个参数给b,剩下的参数给c
def fn(a,b,*c):
    print('a=',a)
    print('b=',b)
    print('c=',c)
fn(1,2,3,4,5)

可变参数不一定要写在最后,但是带有 * 的参数后的所有参数,必须以关键字参数的形式传递

def fn(a,*b,c):
    print('a=',a)
    print('b=',b)
    print('c=',c)
fn(1,2,3,4,c=5)

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

def fn(*,a,b,c):
    print('a=',a)
    print('b=',b)
    print('c=',c)
fn(a=1,b=2,c=3)

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

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

fn(b=5,c=2,d=3,e=4,f=7)

参数的解包

序列

传递实参时,在序列类型的参数前添加 * ,这样序列中的元素会依次作为值传递
要求:序列中元素的个数必须和形参的个数一致

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

# 创建一个元组
tuple = (1,2,3)

fn(*tuple)

# 创建一个序列
list = [10,20,30]

fn(*list)

字典

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

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

# 创建一个字典
dict = {'a':10,'b':20,'c':30}

# 通过 ** 来对一个字典进行解包操作
fn(**dict)

返回值

返回值:函数执行以后返回的结果
return 指定函数的返回值,可以直接使用函数的返回值,也可以通过一个变量来接收函数的返回值

return 后边跟什么值,函数就会返回什么值
return后面可以跟任意的对象,返回值甚至可以是一个函数

def fn():
    return 'hello'

print(fn())

n = fn()
print(n)

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

def fn():
    a = 1
    return
r = fn()
print(r)

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

文档字符串(doc str)

文档字符串:函数的说明。
文档字符串写在函数的第一行,当编写了文档字符串时,就可以通过help()函数来查看函数的说明

# 形参中 a:int ,这是对形参类型进行说明,但不一定要传说明的类型的值
def fn(a:int,b:bool,c:str='hello') -> int:  # -> int 这是对函数返回值的说明
    '''这是一个文档字符串的示例'''  #文档字符串
    return 10
help(fn)

# Help on function fn in module __main__:

# fn(a: int, b: bool, c: str = 'hello') -> int
#    这是一个文档字符串的示例

作用域(scope)

作用域:变量生效的区域
在Python中有两种作用域

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

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

  • 当我们使用变量时,会优先在当前作用域中寻找该变量,存在则使用,不存在则去上一级作用域中寻找,以此类推,直到到达全局作用域也没有找到,就会抛出异常。

  • 在函数中为变量赋值是,默认都是为局部变量赋值。如果在函数内部修改全局变量,则需要使用global关键字来声明变量。

a = 10
def fn():
    global a # 声明在函数内部使用的a是全局变量a
    a = 5 # 修改全局变量a的值
fn() # 调用函数
print(a) # 5

命名空间

命名空间指的是变量存储的位置,每一个变量都需要存储到指定的命名空间中

  • 每一个作用域都会有一个它对应的命名空间
  • 全局命名空间用来保存全局变量;函数命名空间用来保存函数中的变量
  • 命名空间实际上就是一个字典,是一个专门用来存储变量的字典
  • locals()用来获取当前作用域的命名空间
  • 如果在全局作用域中调用locals()则获取全局命名空间;如果在函数作用域中调用locals()则获取函数命名空间。
  • 返回一个字典
a = 10
scope = locals()
print(scope)
print(type(scope))
  • 向字典中添加key-value就相当于在全局中创建了一个变量(一般不建议这么做)
a = 10
scope = locals()
scope['b'] = 20
print(scope)
print(b)
  • globals() 函数可以用来在任意位置获取全局命名空间

递归

递归式函数:在函数体中调用自己

递归是解决问题的一种方式,它的整体思想是将一个大问题分解为一个个的小问题,直到问题无法分解时,再去解决问题

递归式函数的两个要件:

  1. 基线条件:问题可以被分解为的最小问题,当满足基线条件时,递归就不再执行
  2. 递归条件:将问题继续分解的条件
def factorial(n):
    '''
    该函数用来求任意数的阶乘
    '''
    # 基线条件:判断n是否为1。如果为1,则此时不再继续递归
    if n == 1:
        # 1的阶乘就是1,直接返回1
        return 1

    # 递归条件
    return n * factorial(n - 1)

print(factorial(10)) #3628800

高阶函数

接收函数作为参数,或者将函数作为返回值的函数是高阶函数
当我们使用一个函数作为参数时,实际上是将指定的代码传递进了目标函数

匿名函数

lambda 函数表达式专门用来创建一些简单的函数,是函数创建的又一种方式

语法:

# 语法
lambda 参数列表 : 返回值
# 下面两个函数效果相同
def function(a,b):
    return a + b

lambda a,b : a + b

# 调用匿名函数
print((lambda a,b : a + b)(2,3))
# 5

# 将匿名函数赋值给一个变量,一般不会这么做
sum = lambda a,b : a + b
print(sum(5,10))
# 15

map()

map()函数可以对可迭代对象中的所有元素做指定的操作,然后将其添加到一个新的对象中返回

l = [1,2,3,4,5,6,7,8]
r = map(lambda i : i+1 ,l)

print(list(r))

sort()

sort() :对列表中的元素进行排序
sort() 方法默认是直接比较列表中的元素的大小

l = ['dddd','eee','a','bbbbbbbbbb','ccc']
l.sort()
print(l)

在 sort() 函数中可以接收一个关键字参数 key 。key需要一个函数作为参数,当设置了函数作为参数,每次都会以列表中的一个元素作为参数来调用函数,并且使用函数的返回值来比较元素的大小。

l = ['dddd','eee','a','bbbbbbbbbb','ccc']
l.sort(key=len)
print(l)
# ['a', 'eee', 'ccc', 'dddd', 'bbbbbbbbbb']
list = [2,'5',3,6,'1',23]
list.sort(key=int)
print(list)
# ['1', 2, 3, '5', 6, 23]

sorted()

sorted() 与 sort() 的用法基本一致,但是 sorted() 可以对任意的序列进行排序,并且 sorted() 排序不会影响原来的对象,而是返回一个新对象

list = [2,'5',3,6,'1',23]
print('排序前:',list)
sorted(list,key=int)
print('排序后:',list)

闭包

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

可以将一些私有的数据藏到闭包中

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(15))
print(averager(20))

装饰器

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

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

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

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

    # 返回新的函数
    return new_function

像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()
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值