Python函数(2)
Python函数(2)
闭包
- 内层函数对外层函数的变量的引用(非全局)
- 闭包只存在函数中
- 逐层返回,最终返回最外层
特性:解释器执行程序时,如果遇到函数,随着函数的结束而关闭临时名称空间,但是如果遇到闭包,那么闭包的空间不会随着函数的结束而关闭
本质:就是在内存中开辟一个空间,常贮存一下内容,以便以后调用
判断是一个函数否是闭包
# 是闭包
def func():
name = 'panky'
def inner():
print(name)
print(inner.__closure__)
return inner
inner = func()
inner()
>>> (<cell at 0x000001FE50DF9588: str object at 0x000001FE50E8A228>,)
>>> panky
# 非闭包
name = 'panky'
def func2():
def inner():
print(name)
print(inner.__closure__)
return inner
f = func2()
f()
>>> None
>>> panky
闭包应用:
- 装饰器
- 爬虫
装饰器
- 本质是一个闭包
- 在不改变原函数的调用的方式上,给原函数增加一些额外功能
def wrapper(f):
def inner(*args, **kwargs):
print("Before the function")
ret = f(*args, **kwargs)
print("After the function")
return ret
return inner
@wrapper
def func(a, b):
print(a, b)
return a + b
res = func(1, 3)
print(res)
>>> Before the function
>>> 1 3
>>> After the function
>>> 4
# 带有标志位的装饰器
def outer(flag=False):
def wrapper(func):
def inner(*args, **kwargs):
if flag:
print('Before the function')
ret = func(*args, **kwargs)
if flag:
print("After the function")
return ret
return inner
return wrapper
@outer(flag=True)
def func(a, b):
print(a, b)
return a + b
res = func(2, 5)
print(res)
>>> Before the function
>>> 2 5
>>> After the function
>>> 7
# 多个装饰器
def wrapper1(func):
def inner(*args, **kwargs):
print("wrapper1, before the function")
ret = func(*args, **kwargs)
print("wrapper1, after the function")
return ret
return inner
def wrapper2(func):
def inner(*args, **kwargs):
print('wrapper2, before the function')
ret = func(*args, **kwargs)
print('wrapper2, after the function')
return ret
return inner
@wrapper1
@wrapper2
def fun(a, b):
print(a, b)
return a + b
res = fun(9, 8)
print(res)
>>> wrapper1, before the function
>>> wrapper2, before the function
>>> 9 8
>>> wrapper2, after the function
>>> wrapper1, after the function
>>> 17
迭代器
可迭代对象:内部含有__iter__()
方法,遵循可迭代协议,使用__iter__()方法
或者内置函数iter()
可以将可迭代对象变为迭代器
迭代器:内部含有__iter__()
和__next__()
方法,遵循迭代器协议,使用__next__()方法
或者内置函数next()
可以对迭代器进行取值
- 节省内存
- 惰性机制,逐个取值
- 一条路走到黑,不回头
判断是否是可迭代对象:
-
'__iter__' in dir(object)
-
from collections import Iterable isinstance(object, Iterable)
判断是否是迭代器:
-
'__iter__' in dir(object) and '__next__' in dir(object)
-
from collections import Iterator isinstance(object, Iterator)
可迭代对象转化为迭代器:
iterable.__iter__()
iter(iterable)
s = "That is life"
print('__iter__' in dir(s))
print('__next__' in dir(s))
new_s = s.__iter__()
print('__next__' in dir(new_s))
print(next(new_s))
print(next(new_s))
>>> True
>>> False
>>> True
>>> T
>>> h
# 用for loop对iterable进行取值
# for loop机制:在遍历之前,先调用iterable对象的__iter__方法,将其转化为一个iterator,然后
# 在利用__next__方法或者next()内置函数去遍历取值
for i in "That is life":
print(i)
# 用while loop模拟for loop
s1 = 'abcd1234'
obj = iter(s1)
while True:
try:
print(next(obj))
except StopIteration:
break
生成器
Generator: A generator is a kind of iterator that is defined with normal function syntax.
构建方式:
-
生成器函数
# 一个包含yield关键字的函数就是生成器函数 # yield不会终止函数,调用生成器函数不会得到返回的具体值,而是一个iterable object # 每一次获取这个iterable object 的value,就会推动函数的执行,获取返回值,直到函数结束
-
生成器表达式
send方法
和next()内置函数
def func():
count = yield 666
print(count, 'in yield 1')
name = yield 'panky'
print(name, 'in yield 2')
name2 = yield 'suki'
print(name2, 'in yield 3')
name3 = yield 'snoopy'
print(name3, 'in yield 4')
generator = func()
print(next(generator))
print(next(generator))
print(next(generator))
print(next(generator))
# 666
# None in yield 1
# panky
# None in yield 2
# suki
# None in yield 3
# snoopy
# send 不仅能对yield取值,还可以给上一个yield发送一个值
def func():
count = yield 666
print(count, 'in yield 1')
name = yield 'panky'
print(name, 'in yield 2')
name2 = yield 'suki'
print(name2, 'in yield 3')
name3 = yield 'snoopy'
print(name3, 'in yield 4')
generator = func()
print(generator.send(None)) # 第一次取值不能用send传值
print(generator.send('yield 2'))
print(generator.send('yield 3'))
print(generator.send('yield 4')) # 最后一个yield永远不能得到send传的值
# 666
# yield 2 in yield 1
# panky
# yield 3 in yield 2
# suki
# yield 4 in yield 3
# snoopy
yield from
将一个iterable object
变成iterator返回
def func():
list1 = [1, 2, 4, 3, 0]
yield from list1
generator = func()
print(next(generator))
print(next(generator))
各种推导式
列表推导式:
- 循环模式——
[变量(加工后的变量) for 变量 in iterable]
- 筛选模式——
[变量(加工后的变量) for 变量 in iterable if 条件]
- 三元模式——
ret = value1 if 条件 else value2
生成器表达式:与列表推导式一致,将[]
换成()
generator1 = ("python %s season" % i for i in range(1, 10))
for i in generator1:
print(i)
集合推导式:
{i:666 for i in range(1, 10)}
dic1 = {'a': 1, 'b': 2, 'c': 3}
dic2 = {value:key for key, value in dic1.items()}
set1 = {1, 2, 3, -4, 4}
set2 = {i**2 for i in set1}
lambda函数
lambda函数:针对只有返回值的函数
格式:
函数名 = lambda 参数: 返回值
递归函数
Python常用内置函数
数学相关
# abs() : 求取绝对值
abs(-4)
# max() : 求取object最大值
max([1, 2, 3])
# min() : 求取object最小值
min([1, 2, 3])
# sum() : 求取object的和
sum([1, 3, 5])
# len() : 长度
len('abc')
# divmod(a,b): 获取商和余数
divmod(5, 2) >>> (2, 1)
# pow(a,b) : 获取乘方数
pow(2, 3) >>> 8
# round(a,b) : 获取指定位数的小数。a代表浮点数,b代表要保留的位数
round(3.1415926,2) >>> 3.14
# range(a[,b]) : 生成一个a到b的数组,左闭右开
range(1,10) >>> [1,2,3,4,5,6,7,8,9]
类型转换
# int(str): 转换为int型
int('1') >> > 1
# float(int / str): 将int型或字符型转换为浮点型
float('1') >> > 1.0
# str(int): 转换为字符型
str(1) >> > '1'
# bool(int): 转换为布尔类型
str(0) >> > False
str(None) >> > False
# bytes(str, code): 接收一个字符串,与所要编码的格式,返回一个字节流类型
bytes('abc', 'utf-8') >> > b'abc'
bytes(u'爬虫', 'utf-8') >> > b'\xe7\x88\xac\xe8\x99\xab'
# list(iterable): 转换为list
list((1, 2, 3)) >> > [1, 2, 3]
# iter(iterable): 返回一个可迭代的对象
iter([1, 2, 3]) >> > <list_iterator object at0x0000000003813B00>
# dict(iterable): 转换为dict
dict([('a', 1), ('b', 2), ('c', 3)]) >> > {'a': 1, 'b': 2, 'c': 3}
# tuple(iterable): 转换为tuple
tuple([1, 2, 3]) >> > (1, 2, 3)
# set(iterable): 转换为set
set([1, 4, 2, 4, 3, 5]) >> > {1, 2, 3, 4, 5}
set({1: 'a', 2: 'b', 3: 'c'}) >> > {1, 2, 3}
# hex(int): 转换为16进制
hex(1024) >> > '0x400'
# oct(int): 转换为8进制
oct(1024) >> > '0o2000'
# bin(int): 转换为2进制
bin(1024) >> > '0b10000000000'
# chr(int): 转换数字为相应ASCI码字符
chr(65) >> > 'A'
# ord(str): 转换ASCI字符为相应的数字
ord('A') >> > 65
其它操作
# eval(): 执行一个表达式,或字符串作为运算
eval('1+1') >> > 2
# exec(): 执行python语句
exec('print("Python")') >> > Python
# type():返回一个对象的类型。
type('abc') >>> <class 'str'>
# id(): 返回一个对象的唯一标识值
id('str')
# hash(object):返回一个对象的hash值,具有相同值的object具有相同的hash值
hash('python') >>> 7070808359261009780
# help():调用系统内置的帮助系统。
help(str)
help(dict)
# isinstance():判断一个对象是否为该类的一个实例。
s = 'abc'
print(isinstance(s, str)) >>> True
print(isinstance(s, dict))>>> False
# issubclass():判断一个类是否为另一个类的子类。
class A:
pass
class B(A):
pass
class C:
pass
print(issubclass(B, A)) >>> True
print(issubclass(C, A)) >>> False
# globals(): 返回当前全局变量的字典。
globals()
>>> {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000240FB1CE358>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/python36panky/07_Luffy project/luffyproject/test.py', '__cached__': None}
# next(iterator[, default]): 接收一个迭代器,返回迭代器中的数值,如果设置了default,则当迭代器中的元素遍历后,输出default内容。
# reversed(sequence) : 生成一个反转序列的迭代器。
reversed('abc') >> > ['c', 'b', 'a']
重要内置函数
sorted()——排序函数
enumerate()——枚举函数
enumerate()是python的内置函数、适用于python2.x和python3.x
enumerate在字典上是枚举、列举的意思
enumerate参数为可遍历/可迭代的对象(如列表、字符串)
enumerate多用于在for循环中得到计数,利用它可以同时获得索引和值,即需要index和value值的时候可以使用enumerate
enumerate()返回的是一个enumerate对象
lst = [1, 2, 3, 4, 5, 6]
res = enumerate(lst)
print(res) # <enumerate object at 0x000002092226D3A8>
使用enumerate()
lst = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
for index, value in enumerate(lst):
print(index, value)
# 0 a
# 1 b
# 2 c
# 3 d
# 4 e
# 5 f
# 6 g
# 指定索引从1开始
lst = ['a', 'b', 'c', 'd', 'e']
for index, value in enumerate(lst, 2):
print(index, value)
# 2 a
# 3 b
# 4 c
# 5 d
# 6 e
补充:
如果要统计文件的行数,可以这样写:
count = len(open(filepath, 'r').readlines())
这种方法简单,但是可能比较慢,当文件比较大时甚至不能工作。
可以利用enumerate()
:
count = 0
for index, line in enumerate(open(filepath, 'r')):
count += 1
zip()——拉链函数
zip()定义:
- 从参数中的多个迭代器取元素组合成一个新的迭代器
- 返回:返回一个
zip
对象,其内部元素为元祖;可以转化为列表或元祖 - 传入参数:元祖、列表、字典等迭代器
使用zip():
-
当zip()函数中只有一个参数时
zip(iterable)
从iterable
中依次取一个元组,组成一个元组# zip()函数单个参数 list1 = [1, 2, 3, 4] tuple1 = zip(list1) # 打印zip函数的返回类型 print("zip()函数的返回类型:\n", type(tuple1)) # 将zip对象转化为列表 print("zip对象转化为列表:\n", list(tuple1)) """ zip()函数的返回类型: <class 'zip'> zip对象转化为列表: [(1,), (2,), (3,), (4,)] """
-
当zip()函数有两个参数时
-
zip(a,b)
zip()函数分别从a和b依次各取出一个元素组成元组,再将依次组成的元组组合成一个新的迭代器--新的zip类型数据 -
注意:
# 要求a与b的维数相同,当两者具有相同的行数与列数时,正常组合对应位置元素即可; # 当a与b的行数或列数不同时,取两者结构中最小的行数和列数,依照最小的行数和列数将对应位置的元素进行组合;这时相当于调用itertools.zip_longest(*iterables)函数。
# zip()函数有2个参数 m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] n = [[2, 2, 2], [3, 3, 3], [4, 4, 4]] p = [[2, 2, 2], [3, 3, 3]] # 行与列相同 print("行与列相同:\n", list(zip(m, n))) # 行与列不同 print("行与列不同:\n", list(zip(m, p))) """ 行与列相同: [([1, 2, 3], [2, 2, 2]), ([4, 5, 6], [3, 3, 3]), ([7, 8, 9], [4, 4, 4])] 行与列不同: [([1, 2, 3], [2, 2, 2]), ([4, 5, 6], [3, 3, 3])] """
-
zip()
应用于矩阵:
# zip()应用
# 矩阵相加减、点乘
m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
n = [[2, 2, 2], [3, 3, 3], [4, 4, 4]]
# 矩阵点乘
print('=*'*10 + "矩阵点乘" + '=*'*10)
print([x*y for a, b in zip(m, n) for x, y in zip(a, b)])
# 矩阵相加,相减雷同
print('=*'*10 + "矩阵相加,相减" + '=*'*10)
print([x+y for a, b in zip(m, n) for x, y in zip(a, b)])
"""
=*=*=*=*=*=*=*=*=*=*矩阵点乘=*=*=*=*=*=*=*=*=*=*
[2, 4, 6, 12, 15, 18, 28, 32, 36]
=*=*=*=*=*=*=*=*=*=*矩阵相加,相减=*=*=*=*=*=*=*=*=*=*
[3, 4, 5, 7, 8, 9, 11, 12, 13]
"""
*zip()
:
*zip()
函数是zip()
函数的逆过程,将zip对象变成原先组合前的数据。
# *zip()函数
print('=*'*10 + "*zip()函数" + '=*'*10)
m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
n = [[2, 2, 2], [3, 3, 3], [4, 4, 4]]
print("*zip(m, n)返回:\n", *zip(m, n))
m2, n2 = zip(*zip(m, n))
# 若相等,返回True;说明*zip为zip的逆过程
print(m == list(m2) and n == list(n2))
"""
=*=*=*=*=*=*=*=*=*=**zip()函数=*=*=*=*=*=*=*=*=*=*
*zip(m, n)返回:
([1, 2, 3], [2, 2, 2]) ([4, 5, 6], [3, 3, 3]) ([7, 8, 9], [4, 4, 4])
True
"""
filter()——过滤函数
filter被称为高阶函数是有道理的。
filter(self, /, *args, **kwargs)
Docstring: filter(function or None, iterable) --> filter object
Return an iterator yielding those items of iterable for which function(item) is true. If function is None, return the items that are true
从Doc的简单描述可以看出,filter
的主要作用是通过function
对iterable
中的元素进行过滤,并返回一个迭代器(iterator),其中是function
返回True
的元素。如果function
传入None
,则返回所有本身可以判断为True
的元素。
example_1
lst = [x for x in range(10)]
filter_object = filter(lambda x: x % 2 == 0, lst)
print(filter_object)
print(list(filter_object)) # 因为filter返回的是一个iterator,所以输出的时候需要用list进行转换
"""
<filter object at 0x00000249AF02A438>
[0, 2, 4, 6, 8]
"""
example_2
lst = [x for x in range(0, 10)]
filter_object = filter(None, lst)
print(filter_object)
print(list(filter_object))
"""
<filter object at 0x0000020CC222A438>
[1, 2, 3, 4, 5, 6, 7, 8, 9]
"""
和例1的输入略有区别,输入是0--9,filter的第一个参数传入了None,所以在迭代过程中,0被判断为False从而被过滤,1~9被保留下来。这个方法可以替代for循环的数据拾取。
通过上面的例子可以看出,调用filter时并没有触发过滤过程,因为调用filter函数只是返回了一个iterator,它是惰性计算,只有next或者list的时候,才真正开始计算过程。
example_3
def _odd_iter():
n = 1
while True:
n = n + 2
yield n
def _not_divisible(n):
return lambda x: x % n > 0
def primes():
yield 2
it = _odd_iter()
ftr = filter(_not_divisible(2), it) # 1
while True:
n = next(ftr) # 2
yield n
ftr = filter(_not_divisible(n), ftr) # 3
for n in primes():
if n < 100:
print('now:', n)
else:
break
通过这个example_3
,可以看到filter
的两个高级用法:
-
其实filter返回的是一个filter对象。#3行通过重复赋值,可以向filter中添加多个过滤器。例子中,就是通过每次执行#3行,把当前素数作为新的被除数条件加入到过滤器ftr 中,所以在for循环的后续迭代中,每次都增加一个素数条件进入过滤器
通过这种重复赋值的方法,可以给filter添加多个过滤函数,极大的加强了过滤功能
-
filter的第二个参数可以传入iterator。当然,此时就不能用list取filter的结果,只能用next(filter对象)取下一个过滤结果为True的元素
map()——映射函数
map(func, *iterables)
是 Python 内置的高阶函数,它接收一个函数 f 和一个或多个iterable,并通过把函数 f 依次作用在 一个或多个iterable 的每个元素上,得到一个map object并返回
- 当seq只有一个时,将函数func作用于这个seq的每个元素上,并得到一个新的seq
example_1
def f(x):
return x*x
map_object = map(f, [1, 2, 3, 4, 5, 6, 7])
print(map_object) # <map object at 0x0000016F8C8FA470>
print(list(map_object)) # [1, 4, 9, 16, 25, 36, 49]
# 注意:map()函数不改变原有的 list,而是返回一个新的 list。
# 利用map()函数,可以把一个 list 转换为另一个 list,只需要传入转换函数。
# 由于list包含的元素可以是任何类型,因此,map() 不仅仅可以处理只包含数值的 list,事实上它可以处理包含任意类型的 list,只要传入的函数f可以处理这种数据类型。
example_2
"""
假设用户输入的英文名字不规范,没有按照首字母大写,后续字母小写的规则,请利用map()函数,把一个list(包含若干不规范的英文名字)变成一个包含规范英文名字的list:
输入:['adam', 'LISA', 'pankY']
输出:['Adam', 'Lisa', 'Panky']
"""
def format_name(s):
s1 = s[0:1].upper() + s[1:].lower()
return s1
map_object = map(format_name, ['adam', 'LISA', 'panky'])
print(map_object) # <map object at 0x000001C1CE7FA588>
print(list(map_object)) # ['Adam', 'Lisa', 'Panky']
- 当seq多于一个时,map可以并行(注意是并行)地对每个seq执行如下图所示的过程
example_3
map_obj = map(lambda x, y: x**y, [1, 2, 3], [1, 2, 3])
for i in map_obj:
print(i)
"""
1
4
27
"""
exampe_4
map_obj = map(lambda x, y: (x**y, x + y), [1, 2, 3], [1, 2, 3])
for i in map_obj:
print(i)
"""
(1, 2)
(4, 4)
(27, 6)
"""
example_5
# python3中可以处理类表长度不一致的情况,但无法处理类型不一致的情况,
map_obj1 = map(lambda x, y: (x ** y, x + y), [1, 2, 3], [1, 2])
for i in map_obj1:
print(i)
map_obj2 = map(lambda x, y: (x ** y, x + y), [1, 2, 3], [1, 2, 'a'])
for i in map_obj2:
print(i)
example_6
特殊用法,做类型转换:
map_obj = map(int,'1234')
for i in map_obj:
print(type(i))
print(i)