Create dynamic function in python? - python

I got NameError for calling test_gobject, but the funny thing is I never called this function name. I called test_gobjectpy()
Can you explain it to me why Python decide to call the wrong function name (see error output)
Maybe it has some problems because I have a string with the same name as function?!
file name test_dyn_fun.py
second_path = ['test_gobject.py', 'st1.py', 'test_show_desktop.py', 'download_img.py', 'test_dump.py']
print("second_path", second_path)
print()
for i in second_path:
#func = create_dyn_func(i)
tmp = i.replace(".", "") #rm dot for function name
print("tmp =", tmp)
exec(f"def {tmp}(): print({i})")
print()
print(dir(test_gobjectpy))
print()
print(locals())
test_gobjectpy()
Error output:
Traceback (most recent call last):
File "/home/manta/Coding/test_dyn_fun.py", line 13, in <module>
test_gobjectpy()
File "<string>", line 1, in test_gobjectpy
NameError: name 'test_gobject' is not defined

In your loop you create functions, the first one created is effectively created like this:
i = 'test_gobject.py'
tmp = 'test_gobjectpy'
exec(f"def {tmp}(): print({i})")
So, it's as if you ran:
exec("def test_gobjectpy(): print(test_gobject.py)")
For Python to print test_gobject.py, it tries to access an object called test_gobject and its attribute .py.
That's what is causing the error. The fact that test_gobject.py looks like a filename to you doesn't matter, it's just names of variables to Python, the way you wrote it.
What would you expect to happen if you called this function?
def test_gobjectpy():
print(test_gobject.py)
More in general, as a beginning programmer, it's generally best to stay away from stuff like exec() and eval(). It's very common for new Python programmers to think they need this, or that it somehow solves a problem they have, but it's generally the worst solution to the problem and rarely actually a good solution at all. (not never, just rarely)

Related

Input function interpreted as variable for some reason

Been looking around and can't find an answer.
So I call either raw_input() or input() to fill out a simple variable. But instead of running the function, I get
UnboundLocalError: local variable 'input' referenced before assignment
My code doesn't have 'input()' anywhere before that first call, and never makes a variable sharing the name. Same happens for 'raw_input()'. I'm confused here, as calls to the functions work fine in other code, and also on the console, but for some reason throw errors on this. No previous calls. Funny enough, it worked on my first run of the code, but now doesn't. What am I looking for?
Edit: Someone asked for the code. Not much to show.
end = False
lightsoff = []
lightson = []
bias = []
i = 0
while not end:
print "Set #" + str(i + 1) +", LED off: ",
offFile = input()
EDIT: To correct here, a variable named 'input' is referred to much later in the code (it's long). I wrote a couple of references backwards. I didn't know Python made a list (or something) of what's going to be a local variable before running, thus throwing up problems like this.
I suspect your code looks a bit like:
>>> def x():
... input = input()
... print(input)
...
>>> x()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in x
UnboundLocalError: local variable 'input' referenced before assignment
>>>
The problem is that you've created a variable called 'input', and then trying to get something from it before it exists.
>>> def y():
... val = input()
... print(val)
...
>>> y()
Would work a bit better. In python (and most dynamic languages) functions are kind of values too - so you can use the name of a function just like you would any other variable.
So a good idea is to not name a variable the same as a function.
Does that help?

Python - Function - Argument said to be "undefined"

I'm currently taking a Python course, and got to the chapter in our book that talks about functions. (Please note, this is my first time learning any programming.)
One of the exercises I'm working on at the moment asks for me to turn a bunch of conditional statements into a function (i.e. generalization).
To make this brief, my problem is this:
After I define a function, let's say like so...
def count_letter(letter,string):
count = 0
for letter in string:
count += 1
print(count)
(That is the work, as far as I can recall, for what I typed up for the problem.)
I run the program, then call the function in the shell as usual...
(Example directly below)
>>> count_letter(a,bananana)
And I get the following output...
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
count_letter(a,bananana)
NameError: name 'a' is not defined
My teacher and everyone in our class can't figure out why we're getting such an error. We would understand if it was some other type of an error, but having the shell tell us an argument is 'undefined' (i.e. a variable, as we understand the error) is something we haven't been able to figure out.
We've been staring at the code for a week and still can't figure it out.
Any help would be very appreciated.
Afterthought: I'm trying to count the number of "a"s within "bananana" in the example. Thought I should clear the ambiguity there.
As written, a and bananana are the names of variables which should be defined in a similar way you defined the variable count. For example:
>>> character_to_search = 'l'
>>> text = 'Hello World'
>>> count_letter(character_to_search, text)
would be a correct syntax, because both character_to_search and text are undefined.
Another possibility is that instead of using actual variables, your intention was to pass strings directly to the function. In this case, your syntax is slightly incorrect. It should be (note the single quotes):
count_letter('a', 'bananana')

__class_ data member in python, how it is different from static data member in java

i am trying to execute following code to understand Class data member in python, but it is throwing StopIteration error,
class PizzaShop():
pizza_stock = 10
def get_pizza(self):
while not PizzaShop.pizza_stock:
PizzaShop.pizza_stock -= 1
yield "take yours pizza order, total pizzas left {}".format(PizzaShop.pizza_stock)
mypizza_shop = PizzaShop()
pizza_order = mypizza_shop.get_pizza()
print "{}".format(repr(pizza_order.next()))
i am expecting that it should first print some message and then any exception
i am using python 2.7, ubuntu 32bits os
output:
Traceback (most recent call last):
File "/home/scott/pythonfiles/core_python/pizza.py", line 10, in <module>
print "{}".format(repr(pizza_order.next()))
StopIteration
The problem is this line
while not PizzaShop.pizza_stock:
This will stop immediately if pizza_stock is nonzero. Which it always is. You probably intended to write
while PizzaShop.pizza_stock:
Anyway, if you want to find the details on how values, classes, etc. behave in Python, you should check the docs. It's very different from Java.
P.S. The following is unnecessary as str.format has a shorthand for calling repr. Also, you shouldn't call magic methods like .next directly. Use the builtin next() instead.
print "{}".format(repr(pizza_order.next()))
Should be
print "{!r}".format(next(pizza_order))

Why can I write some things out-of-order in python but not others?

Please have a look below:
a = 5
print a + b
b = 4
When I try to run the code above, it gives an error:
Traceback (most recent call last):
File "C:/Users/user/Documents/modules/ab.py", line 2, in
print a + b
NameError: name 'b' is not defined
Ok. a + b is called before b is defined. That means Python runs the code in order, starts from top to down.
But, how about this one:
class Data:
def __init__(self):
self.debug_level = 9
self.assign = [0, 0, 0, 0]
self.days = 0
def create_days(self, startTime, endTime):
res = 0
try:
if self.final_days < self.maximum_days:
Above, self.final_days and self.maximum_days are not defined yet either, but it does not give any errors. What is the logic behind it?
Best regards,
You're not actually "running" the code yet. In your example, all you have is a method declaration inside the Data class. In it, Python will not check for the existence of class fields because they may be set at another time, in some other method (Python's classes are malleable in that sense).
If you try to run your create_days method in a new instance of the Data class without setting the values for those fields beforehand, you'll get an error.
It doesn't give any errors because the attributes are not accessed when the class is defined. As soon as you call create_days() you'll have a problem :D
The body of a function is evaluated only when it is called, not when it is defined.
References are only looked up when the code is run. You can put whatever names you like in the create_days() method, and none will be checked until the line containing them is executed.
If you actually executed it, you would get
AttributeError: Data instance has no attribute 'final_days'
To reproduce this:
x = Data()
x.create_days(1,2)
also, you have a try block. I assume this is an excerpt from some other code. The try block is probably swallowing the exception.
Python is an interpreted language, unlike c++ it is not compiled so the body of a function isn't evaluated until it is called.

