如何在 Python 3 中使用迭代器重新分配多个变量(如果可能)

How to reassign multiple variables (if possible) with an iterator in Python 3

更新 添加一个用法示例以更好地解释为什么 我试图引发这种行为。请参阅 post 末尾的 更新。为 link 添加了更好的语法,并在建议的文章中添加了 link 作为答案。

我正在尝试使用迭代器来更改变量列表的值。

>>> a = 1
>>> b = 2
>>> c = 3
>>> for i in [a,b,c]:
        i += 1
>>> a,b,c #Expecting (2, 3, 4)
(1, 2, 3)

这似乎不起作用,我尝试了一些其他方法(见下文)但没有成功。 1.有人能告诉我解决这个问题的更好方法吗? 2. 有人会解释为什么上面的例子没有像我预期的那样工作吗? 3. 有人会告诉我 how/where 我可以在 python 帮助文档中找到 #2 吗?

我以前寻找答案的地方...

Whosebug question "reassign variable to original value defined prior to the loop at start of each"

Whosebug question on reassigning variables (but not a list of variables)

Python docs: Objects and Value Types

Python docs section 3.1.3

我觉得最后一次参考 python 文档可能有答案,但我被大量的信息淹没了,我的大脑很累,我希望有人在 s.o.可以帮忙。

也试过...

>>> help(__name__)
Help on module __main__:

NAME
    __main__

DATA
    __annotations__ = {}
    a = 1
    b = 2
    c = 3
    i = 4

FILE
    (built-in)

但如果有的话,这只会让我更加困惑。

最后我尝试了...

>>> a = 1
>>> b = 2
>>> c = 3
>>> R = [a, b, c]
>>> for i in range(3):
    R[i] += 1

>>> a, b, c #Hoping for (2, 3, 4)
    (1, 2, 3)
>>> R #Kind of expected (1, 2, 3) based on the above behavior
    [2, 3, 4]

更新 为方便起见,我使用了列表,因为我可以遍历其成员。我不理解的部分是当我说...

>>> x = [a, b, c]

我正在创建一个列表

x = [the value assigned to a,
 the value assigned to b,
 the value assigned to c]

而不是

x = [变量a,变量b,变量c]

所以当我尝试使用语法时

>>> x[0] += 1 #take the current ITEM in place 0 and increment its value by 1.

而不是

>>> a += 1

它被解释为... 将 ITEM 的当前值取为 0, 将该值增加 1, 这是 ITEM 的新值 0 ... 并且我丢失了对原始 ITEM 的引用...变量 a.

这是我为什么要引发这种行为的用法示例...

>>> class breakfast():
>>>     def __init__(self, eggs=None, bacon=None, spam=None):
>>>        self.eggs = eggs
>>>        self.bacon = bacon
>>>        self.spam = spam
>>>        updateOrder = False
>>>        updateItems = []
>>>        for i in [self.eggs, self.bacon, self.spam]:
>>>             if i == None:
>>>                 updateOrder = True
>>>                 updateItems.append(i)
>>>             else:
>>>                 pass
>>>         if updateOrder:
>>>             self.updateOrder(itemsToUpdate = updateItems)
>>>
>>>    def updateOrder(self, itemsToUpdate):
>>>        for i in itemsToUpdate: ###also tried...
>>>     ###for i in range(len(itemsToUpdate)):
>>>            print('You can\'t order None, so I am updating your order to 0 for some of your items.')
>>>            i = 0
>>>         ###itemsToUpdate[i] = 0
>>>
>>> #Finally, the good part, behavior I'm after...
>>> myBreakfast = breakfast(eggs=2,bacon=3)

You can't order None, so I am updating your order to 0 for some of your items.
>>> myBreakfast.spam == 0 #hoping for True....
False

我知道唯一能实现这种行为的方法是说...

>>>     ...
>>>     def updateOrder(self):
>>>         orderUpdated=False
>>>         if self.eggs == None:
>>>             self.eggs = 0
>>>             orderUpdated = True
>>>         if self.bacon == None:
>>>             self.bacon = 0
>>>             orderUpdated = True
>>>         if self.spam == None:
>>>             self.spam = 0
>>>             orderUpdated = True
>>>         if orderUpdated:
>>>             print('You can\'t order None, so I am updating your order')

但是,如果 menu 中的项目(很多)超过 3 个,updateOrder 的代码会变得很长,更糟 重复。

您必须使用循环并在循环期间更改列表的每个值

a=[1, 2, 3]
for i in range(len(a)):
    a[i] += 1

输出将是

[2, 3, 4]

要访问和更改列表中的值,您需要 select 基于项目的位置(您也可以使用切片)。所以,a[0] = 1,a[1] = 2 等等。要更改 a[0] 的值,您需要为其分配一个新值(就像在 for 循环中所做的那样)。

您的示例不起作用,因为您只是更改了 i 的值(即 1、2、3),而不是实际更改列表。您没有select列表本身的任何项目。

文档已提供 here(请参阅第 3.1.3 节)

编辑

根据您的说明:创建已在别处定义的变量列表:

a, b, c = 5, 6, 7
letters = [a, b, c]

# See id of variable a
id(a) 
# 94619952681856

# See id of letters[0]
id(letters[0]
# 94619952681856

# Add 1 to letters[0]
letters[0] += 1

# See id of letters[0]
# 94619952681888

正如你所看到的,当第一次创建列表时,列表中的项目指向同一个变量但是,一旦列表中的值发生变化,python就会创建一个新项目,使得原始值不变。 反之亦然。变量a的任何变化都不会影响列表,因为一旦变量被修改,它的id就会改变,而列表中项目的id不会。

而在早餐的例子中,为什么不直接指定 0 作为每道菜的默认值,而不是 None?除非有其他原因,否则会容易得多。

编辑 2: 如果您需要按照您提供的方式更新属性,则需要使用 setattr 方法

class breakfast():
    def __init__(self, eggs=None, bacon=None, spam=None):
        self.eggs = eggs
        self.bacon = bacon
        self.spam = spam
        # Create a list of attributes. This will return [self, eggs,bacon,spam]
        attributes = list(locals().keys())
        attributes.remove('self') # Remove self from the list

        updateItems = []
        for i in attributes:
            # Check if the attribute is None or not
            if getattr(self, i) == None:
                updateItems.append(i)
            else:
                pass

        for i in updateItems:
            setattr(self, i, 0) # Set the attributes that are None to 0