这里到底发生了什么? (Python 3.7.6)

What exactly is going on here? (Python 3.7.6)

我正在研究别人在 Codewars 上的解决方案,对某些事情有点困惑。这是原始问题的 link:Reverse or Rotate?。感谢原作者 falsetru.

解决方法如下:

def revrot(strng, sz):
    return ''.join(
        chunk[1:] + chunk[:1] if sum(int(d)**3 for d in chunk) % 2 else chunk[::-1]
        for chunk in map(''.join, zip(*[iter(strng)]*sz))
    )

我想我明白了大部分。除了这部分:

zip(*[iter(strng)]*sz)

我认为以这种方式使用的 * 表示一个非关键字可变长度参数列表 - 这意味着可以有任意数量的原始字符串 (strng),它们的长度sz,例如 6。根据文档,zip() 函数正在接收一些可变数量的可迭代对象,这是它所需要的。 (对吗?)

那么,map(''.join, zip(*[iter(strng)]*sz) 首先 returns 字符串 strng 的迭代器。它returns this 在一个列表里面。似乎该列表随后乘以 sz(为什么?)。它 returns 压缩了可变数量的结果(因此 *)。 zip() returns 一个元组(我猜?),然后通过 map.

通过 join 函数传递

问题:

  1. 这是否接近正确?
  2. 为什么 iter(strng) 必须放在列表中 []
  3. 为什么可以加入zip的结果?我尝试加入 ('m',) 作为测试并获得了 'm'。对为什么这也有效感到困惑。
  4. 有人可以解释一下 * 吗?我对什么时候应该使用它感到困惑...

谢谢。我仍然是 Python 的初学者,所以非常感谢您的帮助! (即使只是我的一个问题!)

要了解发生了什么,我们要分析语句

for chunk in map(''.join, zip(*[iter(strng)]*sz))

由内而外:

  1. iter(strng) returns 每次使用 next 或在循环中访问的迭代器 consumes strng的一个元素(一个字符)和returns表示的元素。
  2. [iter(strng)]是一个列表,它的唯一元素是迭代器
  3. [iter(strng)]*szsz 个列表副本的串联,[iter(strng), ..., iter(strng)] 包含 sz 相同的迭代器对象,我的意思是字面上相同的迭代器对象.
  4. *[iter(strng)]*sz 等同于 *[iter(strng), ..., iter(strng)] 并且,当在函数参数列表中使用时,解压 其内容:函数将其参数列表视为(iter(strng), ..., iter(strng)).
  5. zip(*[iter(strng)]*sz) 因此等同于 zip(iter(strng), ..., iter(strng)).
  6. 在每次迭代中,zip 获取其每个参数的第一个元素并将它们放入一个元组中,但是因为对 iter 的各种引用都引用相同的原始实例 iter(strng) zip 返回的第一个元组包含 strng 的前 sz 个字符,第二个包含 sz+12*sz 个字符等
  7. 最后,每个元组都是 ''.join() 的参数,所以我们有一系列字符串,每个长 sz 个字符,跨越原始 strng.

就是这样。