def print_formatted(number):
for n in range(number):
n+=1
methods = ['int', 'oct', 'hex', 'bin']
ls = [eval(method + '(n)') for method in methods]
I don't know why doesn't eval() work in list comprehension.
eval()
is overkill here. These builtins are objects in their own right. There's no need to go through strings.
Adding 1 to n
every loop isn't required because you could start your range at 1 and end one later.
And you're not actually printing or returning the list. You could do a print(ls)
or something.
def print_formatted(number):
for n in range(1, number+1):
methods = [int, oct, hex, bin]
ls = [method(n) for method in methods]
print(ls)
And these aren't technically "methods" since they're not attached to a class.
Another issue is that comprehensions have their own local scope, as if you had defined a generator function (one that contains a yield
). The n
from the surrounding (nonlocal) scope was never used in the comprehension, so the compiler didn't include it in the comprehension's locals, so eval()
couldn't see it. You can explicitly pass in the namespace you want to eval()
though.
def print_formatted(number):
for n in range(number):
n+=1
methods = ['int', 'oct', 'hex', 'bin']
loc = locals() # gets local namespace outside of comp as a dict
ls = [eval(method + '(n)', loc) for method in methods]
print(ls)
print_formatted(4)
[1, '0o1', '0x1', '0b1']
[2, '0o2', '0x2', '0b10']
[3, '0o3', '0x3', '0b11']
[4, '0o4', '0x4', '0b100']
You could also use n
in the comprehension somewhere so that the compiler will include it inside the comprehension's locals. (eval()
defaults to using the local namespace when you don't provide one.) It's not enough to include n
in the eval()
string because that could change at runtime, which is after the time the compiler has to decide what the locals for the comprehension are.
def print_formatted(number):
for n in range(number):
n+=1
methods = ['int', 'oct', 'hex', 'bin']
ls = [eval(method + '(n)') for method in methods for _ in [n]]
print(ls)
I am not recommending you actually do this. The above is only to explain what's going on here, in case you were using a minimal example illustrating the problem for a case that does need eval()
, but you don't need eval()
at all here.
Code should be comprehensible for humans (readability counts) otherwise we'd all still be using assembly language. Too much magic can be confusing. String metaprogramming with eval/exec is about the strongest magic built in to Python. Easy to use, but difficult to use correctly. Avoid it when you don't need it. Even if you think you need it, you probably don't: eval()
is way overused by beginners (of those who know it exists) and they almost never need it.