码迷,mamicode.com
首页 > 其他好文 > 详细

8_函数

时间:2020-07-20 15:34:13      阅读:118      评论:0      收藏:0      [点我收藏+]

标签:utf-8   保留   地址   逗号   生成   function   users   enumerate   大量   

函数

? 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
? 函数能提高代码的可读性,代码的重复利用率。
? Python提供了许多内建函数print(),len(),range()...,但你也可以自己创建函数,这被叫做用户自定义函数。

一、定义函数

1、定义函数的规则

? a、函数以 def 关键词开头,后接函数标识符名称和圆括号 ()。
? b、参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
? c、函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
? d、函数内容以冒号起始,并且缩进四个空格。
? e、return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。

2、语法

定义函数使用 def 关键字,格式如下:
def 函数名(参数列表):
函数体

函数的作用

? 以功能为导向,一个函数就是一个功能
? 减少代码的重复性
? 增强代码的可读性

3、函数调用

? 定义一个函数:给了函数一个名称,指定了函数里包含的参数,和代码块结构。这个函数的基本结构完成以后,你可以通过另一个函数调用执行,也可以直接从 Python 命令提示符执行。如下实例调用了 printme() 函数:

定义函数

? def printme():
? print ("Hello,world")

调用函数

? printme() # "Hello,world"

4、return语句

return [表达式]
语句用于退出函数,选择性地向调用方返回一个表达式。不带参数值的return语句返回None。

可写函数说明

def sum( arg1, arg2 ):

? # 返回2个参数的和

total = arg1 + arg2
return total

调用sum函数

? total = sum( 10, 20 )
? print ("函数外 : ", total) # 函数外 : 30

二、参数传递

? 不可变类型 : int, tuple, str。如fun(a),传递的只是a的值,没有影响a对象本身。在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
? 可变类型 : list, dict 。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响

python 中一切都是对象,函数中不能说值传递还是引用传递,应该说传不可变对象和传可变对象。

1、传不可变对象

def ChangeInt( a ):
a = 10

b = 2
ChangeInt(b)
print( b ) # 结果是 2

实例中有 int 对象 2,指向它的变量是 b,在传递给 ChangeInt 函数时,按传值的方式复制了变量 b,a 和 b 都指向了同一个 Int 对象,在 a=10 时,则新生成一个 int 值对象 10,并让 a 指向它。

2、传可变对象

可变对象在函数里修改了参数,那么在调用这个函数的函数里,原始的参数也被改变了。

def changeme( mylist ):
"修改传入的列表"
mylist.append([1,2,3,4])
print ("函数内取值: ", mylist)
return

调用changeme函数

mylist = [10,20,30]
changeme( mylist ) # 函数内取值: [10, 20, 30, [1, 2, 3, 4]]
print ("函数外取值: ", mylist) # 函数内取值: [10, 20, 30, [1, 2, 3, 4]]

传入函数的和在末尾添加新内容的对象用的是同一个引用

3、参数

调用函数时可使用的正式参数类型

? 位置参数;关键字参数;默认参数;不定长参数;必需参数

? 实参角度:位置参数;关键字参数;混合参数
? 形参角度:位置参数;默认参数,不定长参数(万能参数)
? 形参角度参数顺序:(位置参数,*args ,默认参数, 仅限关键字参数,**kwargs)

a、位置参数

位置参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。不然会出现语法错误:
def printme( str ):
"打印任何传入的字符串"
print (str)

调用 printme 函数,不加参数会报错

printme()

以上实例输出结果:
Traceback (most recent call last):
File "test.py", line 10, in
printme()
TypeError: printme() missing 1 required positional argument: ‘str‘

b、关键字参数

函数调用使用关键字参数来确定传入的参数值。使用关键字参数允许函数调用时参数的顺序与声明时不一致, Python 解释器能够用参数名匹配参数值。

演示函数参数的使用不需要使用指定顺序:

可写函数说明

def printinfo( name, age ):
"打印任何传入的字符串"
print ("名字: ", name,"年龄: ", age)

调用printinfo函数

printinfo( age=50, name="runoob" ) # 名字: runoob 年龄: 50

c、默认参数

调用函数时,如果没有传递参数,则会使用默认参数。当默认参数指向的是可变类型(list、dict)时,无论调用多少次默认参数,它们都是同一个,但并不在全局作用域或局部作用域,存在于‘特殊空间’。

可写函数说明

def printinfo( name, age = 35 ):
"打印任何传入的字符串"
print ("名字: ", name,"年龄: ", age)

调用printinfo函数

printinfo( age=50, name="runoob" ) # 名字: runoob 年龄: 50
print ("------------------------")
printinfo( name="runoob" ) # 名字: runoob 年龄: 35

