1函数概述

1)数学定义 y=f(x) ,y是x的函数,x是自变量
2)Python函数:
    若干语句组成的语句块、函数名称、参数列表形成,它是组织代码的最小单元    实现肯定的性能

2 函数的作用:

结构化变成对代码的最根本封装,个别依照性能组织一段代码;
封装的目标是为了复用,缩小冗余代码;代码更加简洁好看,可读易懂;

3 内建函数

python中提供很多内建函数,能够间接拿来应用,下表列举了一些

函数作用
id()返回变量id
hast()返回对象的hash值
type()返回对象的类型
input()获取用户输出信息
print()打印输出信息
len(s)返回一个汇合类型的元素个数
isinstance(obj, class_or_tuple)判断对象obj是否属于某种类型,返回bool类型
issubclass(cls, class_or_tuple)判断类型cls是否是某种类的子类,返回bool
float() int() bin() hex() oct() bool() list() tuple() dict() set() complex() bytes() bytearray()类型转换
enumerate(seq, start=0)返回索引数字和序列元素的二元组

示例

str_1 = "hello world"print(id(str_1))print(hash(str_1))print(type(str_1))

4 函数的定义:

       def 函数名(参数列表):            函数体(代码块)            [return 返回值]
函数名必须是非法标识符,约定见名知意,尽量应用英文缩写
语句块必须缩进,约定4个空格
python的函数若不写return语句,默认返回一个None值
函数定义的参数列表成为形式参数,只是一种符号表白,简称形参

调用:
函数定义,只是申明了一个函数,它不会被执行,须要调用
调用的形式,就是函数名加上小括号,括号内写上参数。
调用时写的参数就是理论参数,为实参

示例

def add(x:int,  y:int) -> int:  """ 执行两个数的加法的函数"""    return x+y# 调用sum = add(10, 16)print(sum)

5 函数的参数

参数调用时,传入的参数个数要和定义的个数相匹配(可变参数例外)

  • 地位参数:

示例:

def fun(x ,y, z):    max_num = max(x, y, z)    print(max_num)# 地位参数,调用时依照定义的程序传入实参。fun(10, 20, 30) 
  • 关键字参数:

示例:

def fun(x ,y, z):    result = z -x -y    print(result)# 传参形式fun(x=10,  y=20,  z=30) # 能够扭转传参程序fun(y=20, x=10, z=30)# 关键字参数传参要在地位参数之前,地位的参数是依照地位对应的。fun(10, z=30, y=20)
  • 参数默认值:
    定义时,在形参后跟一个值

示例:
示例:

def fun(x=1 ,y=2, z=3):    result = z -x -y    print(result)
  • 可变参数:
    一个形参能够匹配任意个参数
    地位参数的可变参数:
    def add(*nums):        sum = 0        print(type(nums))        for x in nums:            sum+=x        print(sum)

在形参前加*示意该参数是可变参数,能够接管多个实参,收集多个实参为一个tuple,通常为应用*args

  • 可变关键字参数:
def showconfig(**kwargs):    for k, v in kwargs.items():       print('{}={}'.format(k,v))   #  形参应用**符号,示意可接管多个关键字参数   #  收集的实参名称和值组成一个字典# 可变参数混合应用:def showconfig(username, password, **kwargs):    passdef showconfig(username, *args, **kwargs):    pass
参数总结:
参数列表个别程序是一般参数、缺省参数,可变地位参数,keyword-only参数,可变关键字参数.
  • 参数解构
    举例:
    def add(x, y):        return x+y    add(4,5) #间接调用    t = (4,5)    add(*t)    add(*range(1,3)) #同样能够应用可迭代对象传参   #  前提是参数个数雷同

6作用域:

一个标识符的可见范畴,个别常说是变量的作用域。

  • 全局作用域:
    在整个运行环境中都可见
    部分作用域:
    在局部变量应用范畴不能超过其所在的部分范畴

示例:

x = 5def foo():    y = x + 1    x += 1  #谬误,赋值即定义,相当于x未定义就间接应用    print(x)
  • 全局变量global
x = 5def foo():    global x    x += 1    print(x)foo()
  • 闭包
    自在变量:未在本地作用域中定义的变量。例如定义在内存函数外的外层函数中作用域的变量。
    闭包:就是一个概念,呈现在嵌套函数中,指的是内层函数援用了外层函数的自在变量,就造成了闭包。
def counter():    c = [0]    def inc():        c[0] += 1 # 这里不会报错,因为是c[0] 而不是c,这是对c中的元素从新赋值        return c[0]    return inc  #返回是的一个函数援用,而不是函数调用foo = counter()print(foo(), foo())  #打印1和2c = 100print(foo())  #打印3

下面是python2中实现闭包的形式,Python3中还能够应用关键字nonlocal

def counter():    c = 1    def innter():        nonlocal c        c += 1        return c    return innterfoo = counter()print(foo(), foo())c = 100print(foo())

nonlocal关键字:将变量标记为在下级的部分作用域定义,但不能是全局作用域中定义。

  • 默认值的作用域
