![](/img/trans.png)
[英]"Pythonic"/more elegant way to set multiple variables to the same function call or list comprehension
[英]More elegant way of declaring multiple variables at the same time
要在“同时”声明多个变量,我会这样做:
a, b = True, False
但是如果我不得不声明更多的变量,它就会变得越来越不优雅:
a, b, c, d, e, f, g, h, i, j = True, True, True, True, True, False, True ,True , True, True
有没有更好/优雅/方便的方法来做到这一点?
这一定是非常基本的,但是如果我确实使用了一个列表或一个元组来存储变量,我将如何处理以便我会有所帮助,因为:
aList = [a,b]
无效,我必须这样做:
a, b = True, True
或者我错过了什么?
a, b, c, d, e, g, h, i, j = (True,)*9
f = False
正如其他人所建议的那样,使用 10 个不同的具有布尔值的局部变量不太可能是编写例程的最佳方式(特别是如果它们真的只有一个字母的名称:)
根据您在做什么,使用字典可能更有意义。 例如,如果您想为一组单字母标志设置布尔预设值,您可以这样做:
>>> flags = dict.fromkeys(["a", "b", "c"], True)
>>> flags.update(dict.fromkeys(["d", "e"], False))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}
如果您愿意,也可以使用单个赋值语句来完成:
>>> flags = dict(dict.fromkeys(["a", "b", "c"], True),
... **dict.fromkeys(["d", "e"], False))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}
dict
的第二个参数并非完全为此而设计:它实际上是为了允许您使用d=False
等关键字参数覆盖字典的各个元素。 上面的代码将**
后面的表达式的结果**
一组传递给被调用函数的关键字参数。 这当然是创建词典的可靠方法,人们似乎至少接受了这个习语,但我怀疑有些人可能认为它是 Unpythonic。 </disclaimer>
如果您经常使用这种模式,那么另一种方法可能是最直观的,它是将您的数据定义为映射到标志名称(单字符字符串)的标志值( True
、 False
)列表。 然后将此数据定义转换为倒排字典,将标志名称映射到标志值。 这可以通过嵌套列表理解非常简洁地完成,但这是一个非常易读的实现:
>>> def invert_dict(inverted_dict):
... elements = inverted_dict.iteritems()
... for flag_value, flag_names in elements:
... for flag_name in flag_names:
... yield flag_name, flag_value
...
>>> flags = {True: ["a", "b", "c"], False: ["d", "e"]}
>>> flags = dict(invert_dict(flags))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}
函数invert_dict
是一个生成器函数。 它生成或产生——意味着它重复返回——键值对的值。 这些键值对是初始flags
字典的两个元素的内容的倒数。 它们被送入dict
构造函数。 在这种情况下, dict
构造函数的工作方式与上面不同,因为它被提供给迭代器而不是字典作为其参数。
借鉴@Chris Lutz 的评论:如果您真的将它用于单字符值,您实际上可以这样做
>>> flags = {True: 'abc', False: 'de'}
>>> flags = dict(invert_dict(flags))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}
这是有效的,因为 Python 字符串是可迭代的,这意味着它们可以通过一个值一个值地移动。 对于字符串,值是字符串中的单个字符。 因此,当它们被解释为可迭代对象时,例如在 for 循环中使用它们的情况下, ['a', 'b', 'c']
和'abc'
实际上是等效的。 另一个例子是当它们被传递给一个带有可迭代对象的函数时,比如tuple
。
我个人不会这样做,因为它读起来不直观:当我看到一个字符串时,我希望它被用作单个值而不是一个列表。 所以我看着第一行并想“好吧,所以有一个 True 标志和一个 False 标志。” 因此,尽管这是一种可能性,但我认为这不是可行的方法。 从好的方面来说,它可能有助于更清楚地解释迭代器和迭代器的概念。
定义函数invert_dict
使其实际返回一个字典也不是一个坏主意; 我主要只是没有这样做,因为它并没有真正帮助解释例程是如何工作的。
显然,Python 2.7 具有字典推导式,这将为实现该功能提供一种极其简洁的方式。 这留给读者作为练习,因为我没有安装 Python 2.7 :)
您还可以组合来自多功能itertools模块的一些功能。 正如他们所说,有不止一种方法可以做到。 等等,Python 人不会这么说的。 好吧,无论如何在某些情况下都是如此。 我猜 Guido 已经给了我们字典理解,以便有一种明显的方法来做到这一点。
使用列表/字典或定义您自己的类来封装您定义的内容,但如果您需要所有这些变量,您可以执行以下操作:
a = b = c = d = e = g = h = i = j = True
f = False
这是对@ Jeff M和我的评论的详细说明。
当你这样做时:
a, b = c, d
它适用于元组打包和解包。 您可以将打包和解包步骤分开:
_ = c, d
a, b = _
第一行创建了一个名为_
的元组,它有两个元素,第一个元素的值为c
,第二个元素的值为d
。 第二行将_
元组解包到变量a
和b
。 这打破了你的一条巨线:
a, b, c, d, e, f, g, h, i, j = True, True, True, True, True, False, True, True, True, True
分成两条较小的行:
_ = True, True, True, True, True, False, True, True, True, True
a, b, c, d, e, f, g, h, i, j = _
它将为您提供与第一行完全相同的结果(如果您向一个部分添加值或变量但忘记更新另一个,则包括相同的异常)。 但是,在这种特定情况下, 严的回答可能是最好的。
如果您有一个值列表,您仍然可以解压缩它们。 您只需要先将其转换为元组。 例如,下面将分别为a
到j
每a
分配一个介于 0 和 9 之间的值:
a, b, c, d, e, f, g, h, i, j = tuple(range(10))
编辑:除了元素 5(变量f
)之外,将所有这些都分配为 true 的巧妙技巧:
a, b, c, d, e, f, g, h, i, j = tuple(x != 5 for x in range(10))
当人们建议“使用列表或元组或其他数据结构”时,他们的意思是,当您关心许多不同的值时,将它们全部单独命名为局部变量可能不是最好的方法做事。
相反,您可能希望将它们聚集到一个更大的数据结构中,该结构可以存储在单个局部变量中。
intuted 展示了如何为此使用字典,Chris Lutz 展示了如何在解包到单独的变量之前使用元组进行临时存储,但另一个要考虑的选择是使用collections.namedtuple
将值更永久地捆绑在一起。
因此,您可能会执行以下操作:
# Define the attributes of our named tuple
from collections import namedtuple
DataHolder = namedtuple("DataHolder", "a b c d e f g")
# Store our data
data = DataHolder(True, True, True, True, True, False, True)
# Retrieve our data
print(data)
print(data.a, data.f)
当然,真正的代码希望使用比“DataHolder”和字母表中的字母更有意义的名称。
究竟有什么问题呢?
如果您真的需要或想要 10 个a 、 b 、 c 、 d 、 e 、 f 、 g 、 h 、 i 、 j ,则没有其他可能性,一次或另一次,写a ,写b ,写c 。 ....
如果值都不同,您将不得不编写例如
a = 12
b= 'sun'
c = A() #(where A is a class)
d = range(1,102,5)
e = (line in filehandler if line.rstrip())
f = 0,12358
g = True
h = random.choice
i = re.compile('^(!= ab).+?<span>')
j = [78,89,90,0]
也就是说,单独定义“变量”。
或者,使用另一种书写方式,无需使用_
:
a,b,c,d,e,f,g,h,i,j =\
12,'sun',A(),range(1,102,5),\
(line for line in filehandler if line.rstrip()),\
0.12358,True,random.choice,\
re.compile('^(!= ab).+?<span>'),[78,89,90,0]
或者
a,b,c,d,e,f,g,h,i,j =\
(12,'sun',A(),range(1,102,5),
(line for line in filehandler if line.rstrip()),
0.12358,True,random.choice,
re.compile('^(!= ab).+?<span>'),[78,89,90,0])
.
如果其中一些必须具有相同的值,则是写太长的问题
a, b, c, d, e, f, g, h, i, j = True, True, True, True, True, False, True ,True , True, True
?
然后你可以写:
a=b=c=d=e=g=h=i=k=j=True
f = False
.
我不明白你的问题到底是什么。 如果要编写代码,则必须使用编写说明和定义所需的字符。 还有什么 ?
我想知道你的问题是不是表明你误解了什么。
当写入a = 10
,不会创建“其值可以更改的内存块”意义上的变量。 本指令:
要么触发创建一个integer
类型和值 10 的对象,并将名称 'a' 与当前命名空间中的该对象绑定
或者将命名空间中的名称'a'重新分配给对象10 (因为'a'之前已绑定到另一个对象)
我这么说是因为我没有看到定义 10 个标识符 a,b,c... 指向 False 或 True 的实用程序。 如果这些值在执行过程中没有改变,为什么是 10 个标识符? 如果它们发生变化,为什么要先定义标识符?,如果没有事先定义,它们将在需要时创建
你的问题对我来说很奇怪
听起来你对我来说以错误的方式解决你的问题。
重写您的代码以使用元组或编写一个类来存储所有数据。
我喜欢最高票的答案; 但是,如图所示,它存在列表问题。
>> a, b = ([0]*5,)*2
>> print b
[0, 0, 0, 0, 0]
>> a[0] = 1
>> print b
[1, 0, 0, 0, 0]
这将详细讨论(here) ,但要点是a
和b
是同一个对象, a is b
返回True
( id(a) == id(b)
)。 因此,如果您更改索引,您将同时更改a
和b
的索引,因为它们是链接的。 要解决这个问题,您可以这样做(来源)
>> a, b = ([0]*5 for i in range(2))
>> print b
[0, 0, 0, 0, 0]
>> a[0] = 1
>> print b
[0, 0, 0, 0, 0]
然后可以将其用作最佳答案的变体,它具有“所需的”直观结果
>> a, b, c, d, e, g, h, i = (True for i in range(9))
>> f = (False for i in range(1)) #to be pedantic
在你的情况下,我会使用 YAML 。
这是处理多个参数的优雅而专业的标准。 这些值是从一个单独的文件加载的。 您可以在此链接中看到一些信息:
https://keleshev.com/yaml-quick-introduction
但是谷歌更容易,因为它是一个标准,有数百条关于它的信息,你可以找到最适合你理解的。 ;)
此致。
像JavaScript一样,你也可以在 python a = 1; b = "Hello World"; c += 3
一行中使用多个语句a = 1; b = "Hello World"; c += 3
a = 1; b = "Hello World"; c += 3
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.