2014-11-06 130 views
2

我正在寻找成语以取代python for循环,它取代(而不是mutate)正在迭代的迭代中的元素。具体地,考虑以下四个(换)环路:Deuglify元素变异Python for循环

环路一个:只读的Python环被C程序员

for i in range(len(iterable)): 
    print(iterable[i]) 

装置B写成:只读的Python环通过一个Python wirtten程序员

for e in iterable: 
    print(e) 

循环C:在写作缺乏经验的Python程序员写了一个变异的Python循环一次失败的尝试

for e in iterable: 
    if condition(e): 
     e = new_value(e) 

循环d:循环C的修复,其诉诸恢复到环甲

for i in range(len(iterable)): 
    if condition(iterable[i]): 
     iterable[i] = new_value((iterable[i])) 

的丑陋风格除了是可恨难看,环路d失败非序列iterables。

我寻找习语和技术,其

  • 一个)减轻循环d

  • b)中的丑陋允许一个循环来修改非序列iterables的内容(在该子集中在有意义的情况下)的

注:

  1. 原始容器应该是已修改;重点不是创建一个新的容器。

  2. 我是亲密熟悉Loop C失败的原因:你真的不需要向我解释为什么它不起作用。我正在寻找的是更好的方式来编写循环D.

  3. 我不是要修改整个容器的任何循环,只是它的一些个别包含的元素:你不需要向我解释在整个容器循环时修改整个容器,这是一个坏主意。

  4. 我很清楚,通常不可能修改迭代元素。但是在某些特定情况下是可能的,这是b)的一部分。

+0

“允许循环修改**非序列可迭代**的内容”,我认为可迭代序列是序列并且没有**非序列可迭代**。 – 2014-11-06 12:32:46

+0

@VishnuUpadhyay:我怀疑OP会喜欢一种通用的技术,允许遍历字典和其他没有简单整数索引的映射。 – 2014-11-06 13:07:19

+1

@VishnuUpadhyay下面是一些可迭代的例子,但不是序列:'open('/ etc/passwd')','dict(a = 7,b = 3)','iter('hello') ','def x():yield 1',接着是'x()','itertools.cycle()'等等,这些例子都不适合在循环中修改;这将需要比评论允许的更多空间。虽然有人可能会争辩说,基于“dict(a = 1,b = 2).values()”的东西是候选人。 – jacg 2014-11-06 16:49:30

回答

1

回答我的问题,我想出了这是由enumerate启发,并允许写入的方式,是不是所有的丑这样的循环协议(称之为的muteration协议) 。使用协议A环是这样的:

for setit, e in muterate(iterable): 
    if e%2: 
     setit(1000*e) 

就像enumeratemuterate返回一个可迭代产生对:enumerate“s指数被替换为setter函数,它接受与它将替换的新值容器中的原始值。muterate将适用于实施muterate方法的任何类型的迭代,就像iter适用于实现合适的__iter__方法的任何类型。这意味着对于任何支持哑音的类型,可以以的方式编写静音循环,其方式与完全相同。

下面是一个概念验证实现。不能说我对此太过苛刻,但也许这是朝着正确方向迈出的一步。

from functools import partial 
from itertools import chain 

# The global muterate function which dispatches to the various 
# implementations 
def muterate(it): 
    try: 
     return muterate.builtins[type(it)](it) 
    except KeyError: 
     try: 
      return it.muterate() 
     except AttributeError: 
      raise TypeError('No muterator available for {}'.format(type(it))) 
muterate.builtins = {} 

# As I can't implement the muterate method on the builtins, these have 
# to be installed externally in some place where muterate can find 
# them 
def make_muterator(get_iterator): 
    def muterator(container): 
     def make_setter(locator): 
      def setter(new_value): 
       container[locator] = new_value 
      return setter 
     for locator, value in get_iterator(container): 
      yield make_setter(locator), value 
    return muterator 
muterate.builtins[list] = make_muterator(enumerate) 
muterate.builtins[dict] = make_muterator(dict.items) 

# An iterable, mutable type which does not (AND SHOULD NOT) support 
# item setting. 
def make_linked_list(data): 
    the_list = EmptyList() 
    for datum in data: 
     the_list = LinkedList(datum, the_list) 
    return the_list 

class EmptyList: 

    def __iter__(self): 
     return; yield 

    def muterate(self): 
     return; yield 

class LinkedList: 

    def __init__(self, head, tail): 
     self._head = head 
     self._tail = tail 

    def __iter__(self): 
     return chain((self._head,), self._tail) 

    def muterate(self): 
     def setter(new_value): 
      self._head = new_value 
     return chain(((setter, self._head),), self._tail.muterate()) 

    def __repr__(self): 
     return "<{}>".format(', '.join(map(str,tuple(self)))) 
    __str__ = __repr__ 

# Putting the muterate protocol through its paces 
l = range(10) 
d = {letter:rank for (rank, letter) in enumerate('abcdefghij')} 
ll = make_linked_list(reversed(range(10))) 
for iterable in (l,d,ll): 
    for setit, e in muterate(iterable): 
     if e%2: 
      setit(1000*e) 
    print iterable 

其中给出的输出:

[0, 1000, 2, 3000, 4, 5000, 6, 7000, 8, 9000] 
{'a': 0, 'c': 2, 'b': 1000, 'e': 4, 'd': 3000, 'g': 6, 'f': 5000, 'i': 8, 'h': 7000, 'j': 9000} 
<0, 1000, 2, 3000, 4, 5000, 6, 7000, 8, 9000> 

换句话说,所有的奇数元素已被muterating环,它看起来相同所有乘以1000 原始容器内涉及的类型不是太难看,也不依赖于项目设置的可用性。

+0

+1为“muterate”。 – 2014-11-07 01:12:23