默认参数是可变类型的坑点
例一
def func(a, list1=[]):
list1.append(a)
return list1

print(func(10,)) # [10]
print(func(20, [])) # [20] 二新传入了一个列表
print(func(100,)) # [10, 100] 一和三共用一个初始化列表
例二
def func(a, list1=[]):
list1.append(a)
return list1

f1 = func(10,)
f2 = func(20, [])
f3 = func(100,)

print(f1) # [10, 100]
print(f2) # [20]
print(f3) # [10, 100]

d、不定长参数

当需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,声明时不会命名。基本语法如下:
def function_name([args,] *args ):
"函数_文档字符串"
function
return [expression]

加了星号 * (聚合)的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。

可写函数说明

def printinfo( arg1, *vartuple ):
"打印任何传入的参数"
print (arg1)
print (vartuple)

调用printinfo 函数

printinfo( 70, 60, 50 )
输出:
70
(60, 50)

如果在函数调用时没有指定参数,它就是一个空元组。可以不向函数传递未命名的变量。

可写函数说明

def printinfo( arg1, *args ):
"打印任何传入的参数"
print (arg1)
for var in vartuple:
print (var)
return

调用printinfo 函数

printinfo( 10 )
printinfo( 70, 60, 50 )
以上实例输出结果:
10

70
60
50

另一种就是参数带两个星号 **基本语法如下:
def function_name([args,] **kargs):
"函数_文档字符串"
function
return [expression]

加了两个星号 ** 的参数会以字典的形式导入。

可写函数说明

def printinfo( arg1, **vardict ):
"打印任何传入的参数"
print (vardict)

调用printinfo 函数

printinfo(a=2,b=3) # {‘a‘: 2, ‘b‘: 3}

声明函数时,参数中星号 * 可以单独出现,例如:

def f(a,b,*,c):
return a+b+c

如果单独出现星号 * 后的参数必须用关键字传入。

def f(a,b,*,c):
return a+b+c

f(1,2,3) # 报错
Traceback (most recent call last):
File "", line 1, in
TypeError: f() takes 2 positional arguments but 3 were given

f(1,2,c=3) # 正常
6

e、强制位置参数

Python3.8 新增了一个函数形参语法 / 用来指明函数形参必须使用指定位置参数,不能使用关键字参数的形式。在以下的例子中,形参 a 和 b 必须使用指定位置参数,c 或 d 可以是位置形参或关键字形参,而 e 或 f 要求为关键字形参:
def f(a, b, /, c, d, *, e, f):
print(a, b, c, d, e, f)

/ 前面必须使用位置参数, * 后面必须使用关键字参数

以下使用方法是正确的:

f(10, 20, 30, d=40, e=50, f=60)
以下使用方法会发生错误:

f(10, b=20, c=30, d=40, e=50, f=60) # b 不能使用关键字参数的形式
f(10, 20, 30, 40, 50, f=60) # e 必须使用关键字参数的形式

三、函数的名称空间

1、Python分为三个空间

? 内置名称空间(builtins.py)
? 全局名称空间(当前py文件)
? 局部名称文件(函数,函数执行时才开辟)

a、加载顺序

? 内置名称空间(先加载) > 全局名称空间(之后加载) > 局部名称空间(最后加载)

b、取值顺序

? 就近原则。
? 单向不可逆。

2、LEGB规则(就近原则)

? L:local 函数内部作用域
? E:enclosing 函数内部与内嵌函数之间
? G:global 全局作用域
? B:build-in 内置作用域

a、LEGB是作什么用的?

在学习Python函数的时候,会遇到很多定义域的问题,全部变量,内部变量,内部嵌入的函数,等等,Python是如何查找的呢?以及Python又是按照什么顺序来查找的呢?这里做一个顺序的说明

b、顺序是什么

跟名字一样,Python在函数里面的查找分为4种,称之为LEGB,也正是按照这种顺序来查找的。
首先,是local,先查找函数内部
然后,是enclosing,再查找函数内部与嵌入函数之间(是指在函数内部再次定义一个函数)
其次,是global,查找全局
最后,是build-in,内置作用域

c、举例说明

passline = 60

def func(val):
if val >= passline:
print(‘pass‘)
else:
print(‘failed‘)

func(89) # pass

Python函数首先查找local(L),在局部变量作用域里并没有定义passline,然后发现函数内部并没有内嵌函数,这时Python开始查找global,在全局里查找到passline的定义,被调用。

def Max(val1, val2):
return max(val1, val2)

print(Max(90, 100))

