Python 官网:https://www.python.org/
自学并不是什么神秘的东西,一个人一辈子自学的时间总是比在学校学习的时间长,没有老师的时候总是比有老师的时候多。
—— 华罗庚
单行装逼代码
print(''.join(chr(int(''.join(i), 16)) for i in zip(*[iter('576f772c2049276d2077726974696e6720696e2068657861646563696d616c21')]*2)))
Run这行代码,会输出下面那句话。我感觉好神奇!决定Study……
仔细“研究”、拆分后,发现是zip()对同一个迭代器作用,产生的Magic(魔法)。这又让我想要对iter()“钻研”了一番。
先看看iter()的“文档”:
print(iter.__doc__)
iter(iterable) -> iterator
iter(callable, sentinel) -> iterator
Get an iterator from an object. In the first form, the argument must supply its own iterator, or be a sequence.
In the second form, the callable is called until it returns the sentinel.
“文档”显示:iter()有给定一个参数、给定两个参数,两种用法。
一、iter(iterable) -> iterator
当只给定一个参数时,参数必须是可迭代对象(iterable object),返回那个参数(iterable object)的iterator(迭代器)。换句话说,就是iter()赋予了iterable object能一个一个返回内容物(元素)的能力,就是让iterable object具有了__next__()“魔法”方法。可以用内置函数next()实现,也可以用自身“新”得技能(next()方法)实现。iterable object参数可以是符合条件的“任意”Python对象。如:
/sdcard/qpython $ python
Python 3.10.2 (main, Mar 1 2022, 12:58:06) [Clang 12.0.8 (https://android.googlesource.com/toolchain/llvm-project c935d99d7 on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> iter('ok')
<str_iterator object at 0x79d5ca4460>
>>> iter([3, 4])
<list_iterator object at 0x79d5c21c90>
>>> iter((6, 'c'))
<tuple_iterator object at 0x79d5c5aa70>
>>> iter({3,9})
<set_iterator object at 0x79d5ca3a80>
>>> iter({5: 6, 'ok': 'haha'})
<dict_keyiterator object at 0x79d5c36700>
>>>>
如您所见,各种对象返回的迭代器,都留着各自的“烙印”。字符串、列表、元组、集合、字典key,这Python五大基础类型,都带着各自的印记。这对“她”作为迭代器使用,毫无阻滞。下面就来炼炼:
>>> iter('ok').__next__()
'o'
>>> iter([3, 4]).__next__()
3
>>> iter((6, 'c')).__next__()
6
>>> iter(('c', 9)).__next__()
'c'
>>> iter({3, 9}).__next__()
9
>>> d = iter({5: 6, 'ok': 'haha'})
>>> d.__next__()
5
>>> d.__next__()
'ok'
>>>
一个一个迭代器,可以变着花样使。
Python3.x内置函数zip()、map()返回的就是iterator。如:
>>> z = zip((4, 6), list('Good'))
>>> z
<zip object at 0x78cffa1380>
>>> z.__next__()
(4, 'G')
>>> z.__next__()
(6, 'o')
>>> z.__next__()
Traceback (most recent call last):
File "" , line 1, in <module>
StopIteration
>>> m = map(str, range(6, 9))
>>> m
<map object at 0x78cff99de0>
>>> next(m, 'The end.')
'6'
>>> next(m, 'The end.')
'7'
>>> next(m, 'The end.')
'8'
>>> next(m, 'The end.')
'The end.'
>>>
由前面“操作”可以看出,zip object、map object她就是iterator,她们有__next__()方法,内置函数next()也可以调用。
>>> next(zip((4,), ['d']))
(4, 'd')
>>> map(int, list('456')).__next__()
4
iter(object)配合zip()的“特殊”用法
iter()借助zip()和*星号“联众”之力,可以实现用简洁的代码完成序列定长选取。例:
为简化例子,先定义了个函数mychoice(iterator, num)。
>>> def mychoice(iterator, num):
... ''' iterator -> 迭代器对象
... num -> int,连续取值数量 '''
... return zip(*[iterator]*num)
...
>>> print(*mychoice(iter(range(9)), 2))
(0, 1) (2, 3) (4, 5) (6, 7)
>>> print(*mychoice(iter('Chongqing'), 3))
('C', 'h', 'o') ('n', 'g', 'q') ('i', 'n', 'g')
>>>
神不神奇,惊不惊喜。这,就是本笔记开篇提到的“装逼代码”的“奇妙”用法。您也许已经发现,由于zip()的特性,不能完全匹配成组的序列元素,被舍弃。比如还原十六进制编码的字符,四位或者两位都是没有余数的,所以对“实际”的应用,几乎没有影响。这,是如何实现的哩?我想是基于迭代器“只可以读取一次”的特性,在iter()官方文档没有找到相关说明。因为我在这里zip()的参数,都是同一个迭代器,重复几次迭代器就是实现连续取几个序列元素。
上面的return 语句,也可以写成
return zip(iterator, ierator, ...) # 想连续取几个序列元素就重复几次。
举个粟子:
>>>
>>> iterator = iter('I love you.')
>>> tem = iterator
>>> print(*zip(tem, tem, tem))
('I', ' ', 'l') ('o', 'v', 'e') (' ', 'y', 'o')
>>>
对同一个迭代器,在zip()参数中重复三次,就完成了连续三个字符的选取。
利用这一“特性”,可以“异想天开”的做些事情。例如:把十六进制字符编码还原成“本来的样子”。
s = '我是重庆“梦幻精灵_cq”,我爱Python,is studying 一条十六进制码搞怪语句。'
en = "Wow, I'm writing in hexadecimal!"
hex_s = '576F772C2049276D2077726974696E6720696E2068657861646563696D616C21'
def to_hex(s, num=2):
''' 将字符转换成十六进制编码,\n字符含中文num=4,\n默认纯英文。 '''
return ''.join(map(lambda x: hex(ord(x))[2:].upper().zfill(num), s)) # 转换字符编码并去除十六进制标识字符用设置位数存储,不足位补“0”。无缝拼接字符,返回字符串。
if __name__== '__main__':
print(f"\n原字符串:{s}\n十六进制:\n{to_hex(s, 4)}") # 用四位十六进制字符保存字符编码。
print(f"\n原字符串:{en}\n十六进制:\n{to_hex(en)}") # 用to_hex()默认参数转换英文字符成2位十六进制ASCII编码。
b = zip(*[iter(to_hex(s, 4))]*4) # 转换字符成十六进制字符编码。
print(f"\n十六进制编码字符串:\n{[''.join(i) for i in b]}\n") # 打印十六进制字符编码字符串。
b = zip(*[iter(to_hex(s, 4))]*4) # 转换字符成十六进制字符编码。
for i in b: # 遍历还原字符。
print(chr(int(''.join(i), 16)), end="")
输出截屏图片
在对迭代器变量b的操作中,为什么会对其两次赋值。因为b在打印十六进制字符编码列表时,已读取b所以再对b操作得先赋值。(iterator只可以读取一次。)
也可见只用一条复合语句完成还原,或者转换 -> 还原整个过程。不过,“较长”的复合语句“生涩难读”,除了“装逼”,少用为宜。
print(f"\n\n{''.join([chr(int(''.join(i), 16)) for i in zip(*[iter(hex_s)]*2)])}")
print(f"\n{''.join(map(lambda x: chr(int(''.join(x),16)), zip(*[iter(to_hex(s,4))]*4)))}\n")
二、iter(iterable, sentinel) -> iterator
如果给出第二参数sentinel,第一个参数必须是可调用对象(不带参数的函数或者类方法,且每次调用会返回一个值),循环调用第一个参数,直到==第二参数(sentinel的值)。正如sentinel的释义一样,就是——“哨兵”——到此为止。不返回sentinel的值。如:
or more information.
>>> lis = range(9)
>>> iterator = iter(lis)
>>> tem = iter(iterator.__next__, 7)
>>> tem
<callable_iterator object at 0x78d0163940>
>>> print(*tem)
0 1 2 3 4 5 6
>>>
>>> iterator = iter('I am Dream elf, I live in Chongqing.')
>>> print(iter(iterator.__next__, ','))
<callable_iterator object at 0x78d01638b0>
>>> print(*iter(iterator.__next__, ','))
I a m D r e a m e l f
当第二参数sentinel是7时,就输出她前面的0~6,不输出7;当sentinel是“,”,就输出前半句字符串,不带输出“,”。
iter()官方文档:
文档链接https://docs.python.org/3/library/functions.html#iter
文档内容,
iter(object[, sentinel])
Return an iterator object. The first argument(参数) is interpreted very differently depending on the presence of the second argument. Without a second argument, object must be a collection object which supports the iterable protocol (the iter() method), or it must support the sequence protocol (the getitem() method with integer arguments starting at 0). If it does not support either of those protocols, TypeError is raised. If the second argument, sentinel, is given, then object must be a callable object. The iterator created in this case will call object with no arguments for each call to its next() method; if the value returned is equal to sentinel, StopIteration will be raised, otherwise the value will be returned.
See also Iterator Types.
One useful application of the second form of iter() is to build a block-reader. For example, reading fixed-width blocks from a binary database file until the end of file is reached:
from functools import partial
with open(‘mydata.db’, ‘rb’) as f:
for block in iter(partial(f.read, 64), b’'):
process_block(block)
参考CSDN博文:
来源:老齐教室
全栈领域优质创作者——寒佬(还是国内某高校学生)好文:《非技术文—关于英语和如何正确的提问》,“英语”和“会提问”是学习的两大利器。
【8大编程语言的适用领域】先别着急选语言学编程,先看它们能干嘛
靠谱程序员的好习惯