This question already has answers here:
How do I reliably split a string in Python, when it may not contain the pattern, or all n elements?
(5 answers)
Closed 5 years ago.
I've often been frustrated by the lack of flexibility in Python's iterable unpacking. Take the following example:
a, b = "This is a string".split(" ", 1)
Works fine. a contains "This" and b contains "is a string", just as expected. Now let's try this:
a, b = "Thisisastring".split(" ", 1)
Now, we get a ValueError:
ValueError: not enough values to unpack (expected 2, got 1)
Not ideal, when the desired result was "Thisisastring" in a, and None or, better yet, "" in b.
There are a number of hacks to get around this. The most elegant I've seen is this:
a, *b = mystr.split(" ", 1)
b = b[0] if b else ""
Not pretty, and very confusing to Python newcomers.
So what's the most Pythonic way to do this? Store the return value in a variable and use an if block? The *varname hack? Something else?
This looks perfect for str.partition:
>>> a, _, b = "This is a string".partition(" ")
>>> a
'This'
>>> b
'is a string'
>>> a, _, b = "Thisisastring".partition(" ")
>>> a
'Thisisastring'
>>> b
''
>>>
How about adding the default(s) at the end and throwing away the unused ones?
>>> a, b, *_ = "This is a string".split(" ", 1) + ['']
>>> a, b
('This', 'is a string')
>>> a, b, *_ = "Thisisastring".split(" ", 1) + ['']
>>> a, b
('Thisisastring', '')
>>> a, b, c, *_ = "Thisisastring".split(" ", 2) + [''] * 2
>>> a, b, c
('Thisisastring', '', '')
Similar (works in Python 2 as well):
>>> a, b, c = ("Thisisastring".split(" ", 2) + [''] * 2)[:3]
>>> a, b, c
('Thisisastring', '', '')
The *varname hack seems very pythonic to me:
Similar to how function parameters are handled
Lets you use a one-liner or if block or nothing to correct type of the element if desired
You could also try something like the following if you don't find that clear enough for new users
def default(default, tuple_value):
return tuple(map(lambda x: x if x is not None else default, tuple_value))
Then you can do something like
a, *b = default("", s.split(...))
Then you should be able to depend on b[0] being a string.
I fully admit that the definition of default is obscure, but if you like the effect, you can refine until it meets your aesthetic. In general this is all about what feels right for your style.
Related
I checked all Stackoverflow questions on this matter and none can answer my problem.I need to convert \\ to \.
Edited:
This is what I am trying:
>>> a = b'\xe5jb\x8c?Q$\xf3\x1d\x97^\xfa3O\xa6U.txt'
>>> b = str(a)
>>> b
"b'\\xe5jb\\x8c?Q$\\xf3\\x1d\\x97^\\xfa3O\\xa6U.txt'"
>>> b = b.replace('b\'','')
>>> b = b[:len(b)-1]
>>> b
'\\xe5jb\\x8c?Q$\\xf3\\x1d\\x97^\\xfa3O\\xa6U.txt'
>>> c = bytes(b,'utf8')
>>> c
b'\\xe5jb\\x8c?Q$\\xf3\\x1d\\x97^\\xfa3O\\xa6U.txt'
>>> a == c
False
How do I make a==c True? I tried
.replace("\\\\","\\")
but this doesn't help. The string remains the same. I need to store the byte in variable 'a' to a file as a text and call it back. Python-3.8, Windows=10
You can convert c to a string with the decode method, and then use ast.literal_eval to evaluate it as a bytes literal after wrapping it with b'...':
from ast import literal_eval
a = b'\xe5jb\x8c?Q$\xf3\x1d\x97^\xfa3O\xa6U.txt'
c = b'\\xe5jb\\x8c?Q$\\xf3\\x1d\\x97^\\xfa3O\\xa6U.txt'
c = literal_eval("b'%s'" % c.decode())
print(a == c)
This outputs: True
Use .replace() function for string
I want to concat few strings together, and add the last one only if a boolean condition is True.
Like this (a, b and c are strings):
something = a + b + (c if <condition>)
But Python does not like it. Is there a nice way to do it without the else option?
Thanks! :)
Try something below without using else. It works by indexing empty string when condition False (0) and indexing string c when condition True (1)
something = a + b + ['', c][condition]
I am not sure why you want to avoid using else, otherwise, the code below seems more readable:
something = a + b + (c if condition else '')
This should work for simple scenarios -
something = ''.join([a, b, c if condition else ''])
It is possible, but it's not very Pythonic:
something = a + b + c * condition
This will work because condition * False will return '', while condition * True will return original condition. However, You must be careful here, condition could also be 0 or 1, but any higher number or any literal will break the code.
Is there a nice way to do it without the else option?
Well, yes:
something = ''.join([a, b])
if condition:
something = ''.join([something, c])
But I don't know whether you mean literally without else, or without the whole if statement.
a_list = ['apple', 'banana,orange', 'strawberry']
b_list = []
for i in a_list:
for j in i.split(','):
b_list.append(j)
print(b_list)
I tried to find an explanation of this, the Gotcha part:
b = "1984"
a = b, c = "AB"
print(a, b, c)
returns:
('AB', 'A', 'B')
I understand what happens with multiple equals:
a = b = 1
but using it together with a comma, I cannot understand the behaviour, ideas in why it works that way?
The answer is
a = b, c ="AB"
acts like:
a = (b, c) = "AB"
This is why:
a = "AB" and b = "A" and c = "B"
a = b, c = "AB"
Is not interpreted the way you think it does. You do have a multiple assignment, but it is not a = b and c = "AB". It is c,b = "AB" and a = "AB". In python
x = y = z = 1
Is interpreted as x, y, and z getting assigned value 1. And comma is used to unpack lists of values into individual variables, so b, c = "AB" unpacks "AB" into "A" and "B". So at the end of this line,
a = b, c = "AB"
a == "AB"
b == "A"
c == "B"
This comes down to order of operations, line 2 is actually two different statements.
a = b
is completed first. Then
b, c = "AB"
which is unpacking the value of "AB" and assigning "A" to b and "B" to c.
I know it's a basic question but please bear with me. Let's say if we have 4 strings below:
a = ''
b = 'apple'
c = 'orange'
d = 'banana'
So, normally if I want to check if any of the three string a b c is empty, I could use len() function.
if len(a) == 0 or len(b) == 0 or len(c) == 0:
return True
But then I thought it is too troublesome to write like above if I have many strings. So, I used
if not a:
return True
But, when i am checking for multiple strings b c d using the above method, it returns True and I am puzzled as non of the strings b c d where empty.
if not b or c or d:
return True
What is going on?
The problem lies with this line:
if not b or c or d:
You need to include the "not" condition for each string. So:
if not b or not c or not d:
You could also do it like this:
return '' in [a, b, c, d]
The not operator has higher precedence than or.
return not b or not c or not d
should work.
I am new to python and was wondering if someone could help me out with this. I am trying to see if the elements in b are in a. This is my attempt. Currently I am not getting any output. Any help would be appreciated, thank you!
a = [1]
b = [1,2,3,4,5,6,7]
for each in b:
if each not in a == True:
print(each + "is not in a")
You are testing two different things, and the outcome is False; Python is chaining the operators, effectively testing if (each is in a) and (a == True):
>>> 'a' in ['a'] == True
False
>>> ('a' in ['a']) and (['a'] == True)
False
>>> ('a' in ['a']) == True
True
You never need to test for True on an if statement anyway:
if each not in a:
is enough.
You should be able to just say:
if each not in a:
print ("%d is not in a" % each)
Your actual expression is using operator chaining:
if a > b > c:
parses as:
if (a > b) and (b > c):
in python. which means your expression is actually being parsed as:
if (each not in a) and (a == True):
but a == True will always return False, so that if block will never execute.
a = [1,2,3]
b = [1,2,3,4,5,6,7]
c = [7,8,9]
print set(a) <= set(b) #all elements of a are in b
print set(c) <= set(b) #all elements of c are in b
It is better to see the difference between B and A
set(b).difference(set(a))
You don't need ==True. Just:
if each not in a:
This is really easy using sets:
a = [1]
b = [1, 2]
only_in_b = set(b) - set(a)
# set([2])
Another way:
for bb in b:
try:
a.index(bb)
except:
print 'value is not in the list: ' + str(bb)
I would like to add that if the two lists are large. This is not the best way to do it. Your algorithm is O(n^2). The best way is to traverse a, adding the elements as keys to a dictionary. Afterwards, traverse the second list, checking if the elements are already in the dictionary, this instead is an O(n) algorithm.