‘‘‘‘‘‘‘‘‘
100
[Finished in 0.1s]
‘‘‘‘‘‘‘‘‘
Max函数里面直接调用另外一个函数,调用的max()(两个函数的大小写不一样),该函数并没有被定义,但是却属于我们上述的第四种,属于build-in函数,既是在python标准库里的函数,内置的,可以直接调用的。最后一步才会查找到这里

关于第二种,属于内嵌函数,即使在函数里面再次定义一个函数,这时会首先查找local函数里面是否有定义,然后才会查找函数里面内嵌函数里面有没有定义,这一种有专门的名词,叫做闭包

3、作用域

两个作用域,局部作用域和全局作用域

a、局部作用域

定义在函数内部的变量拥有一个局部作用域(局部命名空间)。

b、全局作用域

定义在函数外的拥有全局作用域(全局命名空间和内置命名空间)。

c、局部和全局变量的说明

? a、函数内部的变量,作用域只在函数内部,函数内部不可以直接更改函数外部的变量
? b、函数内部如果需要改变全局变量,就需要使用global修饰变量
? c、在函数嵌套函数的情况下,同样也有函数作用域的问题,但是python中提供了方便,

d、局部修改变量报错的原因

例一
count = 1 #全局变量

def func():
count += 1 # 从局部作用域操作全局变量

func()
报错:UnboundLocalError: local variable ‘count‘ referenced before assignment(赋值前引用局部变量)

例二(定义一个变量,但在定义这个变量之前对其引用,解释器认为:语法错误)
count = 1

def func():
print(count)
count = 3

func()
报错:UnboundLocalError: local variable ‘count‘ referenced before assignment(赋值前引用局部变量)

原因(使用可以,不能改变):
当python解释器读取到局部作用域时,发现了你对一个变量进行修改的操作,解释器会认为你在局部已经定义过这个局部变量了,它就从局部找这个局部变量,没找到就报错了。

4、内置函数globals和locals

a、globals()函数:

返回的事字典,字典里面的键值对:全局作用域的所有内容

b、locals()函数:

返回的事字典,字典里面的键值对:当前作用域的所有内容

5、修改变量作用域global、nonlocal

a、global关键字:

用途:
1、在局部作用域声明一个全局变量

想要在函数里修改全局变量,需要使用关键字global

x=1 #全局变量
def fun():
y=2 #局部变量
global x
x+=1
print(x,y)
fun() # 2 2

想要在函数外访问函数里的变量,也需要使用关键字global,不加global的时候:

