; 函数 | Linux运维部落

函数

函数,函数参数,参数解构,作用域,递归函数,匿名函数以及生成器的基本概念。

函数

函数 Python函数,由若干语句组成语句块,函数名称,参数列表构成,他是组织代码的最小单元

函数的作用

结构化编程对代码的最基本的封装,一般按照 功能组织一段代码 封装的目的为了服用,减少代码函数的分类

内建函数

函数库
函数的定义、调用

def 函数名(参数列表)

函数体

return

函数名就是标识符,命名要求一样

语句块必须缩进,约定4个空格

Python的函数没有return语句,隐式会返回一个None值 定义中的参数列表成为形式参数,只是一种符号表达,简称形参

调用

调用的方式,就是函数名加上小括号,括号内写上参数

调用时写的参数是实际参数,是实实在在传入的值,简称实参
函数是可调用的对象 callable() 函数返回 True False.

函数的参数

位置参数:按照参数定义顺序传入实参

关键字参数:使用形参的名字来出入实参的方式,如果使用来了形参名字,那么传参顺序就可和定义顺序不同

可变参数:一个形参可以匹配任意个参数(传入一个可迭代对象)

可变参数:在形参前使用*表示形参是可变参数,可以接受多个实参 要求位置参数必须在关键参数之前传入,位置参数是按照位置对应的

函数参数默认值

定义时,在形参后跟上一个值

作用:参数的默认值可以在未传入足够实参的时候,对没有给定的参数复制为默认值 参数非常多的时候,并不需要用户每次都输入所有的参数,简化函数调用
def add(x=5,y=6)

print(‘good’)

return x+y
关键字参数的可变参数

def showconfig(**kwargs):

for k,v in kwargs.items():

print(‘{}’..format(k,v))

形参前使用**符号,表示可以接受多个关键字参数
keyword-only参数

keyword-only参数是 python03加入的

如果一个星号参数后,或者一个位置可变参数后,出现普通参数,实际上已经不是普通的参数了,而是keyword-only参数
def fn(*arg,x):

print(x)

print(args)
函数参数规则

参数列表参数一般顺序是,普通参数,缺省参数,可变位置参数、keyword-only参数、可变关键字参数

参数解构
def add(x,y):

retuen x+y
add(4,5)

t = (1,3)

add(*t)
参数解构,给函数提供实参的时候,可以在集合类型前使用*或**,把集合类型的结构解开,提取出所有元素作为函数的实参
非字典类型使用*解构成位置参数

字典类型使用**解构成关键字参数 提取出来的元素数目和参数的要求匹配,也要和参数的类型匹配

def add(x,y):

return x+y
d= {‘x’:5,’y’:6}

add(**d)

def add(*iterable):

result = 0

for x in iterable:

result += x return result

# add([1,2,3])

add(*range(10))

函数的返回值

Python函数使用return语句返回”返回值”

所有函数都有返回值,如果没有return语句,隐式调用 return None

return 语句并不一定是函数的语句块的最后一句

一个函数可以存在多个return语句,但是只有一条可以被执行,如果没有一条return语句被执行到,隐式调用return None

如果有必要,可以显示调用 return None,可以简写为 return

如果函数执行了return ,函数就会返回,当前被执行的return语句之后的其他语句就不会被执行了 函数的作用:结束函数调用、返回值
返回多个值

def showlist():

pass

return 11452,5,5,5

showlist()

返回的类型是一个元组
def showlist():

pass

return 11452,5,5,5

showlist()

print(type(showlist()))

<class ‘tuple’>

返回值的解构
def showlist():

pass

return 1,2,3
x,y,z = showlist()

函数嵌套: 在一个函数中定义了另外一个函数
def outer():

def inner():

print(“inner”)

print(“outer”)

inner()

outer()

函数的作用域: 作用域:一个标识符的可见范围,这就是标识符的作用域。一般常说的是变量的作用域 全局作用域:

在整个程序运行环境中都可见

局部作用域:在函数、类等内部可见

