I don't know how to effectively word my question, but I'll try my best. I want to be able to use a 'for' statement to iterate through a dictionary and access previously-made 'self' items. Like I said, hard to word the question.
I have found that I can use exec() to do it, but I had been told not to use exec() unless absolutely necessary. Also, I realize what this example does is technically useless, but it's a very simplified version of what I need.
global counter
counter = 0
class GUI:
def __init__(self):
self.stuff = ["foo","bar","fooest","barest"]
for i in self.stuff:
self.process(i)
self.printAll()
def process(self,i):
global counter
counter += 1
self.__dict__.update({"ex{}".format(counter):i})
def printAll(self):
global counter
while counter > 0:
exec("print(self.ex{})".format(counter))
counter -= 1
GUI()
This does work; printAll(self) does print self.ex1 thru ex4. Is there a way to do it without exec()?. Please help!
global counter
counter = 0
class GUI:
def __init__(self):
self.stuff = ["foo","bar","fooest","barest"]
for i in self.stuff:
self.process(i)
self.printAll()
def process(self,i):
global counter
counter += 1
self.__dict__.update({"ex{}".format(counter):i})
def printAll(self):
global counter
while counter > 0:
print(eval("self.ex{}".format(counter)))
counter -= 1
GUI()
I hope this is suitable in your case
Related
This question already has answers here:
How can I access "static" class variables within methods?
(6 answers)
Closed 2 years ago.
I am trying to place a method in a class that will replace null values with running average of non null values. Please refer to the code below:
class ElNinoData(object):
# Your implementation here
add = 0
counter = 0
average = 0
# methods
def __init__(self , object):
self.object = object
def get_humidity(self):
if not math.isnan(self.object['humidity']):
global add
global counter
global average
add += self.object['humidity']
counter += 1
average = add/counter
else:
self.object['humidity'] = average
return self.object['humidity']
While executing this class in a method, I am getting the following error:
<ipython-input-40-c52c3ac6484b> in get_humidity(self)
19 global average
20
---> 21 add += self.object['humidity']
22 counter += 1
23 average = add/counter
NameError: name 'add' is not defined
Could anyone please explain the error,I am relatively new to python?
class ElNinoData(object):
add = 0
The add here is not a global variable,
global add
therefore this does not give access to it, but instead looks for that actual global.
add += self.object['humidity']
+= requires the variable to exist already (so that the old value can be added to), and you don't have a global add, nor a local one - you have a class attribute.
To access it directly, you can use ElNinoData.add, just as you would from code outside the class. Similarly for the other class attributes.
Looking up the class attribute via the instance - self.add - also succeeds. However, modifying the value then attaches a separate attribute to the instance, and leaves the class attribute unaffected.
If you want the members to be specific to an object, change it to this
class ElNinoData(object):
# Nothing here
# methods
def __init__(self , object):
self.add = 0
self.counter = 0
self.average = 0
self.object = object
and continue to refer to them with self..
If you want them to be class-wide, leave them where they are, but refer to them via ElNinoData..
In any case, you shouldn't use global here.
I think the problem is that your values add, counter and average are not global.
In order to set these values on your class instance, you have to use self instead.
Something like this:
def get_humidity(self):
if not math.isnan(self.object['humidity']):
self.add += self.object['humidity']
self.counter += 1
self.average = add/counter
else:
self.object['humidity'] = average
return self.object['humidity']
What you are missing here is that you have initialized the variables but not given them any values and then you are adding the values using +=, due to which python is throwing you this error.
Refer to the below code:-
class ElNinoData(object):
# Your implementation here
add = 0
counter = 0
average = 0
# methods
def __init__(self , object):
self.object = object
def get_humidity(self):
if not math.isnan(self.object['humidity']):
global add
global counter
global average
add = 0
counter = 1
add += self.object['humidity']
counter += 1
average = add/counter
else:
self.object['humidity'] = average
return self.object['humidity']
t = {'humidity' : 10}
a =ElNinoData(t)
a.get_humidity()
I have the following code:
counter = 0
def function_1():
func_2(counter)
def func_2(counter):
func_3(counter)
def func_3(counter):
counter += 1
My goal is to keep track of counter incrementation in func_3() in all other functions.
I tried to make counter global
counter = 0
def function_1():
global counter
func_2(counter)
def func_2(counter):
func_3(counter)
def func_3(counter):
counter += 1
but it does not work, the counter incrementation is just local to func_3()
Any hints?
I tried to find an easy to understand explanation for you, but they all seemed to complicated.
The reason that you are seeing counter as a local variable inside your functions is because you are defining it in the function definition: def func_2(counter):.
To use the global counter inside a function you need to do it like this:
counter = 0
def function_1():
func_2()
def func_2():
func_3()
def func_3():
global counter
counter += 1
You can use globals().update(locals()), example:
counter = 0
def function_1():
func_2()
def func_2():
func_3()
def func_3():
counter += 1
globals().update(locals())
or use global method
counter = 0
def function_1():
func_2()
def func_2():
func_3()
def func_3():
global counter
counter += 1
So I'm designing a hangman game using Python and Kivy and I want to add a win/lose option.
one of the functions I've defined is Button_pressed which hides the button if it's been pressed but I want the function man_is_hung() to have something that says "if the button has been pressed 6 times, show "game over"."
Would someone please help me?
def button_pressed(button):
for (letter, label) in CurrentWord:
if (letter.upper() == button.text): label.text=letter
button.text=" " # hide the letter to indicate it's been tried
def man_is_hung():
if button_pressed(button)
Use a decorator:
Example:
class count_calls(object):
def __init__(self, func):
self.count = 0
self.func = func
def __call__(self, *args, **kwargs):
# if self.count == 6 : do something
self.count += 1
return self.func(*args, **kwargs)
#count_calls
def func(x, y):
return x + y
Demo:
>>> for _ in range(4): func(0, 0)
>>> func.count
4
>>> func(0, 0)
0
>>> func.count
5
In py3.x you can use nonlocal to achieve the same thing using a function instead of a class:
def count_calls(func):
count = 0
def wrapper(*args, **kwargs):
nonlocal count
if count == 6:
raise TypeError('Enough button pressing')
count += 1
return func(*args, **kwargs)
return wrapper
#count_calls
def func(x, y):
return x + y
Demo:
>>> for _ in range(6):func(1,1)
>>> func(1, 1)
...
raise TypeError('Enough button pressing')
TypeError: Enough button pressing
You could store the button as a class like so:
class button_pressed(Object):
def __init__(self):
self.num_calls = 0
def __call__(self, button):
self.num_calls += 1
if self.num_calls > 6:
print "Game over."
return None
else:
# Your regular function stuff goes here.
This is basically a manual decorator, and while it might be a bit complicated for what you are trying to do this is an easy way to do bookkeeping on a function.
Really, the correct way to do this kind of thing is to use a decorator that takes a parameter for the number of times you want the function to be able to be called and then applies the above pattern automatically.
Edit: Ahh! hcwhsa beat me to it. His solution is the more general one I was talking about above.
Here's a way to have static variables in functions that doesn't involve globals or classes:
def foobar():
foobar.counter = getattr(foobar, 'counter', 0)
foobar.counter += 1
return foobar.counter
for i in range(5):
print foobar()
ummmm
num_presses = 0
def button_pressed(button):
global num_presses
num_presses += 1
if num_presses > X:
print "YOU LOSE SUCKA!!!"
for (letter, label) in CurrentWord:
if (letter.upper() == button.text): label.text=letter
button.text=" " # hide the letter to indicate it's been tried
would be one way of doing it ... Im kind of suprised you have made it this far without knowing how to save simple states.
In Python, is there a way to assign different decorators to functions as variables?
For example (the following code doesn't execute, obviously):
def status_display(function):
def body():
print("Entering", function.__name__)
function()
print("Exited", function.__name__)
return body
def call_counter(function):
counter = 0
def body():
function()
nonlocal counter
counter += 1
print(function.__name__, 'had been executed', counter, 'times')
return body
def a_function():
print('a_function executes')
# problems start here
# is there a working alternative to this false syntax?
#status_display
a_function_with_status_display = a_function()
#call_counter
a_function_with_call_counter = a_function()
# for an even crazier feat
# I knew this wouldn't work even before executing it
a_function_with_status_display = #status_display a_function()
a_function_with_call_counter = #call_counter a_function()
Thanks in advance.
a_function_with_status_display = status_display(a_function)
a_function_with_call_counter = call_counter(a_function)
You seem to be able to write decorators, but you don't know what they do?
class bambino(object):
counter = 7
def __init__(self):
print("bambino.counter is self.counter ?", bambino.counter is self.counter)
self.counter += 1
print("bambino.counter is self.counter ?", bambino.counter is self.counter)
bambi1 = bambino()
print ("bambi1.counter:", bambi1.counter)
print ("bambino.counter:", bambino.counter)
prints:
bambino.counter is self.counter ? True
bambino.counter is self.counter ? False
bambi1.counter: 8
bambino.counter: 7
I understand that by doing self.counter += 1 counter becomes an attribute of the instance not of the class.
But why did bambi1.counter take it's initial value from bambino.counter?
If an attribute is not found in an object, it gets looked up higher in the hierarchy, first in its class, and then, if not found, in the superclasses.
self.counter += 1 is equivalent to self.counter = self.counter + 1. So to assign the bambi1.counter, Python first needs to get the value of bambi1.counter. Since the bambi1 does not initially have a counter, python doesn't find it and has to look it up in its class.
PS: Please capitalize your class names.