Python函数之常见内置函数及迭代器和生成器
常见内置函数
-
abs() 求绝对值
>>> abs(-99) 99 >>> abs(100.10) 100.1
-
all() 与 any() 判断容器类型中的所有数据值对应的布尔值是否为True
# all() 所有的数据值都为True的情况下,结果才是True >>> all([1, 2, 3, 4, 5, 0]) False >>> all([1, 2, 3, 4, 5]) True # any() 所有的数据值只要有一个为True 结果就是True >>> any([1, 2, 3, 4, 5, 0]) True >>> any([1, 2, 3, 4, 5]) True
-
bin() oct() hex() int() 进制转换
>>> bin(10) # 返回一个整数 int 或者长整数 long int 的二进制表示的字符串 '0b1010' >>> oct(10) # 将一个整数(十进制)转换为一个八进制字符串,八进制以 0o 作为前缀表示 '0o12' >>> hex(10) # 将一个整数(十进制)转换为一个十六进制字符串,十六进制以 0x 作为前缀表示 '0xa' # 将一个字符串或数字转换为整型(十进制) >>> int(0b1010) 10 >>> int(0o12) 10 >>> int(0xa) 10
-
bytes() 类型转换
# 编码(人类的字符>>>计算机的字符) >>> res = '啊吧啊吧'.encode('utf8') >>> res b'\xe5\x95\x8a\xe5\x90\xa7\xe5\x95\x8a\xe5\x90\xa7' # 解码(计算机的字符>>>人类的字符) >>> res1 = res.decode('utf8') >>> res1 '啊吧啊吧' # bytes() 返回一个新的 bytes 对象 >>> res = bytes('啊吧啊吧','utf8') >>> res b'\xe5\x95\x8a\xe5\x90\xa7\xe5\x95\x8a\xe5\x90\xa7' >>> type(res) <class 'bytes'> >>> res1 = str(res,'utf8') >>> res1 '啊吧啊吧' >>>a = bytes([1,2,3,4]) >>> a b'\x01\x02\x03\x04' >>> type(a) <class 'bytes'>
-
callable() 用于检查一个对象是否是可调用的
>>> callable(0) False >>> name = 'kwan' >>> callable(name) False >>> def add(a, b): ... return a + b ... >>> callable(add) # 函数返回 True True
-
chr() ord() 依据ASCII码表实现字符与数字的转换
>>> chr(65) # A~Z 65~90 'A' >>> ord('A') 65 >>> chr(97) # a~z 97~122 'a' >>> ord('a') 97
-
dir() 获取对象内部可以通过句点符获取的数据
# dir() 不带参数时,返回当前范围内的变量、方法和定义的类型列表 >>>dir() # 获得当前模块的属性列表 ['__builtins__', '__doc__', '__name__', '__package__', 'arr', 'myslice'] >>> dir([ ]) # 查看列表的方法 ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] # dir() 带参数时,返回参数的属性、方法列表 >>> dir(list) # 查看列表的方法 ['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
-
divmod() 获取除法之后的整数和余数
# divmod() 接收两个数字类型(非复数)参数,返回一个包含商和余数的元组(a // b, a % b) >>> divmod(7, 2) (3, 1) >>> divmod(8, 2) (4, 0) >>> divmod(8, -2) (-4, 0) >>> divmod(3, 1.3) (2.0, 0.3999999999999999) """ 手上有很多数据 每页展示10条 需要多少页 通过代码自动计算 总数据 每页展示 需要多少页 100 10 10 99 10 10 101 10 11 898 10 ??? """ >>> real_num, more = divmod(898, 10) >>> if more: ... real_num += 1 ... >>> print('总页数:%s' % real_num) 总页数:90
迭代器
迭代器即用来迭代取值的工具,而迭代是重复反馈过程的活动,是访问集合元素的一种方式,其目的通常是为了逼近所需的目标或结果,每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值,单纯的重复并不是迭代
# 不属于迭代
while True:
msg = input('请输入: ').strip()
print(msg)
# 属于迭代
n = 0
while n < 10:
print(n)
n += 1
''' 不仅满足重复,而且以每次重新赋值后的 n 值作为下一次循环中新的值,反复迭代 '''
可迭代对象
- 内置有
__iter__
方法的对象都是可迭代对象,即字符串、列表、元组、字典、集合、打开的文件都是可迭代对象 - 可迭代对象能够支持 for 循环取值
# 判断可迭代对象,通过句点符直接能够点出来 __iter__
# 字符串
str.__iter__()
# 列表
list.__iter__()
# 字典
{'name': 'kwan'}.__iter__()
# 集合
{1, 2, 3, 4, 5}.__iter__()
# 元组
(1, 2, 3, 4, 5).__iter__()
# 文件
f = open(r'userinfo.txt', 'r', encoding='utf8').__iter__()
迭代器对象
索引的方式进行迭代取值,仅适用于序列类型:字符串,列表,元组。
对于没有索引的字典、集合等非序列类型,迭代器提供了不依赖索引来进行迭代取值的方式。
- 调用
obj.__iter__()
方法返回的结果就是一个迭代器对象(Iterator) - 迭代器对象是内置有
__iter__
和__next__
方法的对象 - 打开的文件本身就是一个迭代器对象
- 执行迭代器对象
.__iter__()
方法得到的仍然是迭代器本身,而执行迭代器.__next__()
方法就会计算出迭代器中的下一个值。
# 字符串
>>> res = 'kwan'.__iter__() # 返回一个迭代器对象 赋值给res
>>> res.__next__()
'k'
>>> res.__next__()
'w'
>>> res.__next__()
'a'
>>> res.__next__()
'n'
>>> res.__next__() # 没有了就直接报错
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
# 字典
>>> dict1 = {'name':'kwan','pwd':123}
>>> res = dict1.__iter__() # 返回一个迭代器对象 赋值给res
>>> res.__next__()
'name'
>>> res.__next__()
'pwd'
>>> res.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
# 需求:不使用for循环 依次打印出列表中所有的数据值
>>> l1 = [11, 22, 33, 44, 55, 66]
>>> # 1.先将列表变成迭代器对象
>>> res = l1.__iter__()
>>> # 2.定义一个计数器
>>> count = 0
>>> # 3.编写while循环
>>> while count < len(l1):
... print(res.__next__())
... count += 1
...
11
22
33
44
55
66
迭代器的反复使用
>>> l1 = [11, 22, 33, 44]
>>> l1.__iter__().__next__()
11
>>> l1.__iter__().__next__()
11
>>> l1.__iter__().__next__()
11
>>> l1.__iter__().__next__()
11
''' l1.__iter__() 每次都是产生了一个新的迭代器对象 '''
>>> res = l1.__iter__() # res为迭代器对象
>>> res.__iter__().__next__()
11
>>> res.__iter__().__next__()
22
>>> res.__iter__().__next__()
33
>>> res.__iter__().__next__()
44
''' 迭代器对象 .__iter__() 方法得到的仍然是迭代器本身,则每次使用的都是一个迭代器对象 '''
双下方法的简写
l.__iter__() # 可以简写iter(l)
res.__next__() # 可以简写next(res)
for循环内部原理
for 循环又称为迭代循环,in 后可以跟任意可迭代对象
for
会自动将in
后面的数据调用__iter__()
变成迭代器对象- 之后每次循环调用
__next__()
取值 - 最后没有值
__next__()
会报错,for能够自动处理该错误,让循环正常结束
# 语法结构
for 变量名 in 可迭代对象:
for循环体代码
生成器
- 在 Python 中,使用了 yield 的函数被称为生成器(generator)。
- 生成器是一个返回迭代器的函数,只能用于迭代操作。
- 生成器内置有
__iter__
和__next__
方法,所以生成器本身就是一个迭代器。
在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
# 若函数体包含yield关键字,再调用函数,并不会执行函数体代码,得到的返回值即生成器对象
>>> def my_range(start, stop, step=1):
... print('start...')
... while start < stop:
... yield start
... start += step
... print('end...')
...
>>> res = my_range(0, 3)
>>> res
<generator object my_range at 0x00000268F0FA6580>
#
>>> res.__iter__
<method-wrapper '__iter__' of generator object at 0x00000268F0FA6580>
>>> res.__next__
<method-wrapper '__next__' of generator object at 0x00000268F0FA6580>
>>> next(res) # 触发函数执行直到遇到yield则停止,将yield后的值返回,并在当前位置挂起函数
start...
0
>>> next(res) # 再次调用next(res),函数从上次暂停的位置继续执行,直到重新遇到yield...
1
>>> next(res) # 周而复始...
2
>>> next(res) # 触发函数执行没有遇到yield则无值返回,即取值完毕抛出异常结束迭代
end...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
生成器对象代码实现
- 当函数体代码中有yield关键字,那么函数名第一次加括号调用不会执行函数体代码,而是由普通的函数变成了迭代器对象(生成器)返回值
>>> def index():
... print('啊吧啊吧')
... yield
...
>>> print(index)
<function index at 0x00000268F1214310>
>>> res = index()
>>> print(res)
<generator object index at 0x00000268F0FA6740>
- yield可以在函数体代码中出现多次,每次调用__ next__方法都会从上往下执行直到遇到yield代码停留在此处
>>> def index():
... print('啊吧啊吧')
... yield 1
... print('嘀嘀嘀')
... yield 2
... print('嘿嘿嘿')
... yield 3
...
>>> index
<function index at 0x00000268F0E5E040>
>>> res = index()
>>> print(res)
<generator object index at 0x00000268F0FA6580>
>>> res.__next__()
啊吧啊吧
1
>>> res.__next__()
嘀嘀嘀
2
>>> res.__next__()
嘿嘿嘿
3
- yield后面如果有数据值,则会像return一样返回回去,如果有多个数据值逗号隔开,那么也会自动组织成元组返回
>>> def index():
... print('啊吧啊吧')
... yield 1, 2, 3
... print('嘀嘀嘀')
... yield 2
... print('嘿嘿嘿')
... yield 3
...
>>> index
<function index at 0x00000268F1214310>
>>> res = index()
>>> res
<generator object index at 0x00000268F0FA6740>
>>>
>>> res.__next__()
啊吧啊吧
(1, 2, 3)
>>> res.__next__()
嘀嘀嘀
2
>>> res.__next__()
嘿嘿嘿
3
生成器练习题
# 编写生成器,实现range方法的功能
# 1.先以两个参数的功能编写
def my_range(start_num, end_num):
while start_num < end_num:
yield start_num
start_num += 1
for i in my_range(1, 10):
print(i)
# 2.再考虑一个参数的情况
def my_range(start_num, end_num=None):
if not end_num:
end_num = start_num
start_num = 0
while start_num < end_num:
yield start_num
start_num += 1
for i in my_range(100):
print(i)
# 3.最后考虑三个参数的情况
def my_range(start_num, end_num=None, step=1):
if step < 1:
step = 1
if not end_num:
end_num = start_num
start_num = 0
while start_num < end_num:
yield start_num
start_num += step
for i in my_range(1, 100, 2):
print(i)
for i in my_range(1, 5):
print(i)
for i in my_range(10):
print(i)
yield其他用法
>>> def index(name, food=None):
... print(f'{name}准备干午饭!!!')
... while True:
... food = yield # 在函数内可以采用表达式形式的yield
... print(f'{name}正在吃{food}')
...
# 可以拿到函数的生成器对象持续为函数体send值
>>> res = index('kwan') # 得到生成器对象
>>> res
<generator object index at 0x00000268F0FA6740>
>>> res.__next__() # 需要事先“初始化”一次,让函数挂起在food=yield,等待调用res.send()方法为其传值
kwan准备干午饭!!!
>>> res.send('辣子鸡') # 传值并自动调用__next__方法
kwan正在吃辣子鸡
>>> res.send('糖醋排骨') # 传值并自动调用__next__方法
kwan正在吃糖醋排骨
>>> res.send('清蒸鱼') # 传值并自动调用__next__方法
kwan正在吃清蒸鱼
生成器表达式
创建一个生成器对象有两种方式,一种是调用带yield关键字的函数,另一种就是生成器表达式,与列表生成式的语法格式相同,只需要将[]换成(),即:
(表达式 for i in 可迭代对象 if 条件)
生成器表达式返回的是一个生成器对象,其优点是节省内存(一次只产生一个值在内存中)
>>> [x*x for x in range(3)]
[0, 1, 4]
>>> res = (x*x for x in range(3))
>>> res
<generator object <genexpr> at 0x101be0ba0>
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g) # 抛出异常StopIteration
题(掌握技巧)
>>> def add(n, i): # 普通函数 返回两个数的和 求和函数
... return n + i
...
>>>
>>> def test(): # 生成器
... for i in range(4):
... yield i
...
>>>
>>> g = test() # 激活生成器
>>> for n in [1, 10]:
... g = (add(n, i) for i in g)
...
"""
第一次for循环
g = (add(n, i) for i in g)
第二次for循环
g = (add(10, i) for i in (add(10, i) for i in g))
"""
>>> res = list(g)
>>> res
[20, 21, 22, 23]