def foo(l=[]):    l.append(1)    print(l)foo() #打印[1]foo() #打印[1,1]#起因是函数也是对象,python把函数的对象的默认值放在了属性中,这个属性就随同着这个函数对象的整个生命周期

查看foo.__defaults__

def foo(l=[], u='abc', z=123):    l.append(1)    print(l)print(foo(), id(foo))print(foo.__defaults__)print(foo(), id(foo))print(foo.__defaults__)# 函数两次打印id雷同,表明函数地址没有产生扭转,就是说函数这个对象没有变,调用它,它的属性__defaults__中应用元组保留所有默认值。# 其中l默认值是援用类型,援用类型元素变动,并不是元组的变动

非援用类型中

def foo(l=1, u='abc', z=123):    u = ‘xyz’    z = 789    print(l, u, z)print(foo.__defaults__) #打印(1, 'abc', '123')print(foo(), id(foo))print(foo.__defaults__) #打印(1, 'abc', '123')

可变类型默认值,如果应用这个默认值,就可能批改这个默认值
有时候这个个性是好的,有的时候这种个性是不好的,也会带来一些麻烦
如何做到按需批改?看上面这两种办法

def foo(x=[], u='abc', z=123):    x = x[:]    x.append(1)    print(x)foo()print(foo.__defaults__)foo()print(foo.__defaults__)foo([10])print(foo.__defaults__)foo([10,5])print(foo.__defaults__)
def foo(x=None, u='abc', z=123):    if x is None:        x = []    x.append(1)    print(x)foo()print(foo.__defaults__)foo()lst=[10]foo(lst)print(lst)  #lst产生扭转print(foo.__defaults__)foo([10,5])print(foo.__defaults__)

个别函数中不应用打印语句,结尾应用return
第一种办法:
应用影子拷贝创立一个新的对象,永远不能扭转传入的参数。
第二种办法:
通过值的判断就能够灵便的抉择创立或者批改传入对象。
这种形式灵便,利用宽泛。
很多函数的定义,都能够看到应用None这个不可变的值作为默认参数,这是一种习用法。

7函数的销毁

  • 全局函数
    1)从新定义同名函数
    2)del 语句
    3)程序完结时
  • 部分函数
    1)从新定义同名函数
    2)del 语句
    3)下级作用域销毁

8 变量名解析准则LEGB

1)Local:本地作用域,部分作用域的local命名空间,函数调用时创立,调用完结沦亡
2)Enclosing:Python2.2引入了嵌套函数,实现了闭包,这个就是嵌套函数的内部函数的命名空间
3)GLobal,全局作用域,一个模块的命名空间,模块被导入时创立,解释器退出时沦亡
4)Build-in,内置模块的命名空间,生命周期,从Python解释器启动时创立到解释器退出时沦亡

9 递归函数

  • 递归Recursion:

函数间接或者间接调用本身就是递归
递归须要有边界、递归后退段、递归返回段
递归肯定要有边界条件
当边界条件不满足的时候,递归后退
当边界条件满足的时候,递归返回

  • 间接递归

是通过别的函数调用了函数本身。
然而形成了循环递归调用是十分危险的,然而往往这种状况在代码简单的状况下,还是可能产生这种调用。要用代码标准来防止这种递归调用的产生。
留神:慎用递归

  • 递归肯定要有退出条件,递归调用定要执行到这个退出条件。

递归调用深度不宜过深
查看递归限度层数:

import sysprint(sys.getrecursionlimit())
  • 递归的性能:

循环略微简单一些,但只有不是死循环,能够屡次迭代直至算出后果。
递归函数代码精简易懂,然而只能获取到最外层的函数滴啊用,外部递归后果都是两头后果。而且给定一个n都要进行2n次递归,深度越深,效率越低。

递归示例:
求n的阶乘

def fun(n):    if n == 1:        return 1    return n*fun(n-1)print(fun(3))

10 匿名函数:

  • Python借助lambda表达式构建匿名函数

格局:
lambad 参数列表:表达式

lambda x:x*2(lambda x:x*2)(4) #调用foo = lambda x,y:(x+y)**2foo(2,1)
  • 用处:
    高阶函数传参时,应用lambda表达式,往往能简化代码

11Python生成器函数

  • 生成器generator
    生成器是指生成器对象,能够由生成器表达式失去,也能够用yield关键字失去一个生成器函数,调用这个函数失去一个生成器对象
  • 生成器函数:
    1)函数体中蕴含yield语句的函数,返回生成器对象
    2)生成器对象,是一个可迭代对象,也是迭代器
    3)生成器对象,提早计算,惰性求值
    4)一般函数调用fn(),函数会立刻执行结束,然而生成器函数能够应用next函数屡次执行

生成器函数等价于生成器对象,只不过生成器函数能够更加简单。
示例

def gen():    print("line 1")    yield 1    print("line 2")    yield 2    print("line 3")    return 3next(gen()) #line 1next(gen()) #line 1g = gen()print(next(g)) #line1print(next(g)) #1ine2print(next(g))  #line 3 StopIterationprint(next(g,'End')) #生成器到尾了,返回默认值‘End’