need help-variable creation in Python (continuation)

That was helpful kgiannakakis.
I'm facing a problem as below:
a = ['zbc','2.3']
for i in range(0,5):
exec('E%d=%s' %(i,a[i]))
This results in:
Traceback (most recent call last):
File "", line 2, in
exec('E%d=%s' %(i,a[i]))
File "", line 1, in
NameError: name 'zbc' is not defined
It looks like the code you're generating expands to:
E0=zbc
E1=2.3
At the next iteration through the loop, you'll get an IndexError exception because a is only two elements long.
So given the above, you are trying to assign the value of zbc to E0. If zbc doesn't exist (which it seems that it doesn't), then you will get the NameError you mention.
It's hard to determine what you're actually trying to do with this code, so I'm not sure what to recommend. You could assign strings instead:
exec('E%d="%s"' %(i,a[i]))
This would expand to:
E0="zbc"
E1="2.3"
You would still get the IndexError because your array a is not 5 elements long. That should be an easy fix for you.
Okay. this code is very weird.
As a one liner like this, it's not syntactically correct, but I suspect you're missing line breaks for some reason. But then it becomes
a = ['zbc','2.3']
for i in range(0,5):
exec('E%d=%s' %(i,a[i]))
But that will result in an index error on the reference to a[i] as shown:
>>> a
['zbc', '2.3']
>>> for i in range(0,5):
... print a[i]
...
zbc
2.3
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
IndexError: list index out of range
If you avoided that issue, you'd get
exec("E2.3=1")
on the second pass through the lopp, and that's a syntax error too.
It seems you are trying to use the solution marked in this question.
If your goal is access values in a loop, you should just use a list. This weird concept of variable names with numbers in them is not one that should be used in any language. Try this.
vals = ['foo', 'bar', 'blah', 67, -0.4, 'your mom']
for i in range(len(vals)):
print(vals[i])
That is the correct way to have a list of values indexed by an integer, not putting it in the variable name.
Just keep in mind that 'exec' executes whatever string you pass in to it as if you typed it in your .py file or the interpreter.
When debugging exec() related code, it's helpful to log whatever you're about to 'exec' when you run into trouble, if you did that you'd easily have noticed that E0 wasn't being assigned to the string "zbc" but to the non-existent object zbc.
Aside from that, this code sample is really weird.  There are some legitimate uses for parsing strings into instance variables, or objects in other namespaces, most notably when you're coding a highly dynamic class that needs to do sensible stuff with messy input, or needs to setup a bunch of instance variables from a dict or string.  But without context, the code in your question looks like you're avoiding, or don't understand how, to use list() and dict() objects..
I'd recommend telling a bit more about what you're trying to achieve next time you ask a question around something as peculiar as this.  That would give people a good opportunity to suggest a better solution, or –if you're approaching a particular problem in a completely sensible way– prevent a bunch of answers telling you that you're doing something completely wrong.

Categories

Resources