刘刚刚的个人博客

6.python基础——函数

创建时间:2020-07-13 17:05:56
更新时间:2020-07-13 17:05:56

函数让代码的复用更方便,让功能的实现更加灵活。

函数

函数基础

函数定义

def 函数名(参数1,参数2,...)
    """文档描述"""
    函数体
    return 值

定义函数时发生的事情:

  1. 申请内存空间保存函数体代码
  2. 将内存地址保存到函数名
  3. 不会执行函数体代码,但会检测函数体语法

函数的三种形式:

  1. 无参函数
  2. 有参函数
  3. 空函数

    函数体代码为 pass 或 ...

    常用于构思软件

函数的三种返回形式

  1. 无返回或者返回None
  2. 返回一个值
  3. 返回多个值。此时,解释器会自动处理为tuple 元组的形式

形参与实参

形参:在定义函数阶段定义的参数称为形式参会素,简称形参

实参:在调用函数阶段传入的值称为实际参数,相当于变量值

在调用阶段,实参会绑定给形参

  1. 位置参数

    按照从左到右的顺序依次定义的参数称之为位置参数,

    位置形参:定义函数时,从左到右顺序定义的'变量名',调用时必须相应数量传值。

    位置实参: 从左到右顺序传入 的值。

  2. 关键字参数

    关键字实参: 函数调用时,按照 key=value 的形式传入的值,不需要参考形参的顺序。

    关键字实参与位置实参混合使用:

    1. 位置实参必须放在关键字实参前
    2. 不能为同一个形参重复传值
  3. 默认参数

    默认形参:在定义函数阶段,就已经被赋值的形参称为默认形参。调用时,可以不赋值。

    位置形参与默认形参混用:

    1. 位置形参必须在默认形参的左边
    2. 默认参数值不建议使用可变类型
  4. 可变长度的参数

    指在调用函数时,传入的实参个数不固定,因此需要针对溢出的实参有形参接受。

    实参与形参中使用*

    • 用来接受溢出的位置实参

      def func(x,y,*args):    //溢出的位置实参会被*保存为元祖的格式,然后赋值给args.
          ...

      *后可以任意变量,一般约定变量名为args

      func(*[1,2,3])   //实参中也可以使用*,会将其后的值拆分成位置实参。
      实参与形参中都使用*:近似于将实参转为元组
    • 用来接受溢出的关键字实参

      def func(x,y,**kwargs)   //溢出的位置实参会被**保存为字典的形式,然后赋值给kwargs

      ** 一般约定变量名为kwargs

      func(**{'x':1,'y':2,'x':3})  //**会将实参后的内容拆分为关键字实参

#### 混用*

args必须在*kwargs之前

def func(x,*args,*kwargs)  //当不能确定接受的值时,*接受位置实参,**接受关键字实参

//以下写法调用wrapper时,会原封不动的将参数传给index

def wrapper(*args,**kwargs):
    index(*args,**kwargs)

### 命名关键字参数

定义函数时,*后定义的参数,即为命名关键字参数,必须使用关键字进行传值。

def func(x,y,*,a,b): //a,b 称为命名关键字参数
    ...

### 类型提示

在python中可在参数项中增加参数类型的提示和返回值的提示,类型提示并非强制

def test(name:str,age:int = 18)->int  
#可以使用内置方法__annotations__查看函数的提示信息
test.__annotations__

函数对象

可以把函数当成变量使用(不加括号)

def func():
    ...
//1.可以赋值
func1 = func
//2.可以当作函数的参数传入
foo(func)
//3.可以做为另外一个函数的返回值
def foo(func1)
    return func1
//4.可以作为容器类型的一个元素
{'k1':func}

函数的嵌套

  1. 嵌套调用
  2. 嵌套定义
## 闭包函数

名称空间与作用域、函数嵌套、函数对象的综合使用

有以下特点:

  1. 为嵌套函数
  2. 内部嵌套的函数包含对外层函数作用域名字的引用
def f1():
    x = 111
    def f2():
        print('函数2:',x)
    return f2
    
f = f1()
f() // 执行的为F2,f2的x只和f1内的x有关.

装饰器

通过装饰器可以在不修改装饰器对象源代码以及调用方式的前提下,为被装饰对象添加新功能

在函数层面的解释:指定义一个函数,为其他函数添加额外的功能

为何要用装饰器:开放封闭原则

  1. 开放:指的是对拓展功能是开放的

    1. 封闭:指的是对修改源代码是封闭的