局部变量使用范围不能超过起所在的局部作用域

def outer():

o = 66

def inner():

print(“inner {}”.format(o))

print(chr(o)) print(“outer {}”.format(o))

inner()
def outer1():

a = 65

def inner1():

a = 97

print(“inner1 {}”.format(a))

print(chr(a))

print(“outer1 {}”.format(a))

inner1()

outer1()

从函数嵌套结构例子看出:

外层变量作用域在内层作用域可见

内层作用域inner中,如果定义了 o=97 ,相当于当前作用域重新定义了一个新的变量o,但是这个o 并没有覆盖外层作用域 outer 中的 o

global 使用原则

外部作用域变量会使内部作用域可见,但也不要在这个内部的局部作用域中直接使用,因为函数的目的就是为了封装,尽量与外界隔离 如果函数需要使用为外部全局变量,使用函数的形参传参解决 一句话:不用global

闭包:

自由变量:未在本地作用域中定义的变量。

闭包:就是一个概念,出现在嵌套函数中,指的是 内层函数引用到了 外层函数的自由变量,就形成了闭包。
def counter():

def inc():

c[0] += 1

return c[0]

return incfoo = counter()

print(foo(), foo())

c = 100

print(foo())
这是 Python 2 中实现闭包的方式,Python3 还可以使用nonlocal关键字

def sounter():

sount = 1

def inc():

nonlocal sount

sount += 1

return sount

return inc

foo = sounter()

foo()

foo()
使用了 nonclocal 关键字,将变量标记为在上级的局部作用域中定义,但不能是全局作用中定义

默认值的作用域:
def foo1(xyz=[]):

xyz.append(1)

print(xyz)

return xyz

foo1()

foo1()

[1]

[1, 1]

[1, 1, 1]

 

[1, 1, 1]

函数也是对象,python把函数的默认值放在了属性中,这个属性就伴着这个函数对象的生命周期查看 foo._default_ 属性
def foo1(xyz=[],u=’abc’,z=123):

xyz.append(1)

print(xyz)

return xyz
print(foo1(),id(foo1))

print(foo1.__defaults__)

print(foo1(),id(foo1))

print(foo1.__defaults__)
[1]

[1] 140235248505856

([1], ‘abc’, 123)

[1, 1]

[1, 1] 140235248505856

([1, 1], ‘abc’, 123)

函数地址没变,就是说函数这个对象没变,调用它,他的属性__defaults__中使用元组保存所有默认值xyz 默认值是引用类型,引用类型的元素变动,并不是元组的变化

非引用的默认值例子:
def fo1(w,u=’qqq’,z=123):

u = ‘q999w’

z = 9999

print(w,u,z)
print(fo1.__defaults__)

fo1(‘magedu’)print

(fo1.__defaults__)

默认值的作用域:

函数体内不改变默认值。

如果使用缺省值None 就创建一个列表

如果传入一个列表,就修改这个列表
def foo(xyz=None, u=’adf’, z=2222):

if xyz is None:

xyz = []

xyz.append(1)

print(xyz)

foo()

print(foo.__defaults__)

foo()

print(foo.__defaults__)

foo([10])print(foo.__defaults__)

foo([10,5,5,55])

print(foo.__defaults__)

第一种方法: 使用影子拷贝创建一个新的对象,永远不能改变传入的参数第

二种方法: 通过值的判断就可以灵活的选择创建或者修改传入的参数,这种方式灵活,应用广泛,

函数的销毁:

全局函数销毁

重新定义同名函数

del 语句删除函数对象

程序结束时

局部函数销毁

重新在上级作用域定义同名函数

del 语句删除函数对象

上级作用域销毁时

递归函数
函数的执行过程:
def foo1(b, b1=3):

print(‘foo1 called’,b,b1)
def foo2(c):

foo3(c)

print(‘foo2 called’,c)

def foo3(d):

print(‘foo3 called’,d)
def main():

print(‘main called’)

foo1(100,111)

foo2(200)

print(‘main ending’)

main()

递归 recursion

