I don't understand this syntax.
Python program to demonstrate ternary operator
a, b = 10, 20
Use tuple for selecting an item
print( (b, a) [a < b] )
Use Dictionary for selecting an item
print({True: a, False: b} [a < b])
PS: I guess this is from older version of Python, because in newer versions (don't know from which version) True and False are reserved keywords, so they can't be assigned a value.
lamda is more efficient than above two methods
because in lambda we are assure that only one expression will be evaluated unlike in
tuple and Dictionary
print((lambda: b, lambda: a)[a < b]())
Syntax should be:
[on_true] if [expression] else [on_false]
So how does
print( (b, a) [a < b] )
print({True: a, False: b} [a < b])
print((lambda: b, lambda: a)[a < b]())
fit this syntax?
What's the meaning of [a<b] after tuple/dictionary/lambda? I have never seen this syntax before. It also works when list [b, a] precedes [a<b].
I would expect it to look like this
print( a if a < b else b )
Link to resource:
https://www.geeksforgeeks.org/ternary-operator-in-python/
First note that all these give the minimum value of a and b:
a, b = 10, 20
res1 = (b, a)[a < b] # 10
res2 = {True: a, False: b}[a < b] # 10
res3 = (lambda: b, lambda: a)[a < b]() # 10
We can consider these in turn:
res1 constructs a tuple of 2 integers. a < b returns a Boolean value, in this case True. In Python, True == 1, as bool is a subclass of int. Finally, [] is syntactic sugar for __getitem__, which is the method called for positional indexing. Since Python starts counting from 0, the first index is a. You can also confirm this yourself: (b, a).__getitem__(1) returns 10.
res2 constructs a dictionary mapping Boolean values to a & b. Calling __getitem__ on a dict object returns the value for a given key. Here the key, as before, is True. Since the dictionary maps True to a, this is the value returned.
res3 constructs a tuple of anonymous (lambda) functions, each returning scalars, namely b and a. As per res1, an item can be extracted from a tuple via integer indexing. The only additional requirement is to actually call the lambda functions via ().
Note none of these operate the same way as the ternary operator which is applied at compile time (see comments) via an in-line if / else:
res4 = a if a < b else b
a<b is a bool (True or False). Since bool is a subtype of int, it can be used in a context where an integer is expected, e.g. as a list/tuple index:
>>> True == 1
True
>>> False == 0
True
>>> isinstance(True, int)
True
>>> ('a', 'b')[True] # True == 1
'b'
>>> ('a', 'b')[1<2] # 1<2 == True == 1
'b'
>>> ('a', 'b')[2<1] # 2<1 == False == 0
'a'
For dict keys, it is similar, but the type coercion is not even needed:
>>> {True: 'a', False: 'b'}[1<2] # 1<2 == True
'a'
Your misconception might be regarding a < b .
In all these cases the boolean result of evaluating a < b is used as a key for the object in before.
In the case of
print( (b, a) [a < b] )
and
print((lambda: b, lambda: a)[a < b]())
the object is a tuple containing either the variables themselves or very simple anonymus functions, that return these variables.
In the case of
print({True: a, False: b} [a < b])
the expression is evaluated and used as a key for the dictionary, which has both True and False as keys. The assumption that this means, that it must be an older Python version is incorrect thoug, because a dictionary does not represent a reassignment of values, but is merely a data structure, where a key maps to a value. True and False are valid keys and this circumstance is precisely, what is being used here.
Finally:
print( a if a < b else b )
Is a nice and concise may of expressing the same thing and in fact the line of code I would use in this case
I have am coding the algorithm of Bolzano in Python. This is my code for now:
def Bolzano(fonction, a, b, tol=0.000001):
while abs(b-a)>tol:
m=(a+b)/2
if cmp(fonction(m))==cmp(fonction(a)):
a=m
else:
b=m
return a, b
It works until it encounters cmp, which it doesn't recognise. However I don't see another way to do it, since Python doesn't have a sign function. Is there any other way to extract the sign of a number?
Is there any other way to extract the sign of a number?
How about writing your own?
Implementation
def sign(num):
return -1 if num < 0 else 1
Example
>>> sign(10)
1
>>> sign(-10)
-1
Ohh and cmp is a built-in that requires two parameters (numbers) and simply compares them and checks which of them is larger. You should have used it as follows
def Bolzano(fonction, a, b, tol=0.000001):
while abs(b-a)>tol:
m=(a+b)/2
if cmp(fonction(m), fonction(a)) == 0:
a=m
else:
b=m
return a, b
Maybe use:
if cmp(fonction(m),fonction(a)) == 0:
def same_sign(a, b):
return (a * b) >= 0
Examples:
>>> same_sign(3, 4)
True
>>> same_sign(-3, 4)
False
>>> same_sign(3, -4)
False
>>> same_sign(-3, -4)
True
>>> same_sign(-3, 0)
True
If not, what is the best way to do this?
Right now I'm doing (for a django project):
if not 'thing_for_purpose' in request.session:
request.session['thing_for_purpose'] = 5
but its pretty awkward. In Ruby it would be:
request.session['thing_for_purpose'] ||= 5
which is much nicer.
Jon-Eric's answer's is good for dicts, but the title seeks a general equivalent to ruby's ||= operator.
A common way to do something like ||= in Python is
x = x or new_value
Precise answer: No. Python does not have a single built-in operator op that can translate x = x or y into x op y.
But, it almost does. The bitwise or-equals operator (|=) will function as described above if both operands are being treated as booleans, with a caveat. (What's the caveat? Answer is below of course.)
First, the basic demonstration of functionality:
x = True
x
Out[141]: True
x |= True
x
Out[142]: True
x |= False
x
Out[143]: True
x &= False
x
Out[144]: False
x &= True
x
Out[145]: False
x |= False
x
Out[146]: False
x |= True
x
Out[147]: True
The caveat is due python not being strictly-typed, and thus even if the values are being treated as booleans in an expression they will not be short-circuited if given to a bitwise operator. For example, suppose we had a boolean function which clears a list and returns True iff there were elements deleted:
def my_clear_list(lst):
if not lst:
return False
else:
del lst[:]
return True
Now we can see the short-circuited behavior as so:
x = True
lst = [1, 2, 3]
x = x or my_clear_list(lst)
print(x, lst)
Output: True [1, 2, 3]
However, switching the or to a bitwise or (|) removes the short-circuit, so the function my_clear_list executes.
x = True
lst = [1, 2, 3]
x = x | my_clear_list(lst)
print(x, lst)
Output: True []
Above, x = x | my_clear_list(lst) is equivalent to x |= my_clear_list(lst).
dict has setdefault().
So if request.session is a dict:
request.session.setdefault('thing_for_purpose', 5)
Setting a default makes sense if you're doing it in a middleware or something, but if you need a default value in the context of one request:
request.session.get('thing_for_purpose', 5) # gets a default
bonus: here's how to really do an ||= in Python.
def test_function(self, d=None):
'a simple test function'
d = d or {}
# ... do things with d and return ...
In general, you can use dict[key] = dict.get(key, 0) + val.
In Python, the assignment operator can unpack a list or a tuple into variables, like this:
l = (1, 2)
a, b = l # Here goes auto unpack
But I need to specify exactly the same amount of names to the left as an item count in the list to the right. But sometimes I don't know the size of the list to the right, for example, if I use split().
Example:
a, b = "length=25".split("=") # This will result in a="length" and b=25
But the following code will lead to an error:
a, b = "DEFAULT_LENGTH".split("=") # Error, list has only one item
Is it possible to somehow unpack the list in the example above so I can get a = "DEFAULT_LENGTH" and b equals to None or not set? A straightforward way looks kind of long:
a = b = None
if "=" in string :
a, b = string.split("=")
else :
a = string
This may be of no use to you unless you're using Python 3. However, for completeness, it's worth noting that the extended tuple unpacking introduced there allows you to do things like:
>>> a, *b = "length=25".split("=")
>>> a,b
("length", ['25'])
>>> a, *b = "DEFAULT_LENGTH".split("=")
>>> a,b
("DEFAULT_LENGTH", [])
I.e. tuple unpacking now works similarly to how it does in argument unpacking, so you can denote "the rest of the items" with *, and get them as a (possibly empty) list.
Partition is probably the best solution for what you're doing however.
# 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]
This is slightly better than your solution but still not very elegant; it wouldn't surprise me if there's a better way to do it.
a, b = (string.split("=") + [None])[:2]
The nicest way is using the partition string method:
Split the string at the first occurrence of sep, and return a 3-tuple containing the part before the separator, the separator itself, and the part after the separator. If the separator is not found, return a 3-tuple containing the string itself, followed by two empty strings.
New in version 2.5.
>>> inputstr = "length=25"
>>> inputstr.partition("=")
('length', '=', '25')
>>> name, _, value = inputstr.partition("=")
>>> print name, value
length 25
It also works for strings not containing the =:
>>> inputstr = "DEFAULT_VALUE"
>>> inputstr.partition("=")
('DEFAULT_VALUE', '', '')
If for some reason you are using a version of Python before 2.5, you can use list-slicing to do much the same, if slightly less tidily:
>>> x = "DEFAULT_LENGTH"
>>> a = x.split("=")[0]
>>> b = "=".join(x.split("=")[1:])
>>> print (a, b)
('DEFAULT_LENGTH', '')
..and when x = "length=25":
('length', '25')
Easily turned into a function or lambda:
>>> part = lambda x: (x.split("=")[0], "=".join(x.split("=")[1:]))
>>> part("length=25")
('length', '25')
>>> part('DEFAULT_LENGTH')
('DEFAULT_LENGTH', '')
You could write a helper function to do it.
>>> 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)
But sometimes I don't know a size of the list to the right, for example if I use split().
Yeah, when I've got cases with limit>1 (so I can't use partition) I usually plump for:
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] is there to get an empty ‘str’ or ‘unicode’, matching whichever of those the split produced. You could use None if you prefer.)
Don't use this code, it is meant as a joke, but it does what you want:
a = b = None
try: a, b = [a for a in 'DEFAULT_LENGTH'.split('=')]
except: pass
Many other solutions have been proposed, but I have to say the most straightforward to me is still
a, b = string.split("=") if "=" in string else (string, None)
As an alternative, perhaps use a regular expression?
>>> 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')
If you make sure the re.match() always succeeds, .groups() will always return the right number of elements to unpack into your tuple, so you can safely do
a,b = unpack_re.match(x).groups()
I don't recommend using this, but just for fun here's some code that actually does what you want. When you call unpack(<sequence>), the unpack function uses the inspect module to find the actual line of source where the function was called, then uses the ast module to parse that line and count the number of variables being unpacked.
Caveats:
For multiple assignment (e.g. (a,b) = c = unpack([1,2,3])), it only uses the first term in the assignment
It won't work if it can't find the source code (e.g. because you're calling it from the repl)
It won't work if the assignment statement spans multiple lines
Code:
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.")
Have you tried this?
values = aString.split("=")
if len(values) == 1:
a = values[0]
else:
a, b = values