How to decrement a variable while printing in Python? - python

Some if and else's can be rewritten1 and shortened2 (codegolf-style) likewise, because booleans can act as integers in Python. For example if a<b:return a can be rewritten3 as return("",a)[a<b].
In this case (I simplified the condition for readability),
if a<b: print(a)
can be rewritten as both of the following:
print(("",a)[a<b])
(print(""),print(a))[a<b]
(if we ignore newlines, else end="" can be used).
I would like to decrement a variable n (the whole thing is in a while loop with n in its condition) when a<b is true on top of everything, eg.
if a<b:
print(a)
n-=1
while using the syntax trick above.
In C, (n/n--)-1 is not only equal to 0, but also substracts 1 from n. In Python, I haven't found a way to do this. Some invalid syntaxes I tried:
print(("",a+(n/n--)-1)[a<b])
(print(""),(print(a);n-=1))[a<b]
How to decrement the variable (and print a) when the condition is true using this "trick"?
1,2,3: these statements aren't always true

Python isn't C. For one thing, Python doesn't have a decrement operator, so print(n--) won't work. For another, assignments in Python are statements, not expressions, so print(n-=1) won't work.
If you truly wanted your print statement to have side effects, it could invoke a function:
def decrement():
global n
n -= 1
return n
print(decrement())
But don't. No one will expect that your print statement has side-effects, so everyone will be surprised when commenting out your print statement changes the program's result.
EDIT: I just noticed that this is a code golf question. In that case, my stylistic advice isn't really valid. Everyone expects golfed code to be weird.
Ps. If your goal is to change if statements into expressions, then play with and and or, which short circuit. For example:
a<b and (print(a), decrement())
Or use if ... else expressions
(print(a),decrement()) if a<b else None

n = 10
print(n // (n := n-1) - 1)
# (x := y) is the equivalent of x = y
#but you can use it inside expressions
#and it returns the new value of x
# finally a C simple assignment
a = (b := 1)
print(a, b)
gives
0
1 1

Related

How do I not repeat my list comprehension in a lambda

I am trying to be unnecessarily fancy with a challenge from codesignal. The problem: "Given a number and a range, find the largest integer within the given range that's divisible by the given number."
I have l for left boundary, r for right boundary, and d for the divisor. If none of the numbers within the boundary are divisible, then the function must return a -1. Otherwise, return the largest divisible number.
Is there a way to avoid repeating the list comprehension?
Is there a better way to do this altogether? (that is equally unreadable and unnecessary of course)
These receive a NameError: name '_' is not defined, which makes sense.
maxDivisor = lambda l,r,d: _[0] if [i for i in range(l,r+1)[::-1] if i%d==0] else -1
maxDivisor = lambda l,r,d: [i for i in range(l,r+1)[::-1] if i%d==0][0] if _ else -1
This works, but I don't want to repeat myself:
maxDivisor = lambda l,r,d: [i for i in range(l,r+1)[::-1] if i%d==0][0] if [i for i in range(l,r+1)[::-1] if i%d==0] else -1
This works, but is too readable:
def maxDivisor(left, right, divisor):
for i in range(left,right+1)[::-1]:
if i%divisor ==0:
return i
return -1
Just to reiterate:
maxDivisor(-99,-96,5) should return -1 and
maxDivisor(1,10,3) should return 9.
Thank you for your help with my unnecessary request.
Do not write bad and unreadable code just for the sake of writing bad and unreadable code.1)
Instead, I'd suggest using max with a generator expression and a default, which does, and reads, exactly what you want: Get the max number in this range which is a divisor, or -1 if no such thing exists.
res = max((x for x in range(l, r+1) if x%d==0), default=-1)
Similar, but maybe closer in spirit to what you were trying, you could use next on the filtered reversed range to get the largest such element, or -1 as default.
res = next((x for x in range(r, l-1, -1) if x%d==0), -1)
If you really want to be "fancy", though, how about this: Instead of testing all the numbers, just get the result directly in O(1):
res = r - (r % d) if (r - (r % d) >= l) else -1
(All of the parens are unnecessary here, but IMHO make it more readable, so this even fulfills part of your requirement.)
From your comment, it seems like you are trying "Code Golf", where the goal is to have the shortest code possible. In this case, you might go with the third approach, but use this variant without the ternary ... if ... else .... This should also fully qualify for your "unnecessary and unreadable" requirement:
x=[r-r%d,-1][r-r%d<l] # for code-golf only!
I will not tell you how it works, though, you have to find this out for yourself.
1) Unless this is some sort of obfuscated-code-challenge, maybe.

How to stop short circuiting in Python?

