在Python中,赋值运算符可以将列表或元组解包为变量,如下所示:
l = (1, 2)
a, b = l # Here goes auto unpack
但我需要在左侧指定与左侧列表中的项目计数完全相同的名称。但有时候我不知道右边列表的大小,例如,如果我使用split()。
示例:
a, b = "length=25".split("=") # This will result in a="length" and b=25
但是以下代码会导致错误:
a, b = "DEFAULT_LENGTH".split("=") # Error, list has only one item
是否有可能以某种方式解压缩上面示例中的列表,这样我就可以得到一个=“DEFAULT_LENGTH”并且b等于None
或者没有设置?直截了当的方式看起来有点长:
a = b = None
if "=" in string :
a, b = string.split("=")
else :
a = string
答案 0 :(得分:56)
除非你使用的是Python 3,否则这对你没用。但是,为了完整起见,值得注意的是那里引入的extended tuple unpacking允许你做以下事情:
>>> a, *b = "length=25".split("=")
>>> a,b
("length", ['25'])
>>> a, *b = "DEFAULT_LENGTH".split("=")
>>> a,b
("DEFAULT_LENGTH", [])
即。现在,元组解包与它在参数解包中的工作方式类似,因此您可以使用*
表示“其余项目”,并将它们作为(可能为空)列表。
分区可能是您正在做的最佳解决方案。
答案 1 :(得分:48)
# this will result in a="length" and b="25"
a, b = "length=25".partition("=")[::2]
# this will result in a="DEFAULT_LENGTH" and b=""
a, b = "DEFAULT_LENGTH".partition("=")[::2]
答案 2 :(得分:7)
这比你的解决方案略胜一筹,但仍然不是很优雅;如果有更好的方法,我不会感到惊讶。
a, b = (string.split("=") + [None])[:2]
答案 3 :(得分:6)
最好的方法是使用partition string method:
在第一次出现sep时拆分字符串,并返回包含分隔符之前的部分的3元组,分隔符本身以及分隔符之后的部分。如果找不到分隔符,则返回一个包含字符串本身的3元组,后跟两个空字符串。
2.5版中的新功能。
>>> inputstr = "length=25"
>>> inputstr.partition("=")
('length', '=', '25')
>>> name, _, value = inputstr.partition("=")
>>> print name, value
length 25
它也适用于不包含=
的字符串:
>>> inputstr = "DEFAULT_VALUE"
>>> inputstr.partition("=")
('DEFAULT_VALUE', '', '')
如果由于某种原因你在2.5之前使用的是Python版本,你可以使用list-slicing来做同样的事情,如果稍微不整齐:
>>> x = "DEFAULT_LENGTH"
>>> a = x.split("=")[0]
>>> b = "=".join(x.split("=")[1:])
>>> print (a, b)
('DEFAULT_LENGTH', '')
..以及x = "length=25"
时:
('length', '25')
轻松变成函数或lambda:
>>> part = lambda x: (x.split("=")[0], "=".join(x.split("=")[1:]))
>>> part("length=25")
('length', '25')
>>> part('DEFAULT_LENGTH')
('DEFAULT_LENGTH', '')
答案 4 :(得分:4)
您可以编写辅助函数来执行此操作。
>>> def pack(values, size):
... if len(values) >= size:
... return values[:size]
... return values + [None] * (size - len(values))
...
>>> a, b = pack('a:b:c'.split(':'), 2)
>>> a, b
('a', 'b')
>>> a, b = pack('a'.split(':'), 2)
>>> a, b
('a', None)
答案 5 :(得分:1)
但有时候我不知道右边列表的大小,例如我是否使用split()。
是的,当我有限制> 1的情况下(所以我不能使用分区)我通常会喜欢:
def paddedsplit(s, find, limit):
parts= s.split(find, limit)
return parts+[parts[0][:0]]*(limit+1-len(parts))
username, password, hash= paddedsplit(credentials, ':', 2)
(parts[0][:0]
可以得到一个空的'str'或'unicode',匹配分割产生的那些。如果你愿意,可以使用None。)
答案 6 :(得分:0)
不要使用这个代码,它是一个笑话,但它可以做你想要的:
a = b = None
try: a, b = [a for a in 'DEFAULT_LENGTH'.split('=')]
except: pass
答案 7 :(得分:0)
已经提出了许多其他解决方案,但我必须说对我来说最直接的仍然是
a, b = string.split("=") if "=" in string else (string, None)
答案 8 :(得分:0)
作为替代方案,也许使用正则表达式?
>>> import re
>>> unpack_re = re.compile("(\w*)(?:=(\w*))?")
>>> x = "DEFAULT_LENGTH"
>>> unpack_re.match(x).groups()
('DEFAULT_LENGTH', None)
>>> y = "length=107"
>>> unpack_re.match(y).groups()
('length', '107')
如果确保re.match()始终成功,.groups()将始终返回正确数量的元素以解压缩到您的元组中,这样您就可以安全地进行
a,b = unpack_re.match(x).groups()
答案 9 :(得分:0)
我不建议使用此功能,但只是为了好玩,这里有一些代码可以实现您想要的功能。当您调用unpack(<sequence>)
时,unpack
函数使用inspect
模块查找调用函数的实际源代码行,然后使用ast
模块解析该行并计算要解压缩的变量数。
注意事项:
(a,b) = c = unpack([1,2,3])
),它仅使用作业中的第一项代码:
import inspect, ast
from itertools import islice, chain, cycle
def iter_n(iterator, n, default=None):
return islice(chain(iterator, cycle([default])), n)
def unpack(sequence, default=None):
stack = inspect.stack()
try:
frame = stack[1][0]
source = inspect.getsource(inspect.getmodule(frame)).splitlines()
line = source[frame.f_lineno-1].strip()
try:
tree = ast.parse(line, 'whatever', 'exec')
except SyntaxError:
return tuple(sequence)
exp = tree.body[0]
if not isinstance(exp, ast.Assign):
return tuple(sequence)
exp = exp.targets[0]
if not isinstance(exp, ast.Tuple):
return tuple(sequence)
n_items = len(exp.elts)
return tuple(iter_n(sequence, n_items, default))
finally:
del stack
# Examples
if __name__ == '__main__':
# Extra items are discarded
x, y = unpack([1,2,3,4,5])
assert (x,y) == (1,2)
# Missing items become None
x, y, z = unpack([9])
assert (x, y, z) == (9, None, None)
# Or the default you provide
x, y, z = unpack([1], 'foo')
assert (x, y, z) == (1, 'foo', 'foo')
# unpack() is equivalent to tuple() if it's not part of an assignment
assert unpack('abc') == ('a', 'b', 'c')
# Or if it's part of an assignment that isn't sequence-unpacking
x = unpack([1,2,3])
assert x == (1,2,3)
# Add a comma to force tuple assignment:
x, = unpack([1,2,3])
assert x == 1
# unpack only uses the first assignment target
# So in this case, unpack('foobar') returns tuple('foo')
(x, y, z) = t = unpack('foobar')
assert (x, y, z) == t == ('f', 'o', 'o')
# But in this case, it returns tuple('foobar')
try:
t = (x, y, z) = unpack('foobar')
except ValueError as e:
assert str(e) == 'too many values to unpack'
else:
raise Exception("That should have failed.")
# Also, it won't work if the call spans multiple lines, because it only
# inspects the actual line where the call happens:
try:
(x, y, z) = unpack([
1, 2, 3, 4])
except ValueError as e:
assert str(e) == 'too many values to unpack'
else:
raise Exception("That should have failed.")
答案 10 :(得分:-2)
你试过这个吗?
values = aString.split("=")
if len(values) == 1:
a = values[0]
else:
a, b = values