更优雅的方式同时声明多个变量

时间:2011-03-31 04:28:09

标签: python variables declaration

要在“同一时间”声明多个变量,我会这样做:

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

或者我错过了什么?

10 个答案:

答案 0 :(得分:203)

a, b, c, d, e, g, h, i, j = (True,)*9
f = False

答案 1 :(得分:48)

使用列表/字典或定义您自己的类来封装您正在定义的内容,但如果您需要所有这些变量,您可以这样做:

a = b = c = d = e = g = h = i = j = True
f = False

答案 2 :(得分:46)

正如其他人所建议的那样,使用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等关键字参数覆盖字典的各个元素。上面的代码将**后面的表达式的结果炸成一组传递给被调用函数的keyword arguments。这当然是创建字典的可靠方式,人们似乎至少接受了这个成语,但我怀疑有些人可能认为它是Unpythonic。 </disclaimer>


另一种方法,如果你经常使用这种模式,可能是最直观的,是将数据定义为映射到标志名称的标志值列表(TrueFalse) (单字符串)。然后,将此数据定义转换为反转字典,将字符名称映射到标志值。这可以通过嵌套列表理解非常简洁地完成,但这是一个非常易读的实现:

>>> 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_dictgenerator function生成产生 - 意味着重复返回 - 键值对的值。这些键值对是初始flags字典的两个元素的内容的倒数。它们被送入dict构造函数。在这种情况下,dict构造函数与上面的工作方式不同,因为它被赋予iterator而不是字典作为其参数。


借鉴@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字符串是iterable,这意味着它们可以通过值逐行移动。对于字符串,值是字符串中的单个字符。因此,当它们被解释为可迭代时,就像在for循环中使用它们的情况一样,['a', 'b', 'c']'abc'实际上是等价的。另一个例子是当它们被传递给一个带有可迭代的函数,比如tuple

我个人不会这样做,因为它不直观地阅读:当我看到一个字符串时,我希望它被用作单个值而不是列表。所以我看第一行并想“好的,所以有一个真旗和一个假旗。”所以虽然这是一种可能性,但我认为这不是可行的方法。从好的方面来说,可以更清楚地解释迭代和迭代器的概念。


定义函数invert_dict使其实际返回字典也不是一个坏主意;我大多只是不这样做,因为它没有真正帮助解释例程如何工作。


显然,Python 2.7具有字典理解,这将使得实现该功能的方式非常简洁。这是留给读者的练习,因为我没有安装Python 2.7:)

您还可以组合来自多功能itertools模块的一些功能。如他们所说,There's More Than One Way To Do It。等等,Python的人不这么说。嗯,在某些情况下无论如何都是如此。我猜想Guido已经给了我们字典理解,以便One Obvious Way能够做到这一点。

答案 3 :(得分:9)

这是关于@ Jeff M和我的评论的详细说明。

执行此操作时:

a, b = c, d

它适用于元组打包和拆包。您可以分开包装和拆包步骤:

_ = c, d
a, b = _

第一行创建一个名为_的元组,它有两个元素,第一个元素的值为c,第二个元素的值为d。第二行将_元组解压缩到变量ab中。这打破了你的一条巨大的界限:

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 = _

它将为您提供与第一行完全相同的结果(如果您将值或变量添加到一个部分但忘记更新另一个部分,则包括相同的异常)。 但是,在这种特定情况下,yan's answer可能是最好的。

如果您有值列表,仍可以解压缩它们。你只需要先将其转换为元组。例如,以下内容将分别为aj分配0到9之间的值:

a, b, c, d, e, f, g, h, i, j = tuple(range(10))

编辑:除了元素5(变量f)之外,将所有这些都分配为真的技巧:

a, b, c, d, e, f, g, h, i, j = tuple(x != 5 for x in range(10))

答案 4 :(得分:5)

当人们建议“使用列表或元组或其他数据结构”时,他们所说的是,当您有许多不同的值时,将它们全部命名为局部变量可能不是做事的最佳方式。

相反,您可能希望将它们聚集在一起,形成一个可以存储在单个局部变量中的更大的数据结构。

intuited展示了如何使用字典,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”和字母表字母更有意义的名称。

答案 5 :(得分:4)

事实上,问题是什么?

如果您确实需要或想要10 a b c d e f g h 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个标识符呢?如果它们发生变化,为什么首先定义标识符?,如果没有事先定义,它们将在需要时创建

你的问题对我来说很奇怪

答案 6 :(得分:2)

听起来你正以错误的方式接近你的问题。

重写代码以使用元组或编写类来存储所有数据。

答案 7 :(得分:1)

在您的情况下,我将使用YAML。

这是处理多个参数的一种优雅而专业的标准。 这些值是从单独的文件加载的。 您可以在此链接中看到一些信息:

https://keleshev.com/yaml-quick-introduction

但是对于Google来说,它比较容易,因为它是一种标准,有成百上千的信息,您可以找到最适合您的理解的信息。 ;)

最诚挚的问候。

答案 8 :(得分:0)

我喜欢最高投票的答案;但是,如图所示,列表存在问题。

  >> a, b = ([0]*5,)*2
  >> print b
  [0, 0, 0, 0, 0]
  >> a[0] = 1
  >> print b
  [1, 0, 0, 0, 0]

我们详细讨论了这一问题(here),但要点是aba is b返回True的同一个对象(相同的id(a) == id(b))。因此,如果您更改索引,则会更改ab的索引,因为它们已关联。要解决此问题,您可以执行(source)

>> 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]

然后可以将其用作最佳答案的变体,其具有&#34;期望的&#34;直观的结果

>> a, b, c, d, e, g, h, i = (True for i in range(9))
>> f = (False for i in range(1)) #to be pedantic

答案 9 :(得分:0)

JavaScript 一样,您还可以在python a = 1; b = "Hello World"; c += 3

的一行上使用多个语句