assign value to a variable using eval in a metaprogramming manner - python

I want to assign value to a variable using eval in a metaprogramming manner. My attempt was shown below:
sample = None
var_name = "sample"
value = 0
eval("{0} = {1}".format(var_name, value))
However, I got the following error:
Traceback (most recent call last):
File "tmp.py", line 4, in <module>
eval("{0} = {1}".format(var_name, value))
File "<string>", line 1
sample = 0
^
SyntaxError: invalid syntax
Could you explain how can I do this? I think lower level function like assign(var, val) could exist and this enabled assignment using eval. But I couldn't find such function.

Use exec instead:
sample = None
var_name = "sample"
value = 0
exec("{0} = {1}".format(var_name, value))
eval is for evaluating an expression, not an assignment statement

does exec accomplish what you're trying to do?:
sample = None
var_name = "sample"
value = 5
exec(f"{var_name} = {value}")
print(sample)
output: 5

If you're outside a function you can use
globals()[varname] = value
Example:
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> globals()['a'] = 5
>>> a
5
Inside a function there's locals() but it can only read from the symbol table and not update so you should use eval() like other answers have pointed out.
You can also cheat by using setattr/hasattr/getattr on an object:
>>> class Object:
... pass
...
>>> obj = Object()
>>> obj.a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Object' object has no attribute 'a'
>>> setattr(obj, 'a', 3)
>>> obj.a
3

Related

How to call variable from another function by declaring global in python?

func 1
def num1():
global h
h=7
func 2
def num2():
print(h)
When I call this function:
num2()
Here, it should print the value of h which is globally declared in func 1.
But it is giving NameError why?? Anyone answer me plz..
to access the global variable h through num2() make sure to call num1() before calling num2()
Defining num1 doesn't actually define h. The definition of num1 just says that, when you call num1, it will assign to the global name h. If h doesn't exist at that time, it will be created. But defining num1 isn't sufficient to create h.
You need to ensure that h exists before num2 is called. You can do that by assigning to h yourself, or calling num1.
>>> num2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in num2
NameError: name 'h' is not defined
>>> h = 3
>>> num2()
3
>>> del h
>>> num2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in num2
NameError: name 'h' is not defined
>>> num1()
>>> num2()
7

How does the `j` suffix for complex numbers work? Can I make my own suffix?

I know what are complex numbers and how they mathematically work, but how is it done for python to know it's complex just by putting a j after a digit ?
>>> j
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'j' is not defined
>>> 1*j
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'j' is not defined
>>> 1j
1j
>>> 1j**2
(-1+0j)
Can I make my own suffix, let's say p (for strictly positive) ?
Could I do something working like this ?
>>> ... some weird stuff here ...
>>> p
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'p' is not defined
>>> 1*p
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'p' is not defined
>>> -1p
1p
>>> 0p
1p
>>>
This is built into Python's grammar, just like the decimal point is, or the e in scientific notation (1e10 etc.). The j makes a numeric literal imaginary.
Python does not allow you to change this. That doesn't mean you can't--you could amend the grammar--but then the language is no longer Python.
The closest approximation allowed in Python would be by implementing an operator.
>>> class StrictlyPositive:
def __rmatmul__(self, number):
return abs(number)
>>> p = StrictlyPositive()
>>> -1#p
1
But you have to be careful of operator precedence when doing stuff like this. Why not just use the builtin abs directly?

How to dereference an object in Python?

I have a function with returns a tuple:
def gradiant(params, data):
Q1 = params[0]
Q2 = params[1]
dQ1 = sum(2*(y_i - Q1*x_i - Q2)*(x_i) for x_i, y_i in data)
dQ2 = sum(-2*(y-i - Q1*x_i - Q2) for x_i, y_i in data)
return (dQ1, dQ2)
I'm trying to print the returned values:
grad = gradiant(params, Data)
for x in grad: print(x)
Output:
<generator object <genexpr> at 0x7fdfe009adc0>
<generator object <genexpr> at 0x7fdfe009a5f0>
How do I get to print the integer values?
You have a y-i instead of y_i. It produced a NameError for me. I fixed the typo and it worked fine (I assume, anyway - it printed two numbers).
However, the more interesting issue is how errors are handled within generator expressions (as the typo was part of the generator expression you sent to sum()). I got a NameError, but you got generator expression objects. Look at this function call with an unpacked generator that should contain a TypeError:
>>> print(*(''.join(item2) for item2 in range(3)))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: print() argument after * must be a sequence, not generator
Now let's see what we get by printing the actual object:
>>> print(''.join(item2) for item2 in range(3))
<generator object <genexpr> at 0x00000000028945E8>
That makes some sense, as generators are lazily evaluated and it was never actually called. But let's see what happens when we send it to list(), which should force evaluation:
>>> print(list(''.join(item2) for item2 in range(3)))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <genexpr>
TypeError: can only join an iterable
There's the expected error.
How about a valid generator that contains an invalid generator?
>>> print(*(list(''.join(item2) for item2 in range(3)) for i in range(1)))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: print() argument after * must be a sequence, not generator
The same uninformative error.
What if we use a list comprehension instead of a generator expression?
>>> print(*[''.join(item2) for item2 in range(3)])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <listcomp>
TypeError: can only join an iterable
We get the informative error we were expecting.
Unfortunately, I don't know why this happens, but be extra-careful with generator expressions.

Error while calling Python function

I defined a function which takes 2 arguments. When I call the function, I get an error saying not enough argument:
>>> def fib(self, a,b):
... self.i=a, self.j=b
... print self.i+self.j
...
>>> fib(4,8)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: fib() takes exactly 3 arguments (2 given)
>>> fib(4,8,9)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fib
AttributeError: 'int' object has no attribute 'i'
I passed with both 2 and 3 arguments. What should be the third argument?
I am assuming you don't understand self very well in python. Its heading towards OOP (Object oriented programming).
non-OOP approach (doing the same thing with static methods)
def fib(a,b):
print a+b
fib(4,8)
OOP approach
class Test():
i = 0
j = 0
def fib(self, a,b):
self.i=a
self.j=b
print self.i+self.j
t = Test() # create an object of Test class
t.fib(2, 3) # make the function call
NOTE : python considers a function to be a static function if it does not have the keyword self as the first parameter
You function has 3 arguments: self, a and b.
self is traditionally used for methods.
You write (simplified example):
class A:
def multiply(self, b): # method called with one argument
return 2 * b
a = A()
a.multiply(3)
or
def multiply(b): # this is a function with one argument
return 2*b
mutiply(3)

Simple Function does not work, dont see the error

I am a beginning python programmer, but have written several scripts including ones in which I define my own functions and use them. I cannot seem to get any user defined functions to work within the IDLE. Wondering if I am crazy/dumb. Can somebody please explain the following results?Thanks:
def f(x,y):
solution = x+y
return solution
f(2,2)
SyntaxError: invalid syntax
>>> a = f(2,2)
Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
a = f(2,2)
NameError: name 'f' is not defined
def g(x):
solution = x + 2
return solution
g(2)
SyntaxError: invalid syntax
>>> a = g(2)
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
a = g(2)
NameError: name 'g' is not defined
Add a blank line after the definition of the function to make the interpreter understand that it's finished.
>>> def f(x,y):
solution = x+y
return solution
>>> f(2,2)
4

Categories