Python 在for-in循环期间追加到元组

Python 在for-in循环期间追加到元组,python,iterator,tuples,Python,Iterator,Tuples,我需要在for in循环期间修改元组,以便迭代器对元组进行迭代 据我理解,元组是不可变的;因此tup=tup+(添加)只是重新分配tup,而不是更改原始的tup。所以这很棘手 下面是一个测试脚本: tup = ({'abc': 'a'}, {'2': '2'}) blah = True to_add = {'goof': 'abcde'} for i in tup: if blah: tup = tup + (to_add,) blah = False

我需要在
for in
循环期间修改元组,以便迭代器对元组进行迭代

据我理解,元组是不可变的;因此
tup=tup+(添加)
只是重新分配
tup
,而不是更改原始的tup。所以这很棘手

下面是一个测试脚本:

tup = ({'abc': 'a'}, {'2': '2'})
blah = True
to_add = {'goof': 'abcde'}
for i in tup:
    if blah:
        tup = tup + (to_add,)
        blah = False
    print(i)
其中打印:

{'abc': 'a'}
{'2': '2'}
我想让它打印:

{'abc': 'a'}
{'2': '2'}
{'goof': 'abcde'}
据我所知,我需要“重新指向”隐式元组迭代器mid脚本,以便它指向新的元组。(我知道这是一件非常令人讨厌的事情)

此脚本访问相关的元组生成器:

import gc

tup = ({'abc': 'a'}, {'2': '2'})
blah = True
to_add = {'goof': 'abcde'}
for i in tup:
    if blah:
        tup = tup + (to_add,)
        blah = False
        refs = gc.get_referrers(i)
        for ref in refs:
            if type(ref) == tuple and ref != tup:
                refs_to_tup = gc.get_referrers(ref)
                for j in refs_to_tup:
                    if str(type(j)) == "<class 'tuple_iterator'>":
                        tuple_iterator = j

    print(i)
导入gc
tup=({'abc':'a'},{'2':'2'})
胡说八道
to_add={'goof':'abcde'}
对于tup中的i:
如果是废话:
tup=tup+(要添加,)
废话
refs=gc.get\u referers(i)
参考文献中的参考文献:
如果类型(ref)=元组和ref!=tup:
refs\u to\u tup=gc.get\u referers(ref)
对于参考图中的j:
如果str(类型(j))==“”:
元组迭代器=j
印刷品(一)
如何修改这个tuple_生成器,使其指向新的tup,而不是旧的tup?这可能吗


我意识到这是一个非常奇怪的情况,我无法更改
tup
是一个元组,或者我需要在
中使用隐式
,因为我试图插入我无法更改的代码。

因为您计划在循环中修改元组,您最好使用while循环来跟踪当前索引,而不是依赖迭代器。迭代器仅适用于循环遍历循环中未添加/删除到的集合

如果运行下面的示例,则生成的tup对象将添加项,同时循环3次

tup = ({'abc': 'a'}, {'2': '2'})
blah = True
to_add = {'goof': 'abcde'}

i = 0
while i < len(tup):
    cur = tup[i]
    if blah:
        tup = tup + (to_add,)
        blah = False
    i += 1

print(tup)
tup=({'abc':'a'},{'2':'2'})
胡说八道
to_add={'goof':'abcde'}
i=0
而我
即使通过
元组迭代器
对象的未记录内部,也无法在CPython中以可移植或特定的方式从Python中执行您试图执行的操作。元组引用存储在一个不向Python公开的变量中,并且(与存储的索引不同)不被
\uuuu setstate\uuuu>或任何其他方法修改

然而,如果您愿意在CPython的背后开始使用C指针,并且您知道如何调试不可避免的错误

在封面下,有一个C结构表示
tuple\u迭代器
。我认为它要么是一个结构,要么是一个形状完全相同的结构,但您应该通读tupleobject源代码以确保

下面是C中该类型的外观:

typedef struct {
    PyObject_HEAD
    Py_ssize_t it_index;
    PyObject *it_seq; /* Set to NULL when iterator is exhausted */
} seqiterobject;
那么,如果创建一个与此大小相同的
ctypes.Structure
子类,会发生什么情况,类似这样的情况:

class seqiterobject(ctypes.Structure):
    _fields_ = (
        ('ob_refcnt', ctypes.c_ssize_t),
        ('ob_type', ctypes.c_void_p),
        ('it_index', ctypes.c_ssize_t),
        ('it_seq', ctypes.POINTER(ctypes.pyobject)))
…然后这样做:

seqiter = seqiterobject.from_address(id(j))
seqiter.it_seq = id(other_tuple)
…然后这样做:

seqiter = seqiterobject.from_address(id(j))
seqiter.it_seq = id(other_tuple)
…?好的,您可能会由于引用不足而损坏堆(并且还会泄漏旧值),因此您需要先增加新值,然后减少旧值

但是,如果您这样做……很可能,它会在下次调用
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu


如果需要更多执行类似操作的示例代码,请参阅。除了
sekiterobject
甚至不是一个公共类型,因此它更具黑客性之外,其他一切基本上都是一样的。

您可以编写自己的
协同程序
,并将新的tup发送给它

def coro(iterable):
    iterable = iter(iterable)
    while True:
        try:
            v = next(iterable)
            i = yield v
        except StopIteration:
            break
        if i:
            yield v
            iterable = it.chain(iterable, i)
那么这就如你所描述的那样起作用了:

In []:   
blah = True
tup = ({'abc': 'a'}, {'2': '2'})
to_add = {'goof': 'abcde'}

c = coro(tup)
for i in c:
    if blah:
        i = c.send((to_add,))
        blah = False
    print(i)

Out[]:
{'abc': 'a'}
{'2': '2'}
{'goof': 'abcde'}

我确信在上面的文章中我遗漏了很多边缘情况,但它应该能让您了解如何做到这一点。

您不能像更改原始元组一样更改
元组迭代器中的元组。因为它们是同一个元组。正如我在前面的问题中所解释的,为什么不在while循环中根据元组的长度进行循环呢?类似于
当我
时,我意识到我无法更改tuple。我不想改变元组。我试图将tuple_迭代器指向新的tuple。“如何修改这个tuple_生成器,使其指向新的tup,而不是旧的tup?这可能吗?”不,不可能。
tuple\u iterator
上没有API来更改它所引用的元组,甚至没有私有的和未记录的元组。编写您自己的协同程序,然后
发送要添加到其中的新元组。