通过闭包函数,可以实现不修改原代码的情况下,为函数增加新的功能

  1. 无参装饰器

    def test(x):
        print(x)
    
    def test2(func1):
        def test3(*args,**kwargs):
            print(2)
            func1(*args,**kwargs)
        return  test3
    
    test4 = test2(test)
    test = test4
    test(1)

    装饰器语法糖:

    def test2(func1):
    def test3(*args,**kwargs):
      print(2)
      func1(*args,**kwargs)
    return  test3
    
    @test2 //使用@后,再次调用test则自动调用装饰器,语法糖会默认传入一个参数
    def test(x):
    print(x)
    
    test(1)

    如果叠加多个装饰器,只需要将后边的装饰器写到最上边即可

    在使用装饰器时,如果想将原函数的属性也赋值给装饰函数可以使用:

    //写法一:
     def test2(func1):
         def test3(*args,**kwargs):
             print(2)
             func1(*args,**kwargs)
         test3.__name__ = func1.__name__
         test3.__doc__ = func1.__doc__
         return  test3
     //写法二:
     from functools import wraps
     def test2(func1):
         @wrap(func1) 
        def test3(*args,**kwargs):
             print(2)
             func1(*args,**kwargs)
         return  test3
     
  2. 有参装饰器

    当修改函数功能时,如果需要增加参数的传入,则需要在函数外层加一层嵌套

    def test4(y):
        def test2(func1):
            print(y)
            def test3(*args, **kwargs):
                func1(*args, **kwargs)
            return test3
        return test2
    
    @test4(2)  //改函数的执行结果为 test2
    def test(x):
        print(x)
    
    test(1)

迭代器

通过迭代器可以进行循环取值

可迭代对象:内置有__ iter __ 方法的都可称为可迭代对象

包括:列表,字符串、元祖、字典、集合、打开文件

使用方式:

  1. 调用可迭代对象下的 iter 方法,会将其转化为迭代器对象
  2. 调用 ——next—— 即可获取迭代对象的每个元素,如果超出可迭代的次数,那么会抛出异常

for 循环的原理

  1. 调用对象的 iter 方法
  2. 循环使用next
  3. 捕捉到异常后停止

优缺点

有统一的取值方式

无法按照索引取值

生成器 (generator)

在函数内使用 yield 关键字,那么函数执行后,会返回一个迭代器对象,使用一次 next 那么就会运行一次到yield的位置

def func():
    yield 1
    yield 2
    yield 3
    
x = func()
x.__next__()
x.__next__()

可以使用yield的表达式形式:

通过表达式形式,可以使用send()进行传值,在传值时需要注意:

  1. 首次send()需要传 None,不能传其他参数
  2. 首次send(None),效果与next()一样
  3. 每次send()会自动执行一次代码
def test():
    print('运行一次')
    while 1:
        num = yield None
        print(num)

x = test()
next(x)
x.send( )

三元表达式

格式:

条件成立的值  if  条件  else  条件不成立的值

生成式

列表生成式

可以将代理for 对列表进行遍历处理。

格式:

new_l = [ 需要追加的值 for  每次循环的变量名  in 待循环的列表  if 条件  ]

字典生成式

new_dict = 
{k:v for  k,v  in 待循环的字典  if 条件  }

集合生成式

new_dict = 
{value for  value  in 待循环的集合  if 条件  }

生成器表达式

生成的为生成器,每次需要使用next() 调用

new_dict = 
(value for  value  in 待循环的内容  if 条件  )

递归调用

函数自己调用自己,一定要注意停止递归的条件。在python 中没有尾递归优化。

递归调用的两个阶段:

  1. 回溯:一层一层的调用
  2. 递推:递归条件结束后,一层层的返回

匿名函数

匿名函数用于临时调用一次的场景,一般与其他函数配合使用。

定义:

//不需要写return,会自动返回函数体执行的结果
res = lambda 需要传入的参数:函数体

使用场景:比较字典中值得大小,返回字典的key。如:max(),min()

,map(),filter(),reduce()

test_dic = {
    'num1':1,
    'num2':2,
    'num3':3
}
res = max(test_dic,key=lambda k:tese_dic[k])
我的名片

昵称:shuta

职业:后台开发(python、php)

邮箱:648949076@qq.com

站点信息

建站时间: 2020/2/19
网站程序: ANTD PRO VUE + TP6.0
晋ICP备18007778号