![img](file:///C:\Users\dell\AppData\Local\Temp\ksohtml12832\wps4.jpg)

加global的时候:

![img](file:///C:\Users\dell\AppData\Local\Temp\ksohtml12832\wps5.jpg)

当函数外变量和函数里变量同名,且函数里使用了global关键字,优先使用函数里的变量
a=10
def f1():
global a
a+=1
print(a)
def f2():
global a
a=1
print(a)
f1()
f2()

运行结果

11
1 #f2中同时存在global a 全局变量和a = 1这个局部变量,优先使用f2中自带的a

b、nonlocal关键字:

作用:
内层函数对外层函数的局部变量进行修改

如果要修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量则需要 nonlocal 关键字了

def fun2():
q=1 #局部外层
print(‘局部外层‘,q)
def fun3():
w=22
nonlocal q # nonlocal关键字声明
q+=1 #局部里层
print(q)
print(‘局部里层‘,w)
fun3()

fun2()

运行结果:

局部外层 1
2
局部里层 22

四、函数名的应用

1、函数名 + ()就可以执行函数

函数名指向的是函数的内存地址
def func():
pass

print(func) # <function func at 0x000001C747225948>
print(type(func)) # <class ‘function‘>

2、函数名就是变量

? def func():
? pass

f1 = func
f2 = f1
f2()

3、函数名可以作为容器类数据类型的元素

def func1():
pass
def func2():
pass

list_1 = [func1, func2]
for i in list_1:
i()

4、函数名可以作为函数的参数

def func1():
print(‘Hello‘)

def func2(func):
func()

func2(func1) # Hello

5、函数名可以作为函数的返回值

def func1():
print(‘Hello‘)

def func2(func):
return func

ret = func2(func1)
ret() # Hello 相当于func1()

五、推导式、生成器、迭代器

1、推导式

用一行代码构建一个比较复杂有规律的列表

列表推导式

一种快速生成列表的方式,其形式是用方括号括起来的一段语句。

循环模式:[变量(加工后的变量) for 变量 in iterable]
筛选模式:[变量(加工后的变量) for 变量 in iterable if 条件]
嵌套模式:[变量(加工后的变量) for 变量 in iterable]

lis = [x * x for x in range(1, 100)]
# 增加条件语句
[x * x for x in range(1, 11) if x % 2 == 0]
# 多重循环
[a + b for a in ‘123‘ for b in "xyz"]

字典推导式

# 使用大括号{}可以制造字典推导式!
   	dic = {x: x**2 for x in (2, 3, 5)} 
# 更多用法
dic = {"k1":"v1", "k2":"v2"}
a = [k+":"+ v for k, v in dic.items()]

集合推导式

# 大括号除了能用作字典推导式,还可以用作集合推导式,两者仅仅在细微处有差别。
        a = {x for x in "adadfdaf"  if x not in "abc"}

2、生成器

a、出现原因

有时候,序列或集合内的元素的个数非常巨大,如果全制造出来并放入内存,对计算机的压力是非常大的。
比如,假设需要获取一个10**20次方如此巨大的数据序列,把每一个数都生成出来,并放在一个内存的列表内,这是粗暴的方式,有如此大的内存么?
如果元素可以按照某种算法推算出来,需要就计算到哪个,就可以在循环的过程中不断推算出后续的元素,而不必创建完整的元素集合,从而节省大量的空间。

b、生成器

一边循环一边计算出元素的机制,称为生成器。

获取生成器的三种方式

? 1、生成器函数
? 2、生成器表达式
? 3、Python内部提供

生成器函数
yield

yield关键字 :使用yield返回的函数会变成一个生成器(generator)。

在调用生成器的过程中,每次遇到yield时函数会暂停并保存当前所有的运行信息,返回yield的值。并在下一次执行next()方法时从当前位置继续运行。

生成器函数中可以存在多个yield,一个yield对于一个next()

def fib(n):
a, b, count = 0, 1, 0
while True:
if count > n:
return
yield b # yield让该函数变成一个生成器
a, b = b, a + b
count += 1

res = fib(10)
print(res) # <generator object fib at 0x00000158ED6E28C8>

for i in res:
print(i, end=" ") # 1 1 2 3 5 8 13 21 34 55 89

yield from :将一个可迭代对象变成一个生成器
优化内层循环,提高效率

def func():
li = [1, 2, 3, 4]
yield from li

gen = func()
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3
print(next(gen)) # 4
print(next(gen)) # 抛出StopIteration异常

通过列表推导式修改
print([x * x for x in range(1, 4)]) # [1, 2, 3]
g = (x * x for x in range(1, 4)) # 返回的是一个生成器对象
print(g) # <generator object at 0x0000027902992A48>
可以通过next()函数获得generator的下一个返回值,这点和下面介绍的迭代器非常相似:
next(g)
next(g)
next(g)
next(g) # 抛出StopIteration异常
通常情况下,使用for循环来遍历:
for i in g:
print(i)

3、迭代器Iterator

迭代:通过for循环遍历对象的每一个元素的过程

可以通过collections模块的Iterable类型来判断一个对象是否可迭代:
from collections import Iterable
isinstance("123", Iterable)
isinstance((3, 56, 23), Iterable)
isinstance(1324, Iterable)

a、可迭代对象

内部含有 ’iter’方法的对象称为可迭代对象
可迭代对象:list、tuple、range、string、dict、set、bytes、文件句柄等都是可迭代对象

获取一个对象的所有方法:dir()
dir(str),dir(list),dir(tuple),dir(list)

判断是否是可迭代对象 :’iter’ in dir(对象)

优点:
1、存储的数据能直接显示,比较直观。
2、拥有的方法比较多。
缺点:
1、占用内存。
2、不能直接通过for循环
3、不能直接取值(索引、key除外)

b、迭代器

1、迭代器

是一种可以被遍历的对象,并且能作用于next()函数(内部含有’iter’方法并且含有’next’)方法的对象就是迭代器)。

2、迭代器的特点:

迭代器是数据处理的基石,扫描内存中放不下的数据集时,我们要找到一种惰性获取数据项的方式,即按需一次获取一个数据项。这就是迭代器模式。

? 优点:
? 可以节省内存和空间。
? 惰性机制,(一次只读一行)
? 缺点:
? 速度慢。
? 迭代器只能往后遍历不能回溯。

3、迭代器两个基本方法

? iter() 和 next()。可迭代对象不是迭代器对象,可以使用collections模块中的Iterator类型来判断一个对象是否是迭代器对象。
? from collections import Iterator
? lis = [23, 43, 23]
? isinstance(lis, Iterator) # 返回False

4、可迭代对象转化成迭代器

a、iter(object):
list_1 = [1, 2, 3]
print(iter(list_1)) # <list_iterator object at 0x00000258794BF308>

b、object.iter():
list_1 = [1, 2, 3]
print(list_1.iter()) # <list_iterator object at 0x00000258794BF308>

5迭代器取下一个元素

a、next(object)
list_1 = iter([1, 2, 3])
print(next(list_1)) # 1
print(next(list_1)) # 2
print(next(list_1)) # 3
print(next(list_1)) # 抛出StopIteration异常

b、object.next()
list_1 = iter([1, 2, 3])
print(list_1.next()) # 1
print(list_1.next()) # 2
print(list_1.next()) # 3
print(list_1.next()) # 抛出StopIteration异常

使用for循环来遍历迭代器对象
lis = [1,2,3,4]
it = iter(lis) # 创建迭代器对象
for x in it: # 使用for循环遍历迭代对象
print (x, end=" ")

总结:

类变成为一个迭代器,需要在类里实现__iter__()和__next__()方法

迭代器表示的是一个元素流,可以被next()函数调用并不断返回下一个元素,直到没有元素时抛出StopIteration错误。可以把这个元素流看做是一个有序序列,但却不能提前知道序列的长度,只能不断通过next()函数得到下一个元素,所以可以节省内存和空间

迭代器和可迭代对象对比
可迭代对象是一个私有方法多,操作灵活,比较直观,存储数据相对少的一个数据集。
用途:侧重于数据灵活处理,内存空间足够。

迭代器是非常节省内存,可以记录取值位置,不直观,操作方法比较单一的数据集
用途:数据量过大,可以撑爆内存或以节省内存为首选因素时。

模拟for循环机制

# while 模拟for循环机制

list_1 = [1, 2, 3]

# 将可迭代器对象转化成迭代器

obj = iter(list_1)
while True:
try:
print(next(obj))
except StopIteration:
break

六、匿名函数

语法

lambda 函数的语法只包含一个语句,如下:
lambda [arg1 [,arg2,.....argn]]:expression

lambda是定义匿名函数的关键字,相当于函数def,lambda后面直接加形参,星灿之间用逗号隔开

使用 lambda 来创建匿名函数。

lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。

# 可写函数说明

? sum = lambda a, b: a+ b

# 调用sum函数

? print ("相加后的值为 : ", sum( 10, 20 ))
? print ("相加后的值为 : ", sum( 20, 20 ))
以上实例输出结果:

? 相加后的值为 : 30
? 相加后的值为 : 40

七、内置函数

1、callable()

函数拥有检查一个对象是否是可调用的。

str1 = ‘Hello‘
print(callable(str1))

def func():
pass
print(callable(func))

2、max()、min()、sum()、abs()

max()最大值
list1 = [6, 9, 3, 7, 5]
print(max(list1)) # 9

min()最小值
list1 = [6, 9, 3, 7, 5]
print(min(list1)) # 3

sum()序列元素之和
list1 = [6, 9, 3, 7, 5]
print(sum(list1)) # 30
abs()绝对值
a = -150
print(abs(a)) # 150

max(x) min(x) 的key参数可以用来指定比较规则 x为序列
x=[‘21‘,‘1234‘,‘9‘,‘99‘]
print(max(x)) # 默认按照字符串的ascii码大小
print(max(x, key=len)) # 按照字符串长度 key是一个函数function len()
# 模拟底层实现
def max(l,key=None):
maxobj=l[0]
for i in l:
if key!=None:
if key(i)>key(maxobj):
maxobj=i
else:
if i>maxobj:
maxobj=i
return maxobj
print( max(x,key=int)) #按照元素经过int()后的大小比较 字符串需为数字,否则报错

输出:
99
1234
1234

结合前面的列表推导式,随机数生成器,max()函数
x=[ [ random.randint(1,100) for j in range(6)] for i in range(5) ]
for item in x:
print(item)
print(max(x,key=sum))
‘‘‘
def max(x,key=sum):
maxobj=x[0]
for i in x:
if sum(i)>sum(maxobj)
maxobj=i
return maxobj
‘‘‘
输出:
[100, 86, 20, 72, 2, 42]
[27, 67, 75, 57, 77, 39]
[56, 83, 93, 97, 81, 89]
[11, 53, 34, 11, 29, 27]
[76, 14, 30, 9, 32, 50]
[56, 83, 93, 97, 81, 89]

sum(x,start=0) 返回序列x中所有元素之和 返回start+sum(x),即设置初始值

print (sum([1,2,3,4]))
print(sum([1,2,3,5],20))
‘‘‘
def sum(l,start=0):
result=0
for i in l:
result+=sum(i) ->sum([1,2,3])+0
return start+result
‘‘‘
arr2=[[1,2,3],[2,3,4]]
print(sum(arr2,[5])) #start的类型要与序列元素一致
输出:
10
31
[5, 1, 2, 3, 2, 3, 4]

3、divmod()、round()、pow()、bytes()

divmod():
计算除数与被除数的结果,返回一个包含商和余数的元组(a//b, a%b).

round():
保留浮点数的小数位数,默认保留整数。

pow():
求xy次幂(三个参数为xy的结果对z取余)

bytes()
用于不同编码之间的转化
str1 = ’中国’
bytes(str1, encoding=’utf-8’)

4、all()、any()

all()
函数用于判断 所有元素是否都为 TRUE,如果是返回 True,否则返回 False。

函数等价于:

def all(iterable):
for element in iterable:
if not element:
return False
return True
print( all([‘a‘, ‘b‘, ‘d‘]) )
print( all([‘a‘, ‘b‘, ‘‘, ‘d‘]) )
print( all([‘a‘, ‘b‘, ‘d‘,‘0‘]) ) # 列表list,存在一个为空的元素
输出:
True
False
False

any()
函数用于判断是否全部为 False,则返回 False,如果有一个为 True,则返回 True。

# 函数等价于:

def any(iterable):
for element in iterable:
if element:
return True
return False

a=any([‘‘,0])
print(a)
a=any([‘asd‘,‘‘])
print(a)
输出:
False
True

5、sorted()、reversed()

sorted()

对列表 、元组、 字典 、集合或其他可迭代对象进行排序并返回新列表
语法:
sorted(iterable,,key=None,reverse=False)
iterable可迭代对象 ,
多个, key 指定排序规则,reverse:是否逆序 默认为false

x=[‘aaa‘,‘bc‘,‘d‘,‘b‘,‘ba‘,‘AB‘]
print( sorted(x,key=len)) # [‘d‘, ‘b‘, ‘bc‘, ‘ba‘, ‘AB‘, ‘aaa‘]
print( sorted(x,key=str)) # [‘AB‘, ‘aaa‘, ‘b‘, ‘ba‘, ‘bc‘, ‘d‘]
print( sorted(x,key=str.lower)) # [‘aaa‘, ‘AB‘, ‘b‘, ‘ba‘, ‘bc‘, ‘d‘] # 返回的是列表

reversed()
对可迭代对象 (生成器对象和具有惰性求值对象特性的zip、map、filter,enumerate等对象除外)进行反转,并返回一个迭代的reverse对象(迭代器)

reverse(seq 序列)

x=[‘aaa‘,‘bc‘,‘d‘,‘b‘,‘ba‘]
print(reversed(x)) # 返回一个reverse对象
print( list ( reversed(x)))
输出:
<list_reverseiterator object at 0x000001CAA8CC1748>
[‘ba‘, ‘b‘, ‘d‘, ‘bc‘, ‘aaa‘]

6、zip()

zip()函数:把多个可迭代对象的元素压缩到一起,返回一个可迭代的zip对象,其中每个元素都是包含原来的多个可迭代对象对应位置上元素的元组,如同拉拉链一样
print( zip(‘abc‘,[1,2,3]))
print( list( zip(‘abc‘,[1,2,3])))
print(list(zip(‘abcd‘,[1,2,3,4],[4,5,6,7,8,9])))
输出:
<zip object at 0x000001CAA8C796C8>
[(‘a‘, 1), (‘b‘, 2), (‘c‘, 3)]
[(‘a‘, 1, 4), (‘b‘, 2, 5), (‘c‘, 3, 6), (‘d‘, 4, 7)]

7、map()

映射,将一个函数参数映射到序列或迭代器的对象的每个元素上,并返回一个个迭代的map对象,这个对象的每个元素是原序列中元素经过函数处理后的结果

用户自定义函数

def addTen(num):
return num+10
print( list(map(addTen,range(5))))
输出:
[‘10‘, ‘11‘, ‘12‘, ‘13‘, ‘14‘]

def addTen2(num1,num2):
return num1+num2
print( list( map(addTen2 ,range(5) ,range(10,15) ) ) )
输出:
[10, 12, 14, 16, 18]

使用lambda: 匿名函数,有返回值
lam1=lambda num:num+10
print( list(map(lam1,range(5))))
print( list(map(lambda num:num+10,range(5))))
print( list(map (lambda :+10,range(5))))
输出:
[10, 11, 12, 13, 14]
[10, 11, 12, 13, 14]
[10, 11, 12, 13, 14]

lam2=lambda num1,num2:num1+num2
print( list(map(lam2,range(5),range(10,15))))
print(list(map(lambda num1,num2:num1+num2 ,range(5),range(10,15))))
print( list(map(lambda _1,_2:_1+_2,range(5),range(10,15))))
输出:
[10, 12, 14, 16, 18]
[10, 12, 14, 16, 18]
[10, 12, 14, 16, 18]

def myMap(iterable,op,value):
if op not in [‘+‘,‘-‘,‘*‘,‘/‘,‘//‘,‘**‘]:
return ‘Error operatoe‘
lam1=lambda :eval( str()+op+str(value))
return map(lam1,iterable)
print( myMap([1,2,3],‘+‘,5))
print(list (myMap([1,2,3],‘+‘,5)))
print( list(myMap([1,2,3],‘^‘,5)))
输出:

<map object at 0x00000284FBB4A7F0>
[6, 7, 8]
[‘E‘, ‘r‘, ‘r‘, ‘o‘, ‘r‘, ‘ ‘, ‘o‘, ‘p‘, ‘e‘, ‘r‘, ‘a‘, ‘t‘, ‘o‘, ‘e‘]

# 取出整数每一位,

x=random.randint(1,1e30)
print(x)
print(list(str(x)))
print( list(map (int,str(x))))
输出:
438251004955062915134138002088
[‘4‘, ‘3‘, ‘8‘, ‘2‘, ‘5‘, ‘1‘, ‘0‘, ‘0‘, ‘4‘, ‘9‘, ‘5‘, ‘5‘, ‘0‘, ‘6‘, ‘2‘, ‘9‘, ‘1‘, ‘5‘, ‘1‘, ‘3‘, ‘4‘, ‘1‘, ‘3‘, ‘8‘, ‘0‘, ‘0‘, ‘2‘, ‘0‘, ‘8‘, ‘8‘]
[4, 3, 8, 2, 5, 1, 0, 0, 4, 9, 5, 5, 0, 6, 2, 9, 1, 5, 1, 3, 4, 1, 3, 8, 0, 0, 2, 0, 8, 8]

8、filter( )

filter()将一个单参数函数作用到一个序列上,返回该序列中使得该函数返回值为True的那些元素组成的filter对,如果指定函数为none,则返回序列中等价于True的函数

seq=[‘sada‘,‘1sd‘,‘***‘,‘?!‘]
def func(value):
return value.isalnum() # 判断是否为字母或数字
print(filter (func,seq))
print(list(filter(func,seq)))

seq2=[33,55,88,99]
print( list( filter(lambda :>60 ,seq2)))
输出:
<filter object at 0x000001CAA8C23160>
[‘sada‘, ‘1sd‘]
[88, 99]

*.map、filter、enumerate、zip等对象不仅具有惰性求值的特点,还有另外一个特点,访问过的元素不可再次访问
x=map(str,range(10))
print(list(x))
print(list(x))
x=map(str,range(10))
x=list(x)
print(x)
print(x)
输出:
[‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘]
[]
[‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘]
[‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘]

9、type() 和 isinstance()

type(x) 查看参数x的类型
isinstance(x,y) 判断x是否是y的实例
type([3]) #查看3的类型
type({3}) in (list ,tuple,dict) # {}是set 集合 in 判断是否在in()的元素里
isinstance(3,int) # 判断3是否是int类型的实例
isinstance(3j,(int ,float,str,complex)) #complex 判断3j是否为int float str 或complex类型
输出:
list
False
True
True

10、reduce( )

标准库 functools中的函数reduce()可以将一个接收2个参数的函数以迭代器累积的方式从左到右依次作用到一个序列或迭代器对象的所有元素上,并且允许指定一个初始值

from functools import reduce
seq=list(range(1,100))
print(seq)
print(reduce(lambda _1,_2:_1+_2,seq))
输出:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
4950

# opeator 模块 操作符

#add() sub() mul() div()

import operator
print( operator.add(1,2))
print( operator.mul(1,2))
print( reduce (operator.add,seq))
print( reduce(operator.mul,range(1,11)))
输出:
3
2
4950
3628800

11、callable()

callable:函数用于检查一个对象是否是可调用的。如果返回True,object仍然可能调用失败;但如果返回False,调用对象ojbect绝对不会成功。

name = ‘alex‘
def func():
pass
print(callable(name)) # False
print(callable(func)) # True

12、locals() : 内置函数

将局部变量,使用字典的方式进行打包,key是变量名,value是变量中存储的数据

八、闭包

1、内嵌函数

函数里又嵌套一个函数
def fun1():
print(‘fun1()在被调用‘)
def fun2():
print(‘fun2()在被调用‘)
fun2()

2、闭包

定义:
内层函数对外层函数非全局变量的引用(使用),就会形成闭包。
闭包是函数里面嵌套函数,外层函数返回里层函数,这种情况称之为闭包。

现象:
闭包可以使用(引用)外层函数的局部变量,是函数内部和函数外部沟通的桥梁
被引用的非全局变量也称作自由变量,这个自由变量会与内层函数产生一个绑定关系
自由变量不会再内存中消失

作用:
保证数据安全

判断是否是闭包:
是否是嵌套函数
是否对自由变量的引用(函数名.code.co_freevars : 查看函数的自由变量)
print(ret.code.co_freevars) # (‘a‘,)

def wrapper(): # 外层函数
a = 10 # 自由变量
def inner(): # 内层嵌套函数
print(a) # 对外层函数自由变量的引用
return inner # 返回一个函数,调用不执行

ret = wrapper()
ret() # 10 #相当于 wrapper()()
满足条件

3、回调函数

def fun6():
print(‘第一个函数‘)
def fun7(a): #把上一个函数体当成参数
a()
print(‘第二个函数‘)

fun7(fun6)

运行结果:

第一个函数
第二个函数

4、递归函数

即自己调用自己,递归中可以函数自身调用自身,但是使用时类似于条件循环一样,要有递归的终止条件

递归的最大深度是1000层
节省内存空间,不让用户无限使用
递归要尽量控制次数,如果需要很多层才能解决问题,则不适合递归

递归和循环的关系
递归不是万能的
递归比循环更占用内存

sys.setrecursionlimit(n) :设置递归的最大深度

递归函数必须要有停下来的机制

用途:
计算阶长
os模块:查看文件夹下所有文件(文件夹里还有文件夹,找到所有)
os模块:计算文件夹下所有文件的大小(文件夹里还有文件夹,找到所有)
计算斐波那契数列
三级菜单

阶乘

# 5!=5*4*3*2*1

def factorial(n):
if n==1:
return 1
else:
return factorial(n-1)*n

优点:使用递归时,常常可以让代码更加简洁
缺点:递归会占用比较多的内存,当递归次数比较多时,性能就会降低,因此不建议多使用递归

九、装饰器

可以在不改变原函数的代码以及调用方式的前提下增加额外的功能(完美呈现了开放封闭原则);装饰器的返回值是函数对象。

实质: 是一个函数(本质:闭包)。
参数:是你要装饰的函数名(并非函数调用)。
返回:是装饰完的函数名(也非函数调用)。
作用:为已经存在的对象添加额外的功能。
特点:不需要对对象做任何的代码上的变动。

装饰器有很多经典的应用场景,比如:插入日志、性能测试、事务处理、权限校验等。装饰器是解决这类问题的绝佳设计。

def wrapper(func):
def inner(args, **kwargs):
# 额外增加功能,在函数执行前增加的功能
ret = func(
args, **kwargs)
# 额外增加功能,在函数执行后增加的功能
return ret
return inner

装饰器最大的作用就是对于我们已经写好的程序,我们可以抽离出一些雷同的代码组建多个特定功能的装饰器,这样我们就可以针对不同的需求去使用特定的装饰器,这时因为源码去除了大量泛化的内容而使得源码具有更加清晰的逻辑。

定义一个能打印日志的decorator:
def log(func):
def wrapper(args, **kw):
print(‘call %s():‘ % func.name)
return func(
args, **kw)
return wrapper

@log
def now():
print(‘2015-3-25‘)
调用:
now()
输出:
call now():
2015-3-25
函数对象有一个__name__属性,可以拿到函数的名字。调用now()函数,不仅会运行now()函数本身,还会在运行now()函数前打印一行日志。把@log放到now()函数的定义处,相当于执行了语句:
now = log(now)
wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。

如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数:
def log(text):
def decorator(func):
def wrapper(args, **kw):
print(‘%s %s():‘ % (text, func.name))
return func(
args, **kw)
return wrapper
return decorator

@log(‘execute‘)
def now():
print(‘2015-3-25‘)

now()
输出:
execute now():
2015-3-25
和两层嵌套的decorator相比,3层嵌套的效果是这样的:
now = log(‘execute‘)(now)
首先执行log(‘execute‘),返回的是decorator函数,再调用返回的函数,参数是now函数,返回值最终是wrapper函数。函数也是对象,它有__name__等属性,但你去看经过decorator装饰之后的函数,它们的__name__已经从原来的‘now‘变成了‘wrapper‘:
print(now.name) #输出:wrapper
因为返回的那个wrapper()函数名字就是‘wrapper‘,所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。
Python内置的functools.wraps就是干这个事的,所以,一个完整的decorator的写法如下:
import functools

def log(func):
@functools.wraps(func)
def wrapper(args, **kw):
print(‘call %s():‘ % func.name)
return func(
args, **kw)
return wrapper

import functools

def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(args, **kw):
print(‘%s %s():‘ % (text, func.name))
return func(
args, **kw)
return wrapper
return decorator

8_函数

标签:utf-8   保留   地址   逗号   生成   function   users   enumerate   大量   

原文地址:https://www.cnblogs.com/q121211z/p/13344827.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!