Python short circuits the logical operators.
for eg:
if False and Condition2:
#condition2 won't even be checked because the first condition is already false.
Is there a way to stop this behavior. I want it to check both the conditions and then perform the and operation(as done in c, c++ etc). It's useful when we are performing some operation along with the condition. e.g.:
if a < p.pop() and b < p.pop():
One way can be checking the conditions before and then comparing the Boolean values. But that would be wastage of memory.
if all([a < p.pop(), b < p.pop()])
This creates a list, which will be evaluated in its entirety, and then uses all to confirm that both values are truthy. But this is somewhat obscure and I'd rather suggest you write plain, easy to understand code:
a_within_limit = a < p.pop()
b_within_limit = b < p.pop()
if a_within_limit and b_within_limit:
If the conditions are booleans, as they are in your example, you could use & instead:
>>> a, b, p = 1, 1, [0, 0]
>>> (a < p.pop()) & (b < p.pop())
False
>>> p
[]
You can use the all() and any() built-in functions to somehow emulate the and and or operators. Both take an iterable of boolean-likes values as parameter. If you give it a literal tuple or list, all members will be fully evaluated:
# all emulates the and operator
if all((False, Condition2)):
do_stuff()
# any emulates the or operator
if any((False, Condition2)):
do_stuff()
Short answer: No, you cannot stop it to do this.
For example:
av = p.pop()
bv = p.pop()
if a < av and b < bv:
pass
Or:
av, bv = p.pop(), p.pop()
if a < av and b < bv:
pass
Also, there is no waste of memory in these examples. In Python, almost everything is done by reference. The value object being popped already exists somewhere. Even the scalars like strings, ints, etc are objects (some of them are slightly optimized). The only memory changes here are (1) the creation of a new variable that refers to the same existing object, and (2) removal of the record in the dict at the same time (which referred to that object before popping). They are of the similar scale.

Understanding recursive odd/even functions

I'm currently studying python from http://www.sololearn.com/Play/Python and I'm having trouble understanding why this code works.
def is_even(x):
if x == 0:
return True
else:
return is_odd(x-1)
def is_odd(x):
return not is_even(x)
print(is_odd(1))
I get how recursion works for a fibonacci and factorial but I can't wrap my head around this one.
is_even's base case resolves to True. Since is_odd(x) returns not is_even(x), the value True will be a part of the expression returned by is_odd. The question is how many times will that True value be negated. By tracing the calls you can see it will be negated an even number of times, and hence "retain" its truthiness, when x is odd [e.g.: x=3 ==> (not (not (not (not True)))) == True] and an odd number of times, and hence "lose" its truthiness, when x is even [e.g.: x=2 ==> (not (not (not True))) == False]. There's probably some term from logic that names this general property of multiple negation.
It's based on an inductive definition of evenness:
Zero is even
If some number "n" is even, then "n+1" is not even
If some number "n" is not even, then "n+1" is even
"odd" is obviously "not even".
The code takes this definition, and checks it backwards - using recursion.
If i have zero, then it is even
If I have some other number "n" , then it is even if "n-1" is not - that is, if "n-1" is odd.
That recursive function is really a bad way to teach recursion, you should apply recursion only when it's useful. In fact, test those functions with negative numbers and you'll get RuntimeError: maximum recursion depth exceeded errors.
To check parity numbers you'd better use % operator or & and operator, ie:
def is_even(x):
return (x & 1) == 0
def is_odd(x):
return (x & 1) == 1
That said, I think #Elazar & #DAXaholic answers should give you some insights about that buggy recursive function and wrap your mind about it.
A little hint:
0 -> True
1 -> not True
2 -> not not True
3 -> not not not True
...
and so on.

Compacting an if statement

I want to write this if statement as compact as possible (to avoid having duplicate code)
if length == 10 if boolean is False or length == 13 if boolean is True:
The part that PyCharm does not like is the
if boolean is True
It asks for a colon.
PyCharm does not allow me to run it. Does anyone have a nice compact solution to this if?
I think you meant
if (not boolean and length == 10) or (boolean and length == 13):
The parentheses aren't necessary, but I think they help readability. #jonsharpe's solution is even shorter and only has to evaluate boolean once, but it may be harder to read, especially if you're not familiar with Python's ternary expressions.
Never use is for equality comparison (that's what == is for), but boolean types should never be explicitly compared to True or False anyway.
You can use a conditional expression (also known as a "ternary") to write it out much more concisely:
if length == 13 if boolean else length == 10:
or, equivalently:
if length == (13 if boolean else 10):
Per the documentation:
The expression x if C else y first evaluates the condition, C (not x); if C is true, x is evaluated and its value is returned; otherwise, y is evaluated and its value is returned.

Ternary returns/assignments vs traditional if-else blocks

PEP 8 discourages the usage of compound statements, but I couldn't find anything about the advised usage of Python's ternary/conditional syntax. For example:
return x if n == 0 else y
i = x if n == 0 else y if n == 1 else z
Does there exist any convention concerning whether the above statements should be preferred to more traditional if/else blocks?
if n == 0:
return x
return y
if n == 0:
i = x
elif n == 1:
i = y
else:
i = z
The "traditional if/else blocks" should generally be preferred.
The only places where you'd still want to use the ternary operator is in places where the syntax requires an expression, e.g. within lambda expressions. Even there, only do it if the ternary expression is short and readable (of course, readability is subjective..)
You can always replace a lambda expression with a small function, but in places where you think that would make the code less readable, it is ok to use lambda expressions with short ternary operations.
I agree with shx2's comments.
Another consideration is testability... using the ternary expr places all the logic on a single line/expr. Basic line-base code coverage tools wouldn't then give a good read on the true coverage of your tests.
Using traditional is/else blocks gives a better reading.

Categories