函数直接或间接调用自身就是 递归

递归需要有边界条件,递归前进段,递归返回段

递归一定要有–边界条件 当边界条件不满足的时候,递归前进 当边界条件满足的时候,递归返回

递归要求

递归一定要有退出条件,递归调用一定要执行到这个退出条件,没有退出条件的递归调用,就是无限调用 递归调用的深度不宜过深

Python 对递归调用的深度做了限制,以保护解释器

超过递归深度限制,抛出RecursionError:maxinum recursion depth exceeded 超出最大深度 sys.getrecursionnlimit()

递归的性能:

循环稍微复杂一些,但是只要不是死循环,可以多次迭代直至算出结果

递归还有深度限制,如果递归复杂,函数反复压栈,栈内存很快溢出了

间接递归:

间接递归,是通过别的函数调用了函数自身

如果构成循环递归是非常危险的,在代码复杂的情况下,要用代码的规范来避免递归调用的发生

递归总结:

递归是一种自然的表达,符合逻辑思维

递归相对运行效率低,每一次调用函数都要开辟栈帧

递归有深度限制,如果递归层次太深,函数反复压栈,栈内存很快就溢出了

如果是有限次数的递归,可以使用递归调用,或者使用循环代替,循环代码稍微复杂一些,但是只要不是死循环,可以多次迭代直至算出结果

绝大多数递归,都可以使用循环实现

即使代码递归很简洁,但是能不用则不用递归

 

匿名函数:

匿名函数,即没有名字的函数

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

格式:lambda 参数列表:表达式 lambda x:x**2

使用lambda关键字来定义匿名函数

参数列表不需要小括号

冒号是用来分割参数列表和表达式的

不需要return ,表达式的值,就是匿名函数返回值

lambda 表达式 只能写在一行上,被称为单行函数

用途:在高阶函数传参时,使用lambda表达式,往往能简化代码

生成器: 生成器指的是生成器对象,可以由生成器表达式得到,也可以使用yield关键字得到一个生成器函数,调用这个函数得到一个生成器对象

生成器函数:

函数体中包含yield语句的函数,返回生成器对象

生成器对象,是一个可迭代对象,是一个迭代器

生成器对象,是延迟计算、惰性求值的

def inc():

for i in range(5):

yield i

print(type(inc))

print(type(inc()))

x = inc()

print(type(x))

print(next(x))

print(next(x))

for m in x:

print(m, ‘*’)

for m in x:

print(m, ‘**’)

普通的函数调用fn(),函数会立即执行完毕,但是生成器函数可以使用next函数多次执行

生成器函数等价于生成器表达式,只不过生成器函数可以更加的复杂

生成器函数:

包含了yield语句的生成器函数生成生成器对象时,生成器函数的函数体不会立即执行

next(generator) 会从函数的当前位置向后执行到碰到第一个yield语句,弹出值,并暂停函数执行

再次调用next函数,和上一条一样的处理过程

没有多余的yield的语句能被执行,继续调用next函数,会抛出Stpoiteration异常

生成器应用

协成coroutine

生成器的高级用法

比进程,线程轻量级

是在用户空间调度函数的一种实现

Python3 asyncio 就是协成实现,已经加入到标准库

Python3.5 使用async,await关键字直接源生支持协成

协成调度器实现思路了: 有两个生成器A,B next(A)后,A执行到了yield语句暂停,然后去执行next(B),B执行到yield语句也暂停,然后在此调用next(A),再调用next(B),周而复始,就实现了调度效果

可以引入调度策略来实现切换的方式

协成是一种非抢占式的调度

本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:/87933

发表评论

电子邮件地址不会被公开。 必填项已用*标注

联系我们

400-080-6560

在线咨询:点击这里给我发消息

邮件:1660809109@qq.com

工作时间:周一至周五,9:30-18:30,节假日同时也值班

友情链接:华宇招商  万达娱乐主管QQ  万达招商QQ  万达娱乐登录  guoqibee.com  万达娱乐  万达娱乐直属  万达主管  万达注册