如何在 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 文档可能有答案,但我被大量的信息淹没了,我的大脑很累,我希望有人在 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
更新 添加一个用法示例以更好地解释为什么 我试图引发这种行为。请参阅 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 文档可能有答案,但我被大量的信息淹没了,我的大脑很累,我希望有人在 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