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)

浙公网安备 33010602011771号