NameError: name 'x' is not defined Python - python

I'm trying to get around this error but can't find a solution. Actually the code worked perfectly some time but suddendly started to drop the error:
"NameError: name 'number_exit' is not defined"
And also:
"NameError: name 'price_buy' is not defined"
The code is generating a list of random numbers
import numpy as np
# This function generates a list of numbers under certain rules
def num_var_list():
global number_list, number_exit, number_target
number_list = []
number_target = number_exit
num_max_robot = (number_target * 20) / 100
while num_max_robot > 0:
num_robot = np.random.randint(1,int(num_max_robot))
if num_robot > number_target:
number_list.append(number_target)
else:
number_list.append(num_robot)
number_target = number_target - number_target
return number_list
# This function generates a random number between a certain range
def fun_price_buy():
global price_buy
price_buy = np.random.randint(50000,300000)
return price_buy
# This function generates a random number between a certain range
def fun_mx_buy():
global number_exit
number_exit = np.random.randint(50, 150)
return number_exit
lista_number_list = []
lista_price_buy = []
lista_mx_buy = []
# This loop append each function 50 times to a new list
while len(lista_price_buy) <= 50:
lista_number_list.append(num_var_list())
lista_price_buy.append(fun_price_buy())
lista_mx_buy.append(fun_mx_buy())
Actually, when Python doesn't drop the error, the code makes exactly what I want it to do. So I'm not sure how to adjust it to let it work without NameError warnings.
Any help will be highly appreciated. Thank you!

When doing global price_buy that means you use the globally defined price_buy to be defined localy in your method but
neither price_buy nor number_exit are defined globally (outside a method)
you don't need global variable
They only to be local, and just better : inlined
def fun_price_buy():
price_buy = np.random.randint(50000,300000)
return price_buy
# inline, no temporaty variable is needed
def fun_price_buy():
return np.random.randint(50000,300000)
Finally, and if you want to get the value from the method in a variable for doing something with it:
import numpy as np
# This function generates a list of numbers under certain rules
def num_var_list(number_exit):
number_list = []
number_target = number_exit
num_max_robot = (number_target * 20) / 100
while num_max_robot > 0:
num_robot = np.random.randint(1,int(num_max_robot))
if num_robot > number_target:
number_list.append(number_target)
else:
number_list.append(num_robot)
number_target = number_target - number_target
return number_list
def fun_price_buy():
return np.random.randint(50000,300000)
def fun_mx_buy():
return np.random.randint(50, 150)
lista_number_list = []
lista_price_buy = []
lista_mx_buy = []
# This loop append each function 50 times to a new list
while len(lista_price_buy) <= 50:
number_exit = fun_mx_buy()
price_buy = fun_price_buy()
vr_list = num_var_list(number_exit)
lista_number_list.append(vr_list)
lista_price_buy.append(price_buy )
lista_mx_buy.append(number_exit )

why do you have so much global ?
def num_var_list():
number_exit=fun_mx_buy()
number_list = []
number_target = number_exit
num_max_robot = (number_target * 20) / 100
while num_max_robot > 0:
num_robot = np.random.randint(1, int(num_max_robot))
if num_robot > number_target:
number_list.append(number_target)
else:
number_list.append(num_robot)
number_target = number_target - number_target
return number_list
is it works for you?

It looks like you are defining variables via globals inside a function. You'll want to convert your price_buy and number_exit to local variables.
or:
# This function generates a random number between a certain range
def fun_price_buy():
return np.random.randint(50000,300000)
# This function generates a random number between a certain range
def fun_mx_buy():
return np.random.randint(50, 150)

If you still want to use global variables (as other answers pointed, not a recommended approach), you will have to give them a value before using them:
number_exit = 0
# This function generates a list of numbers under certain rules
def num_var_list():
global number_list, number_exit, number_target
number_list = []
You can instantiate number_exit in the scope of the function as well, but you need to do so before actually using it.
# This function generates a list of numbers under certain rules
def num_var_list():
global number_list, number_exit, number_target
number_list = []
number_exit = 0

You haven't defined those global variables. Typing global whatever doesn't automatically define a variable called whatever. It just tells the interpreter that there's an existing variable called whatever in global scope.
For example, the following code produces no errors:
blah = 'yada'
def foo(bar):
global blah
print(blah, bar)
foo('test') # output: yada test
Whereas in this example, if the global variable isn't defined beforehand (I commented it out), it gets the same error as you:
#blah = 'yada'
def foo(bar):
global blah
print(blah, bar)
foo('test') # output: NameError: name 'blah' is not defined
So, to stop getting the error, you have to give your global variables some value beforehand, like None. Although you could be avoiding globals altogether if you used a class to hold those values you need, like this:
import numpy as np
class MyClass(object):
def __init__(self):
#you'll have to set the numerical values to something that causes num_var_list to not loop infinitely
self.number_list = None
self.number_exit = 0
self.number_target = 0
self.price_buy = 0
# This function generates a list of numbers under certain rules
def num_var_list(self):
self.number_list = []
self.number_target = self.number_exit
num_max_robot = (self.number_target * 20) / 100
while num_max_robot > 0:
num_robot = np.random.randint(1,int(num_max_robot))
if num_robot > self.number_target:
self.number_list.append(self.number_target)
else:
self.number_list.append(num_robot)
self.number_target = self.number_target - self.number_target
return self.number_list
# This function generates a random number between a certain range
def fun_price_buy(self):
self.price_buy = np.random.randint(50000,300000)
return self.price_buy
# This function generates a random number between a certain range
def fun_mx_buy(self):
self.number_exit = np.random.randint(50, 150)
return self.number_exit
def main():
lista_number_list = []
lista_price_buy = []
lista_mx_buy = []
my_class_instance = MyClass()
# This loop append each function 50 times to a new list
while len(lista_price_buy) <= 50:
lista_number_list.append(my_class_instance.num_var_list())
lista_price_buy.append(my_class_instance.fun_price_buy())
lista_mx_buy.append(my_class_instance.fun_mx_buy())
if __name__ == '__main__':
main()

Related

Python class scope lost in nested recursion function

When I attempted to write a recursive nested function within a python class, every time the recursive function completed and returned back to the first function my class property reverted back to the original state.
def main():
input = [
[1,3,1],
[1,5,1],
[4,2,1]
]
sln = Solution()
sln.findPath(input)
print("Output: " + str(sln.minPathSum))
print(*sln.minPath, sep = "->")
class Solution():
minPath = []
minPathSum = None
grid = []
def findPath(self, grid):
self.minPath = []
self.minPathSum = None
self.grid = grid
self.recurse(0,0,[])
def recurse(self, xCoord, yCoord, currentPath):
if(len(self.grid) <= yCoord):
return
if(len(self.grid[yCoord]) <= xCoord):
return
currentValue = self.grid[yCoord][xCoord]
currentPath.append(currentValue)
if(len(self.grid) - 1 == yCoord and len(self.grid[yCoord]) - 1 == xCoord):
currentPathSum = sum(currentPath)
if(self.minPathSum == None or currentPathSum < self.minPathSum):
self.minPathSum = currentPathSum
self.minPath = currentPath
else:
#right
self.recurse(xCoord + 1, yCoord, currentPath)
#down
self.recurse(xCoord, yCoord + 1, currentPath)
currentPath.pop()
return
if __name__ == "__main__":
main()
Running this results in:
Output: 7
Debugging the code within VSCode does indicate that self.minPath is getting set within the recurse function; however, it appears to be losing scope to the original class instance.
In addition I attempted to recreate the same nested situation with separate code and ended up with the following.
def main():
tst = ScopeTest()
tst.run()
print(*tst.tstArray)
print(tst.tstNumber)
class ScopeTest():
tstArray = []
tstNumber = 0
def run(self):
self.otherFunc()
def otherFunc(self):
self.tstArray = [1,2,3,4,5]
self.tstNumber = 7
if __name__ == "__main__":
main()
The above did return the expected outcome which leads me to think this has something to do with the recursion.
Just a heads up, I'm fairly new to python so I may be making a rookie mistake, but I can't seem to figure out why this is happening.
Your recurse() method is generating a currentPath parameter and when this is deemed to be correct you execute: self.minPath = currentPath. Unfortunately, you just reference the same object as currentPath which is later mutated.
Your line should be: self.minPath = currentPath[:]
You then see some contents in self.minPath
Mandatory link to Ned Batchelder
Also you can remove these lines:
minPath = []
minPathSum = None
grid = []
from just below class Solution():

Can't get variables from a function inside a class (python)

i'm stuck with this problem, i can't read the variables bpm and spo2 from the function run_sensor (i need these two variables in another script). If someone can help me, thanks.
class HeartRateMonitor(object):
LOOP_TIME = 0.10
def __init__(self, print_raw=False, print_result=False):
self.bpm = 0
if print_raw is True:
print('IR, Red')
self.print_raw = print_raw
self.print_result = print_result
def run_sensor(self):
sensor = MAX30102()
ir_data = []
red_data = []
bpms = []
# run until told to stop
while not self._thread.stopped:
# check if any data is available
num_bytes = sensor.get_data_present()
if num_bytes > 0:
# grab all the data and stash it into arrays
if len(ir_data) == 100:
bpm, valid_bpm, spo2, valid_spo2 = hrcalc.calc_hr_and_spo2(ir_data, red_data) # <-------------- here
if valid_bpm:
bpms.append(bpm)
while len(bpms) > 4:
bpms.pop(0)
self.bpm = np.mean(bpms)
if (np.mean(ir_data) < 50000 and np.mean(red_data) < 50000):
self.bpm = 0
if self.print_result:
print("Finger not detected")
if self.print_result:
print("BPM: {0}, SpO2: {1}".format(round(self.bpm), round(spo2)))
You need to use Global keyword for this issue. Write this -
global bpm
global spo2
under the function you need to use the variables in
You can't access class variables from another function. However, if you were to create an instance of the HeartRateMonitor class, then you can import it and get its bpm and spo2.
instance = HeartRateMonitor()
Then, in your other script:
from heartratemonitor.py import instance
instance.run_sensor() # I assume this is what you want to do
print(instance.bpm)
print(instance.spo2)

Why does this list return an Int rather than an object?

Tcard.attack(self.players[self.opponent])
AttributeError: 'int' object has no attribute 'attack'
This is the error I get from calling attack().
Tcard = self.players[self.turn].returnCard()
Tcard.attack(self.players[self.opponent])
For some odd reason when Tcard.attack() calls with the parameters self.players[self.opponent], the list returns an int ranther than a Player object. Can someone please explain why it is returning an int rather than an object?
Here is the code for the whole file:
class Game():
def __init__(self):
self.players = []
self.turn = 0
self.opponent = 1
def prepare_game(self):
AI_1 = AI("AI_1", 1000)
AI_1.generate_inventory()
AI_2 = AI("AI_2", 1000)
AI_2.generate_inventory()
self.players.append(AI_1)
self.players.append(AI_2)
def start(self):
p1 = self.players[self.turn]
p2 = self.players[self.opponent]
Tcard = self.players[self.turn].returnCard()
print "Battle time"
print "%s attacked %s" % (p1.Name, p2.Name)
Tcard.attack(self.players[self.opponent])
#switch
if self.turn == 0:
self.turn = 1
self.opponent = 0
self.start()
else:
self.turn = 0
self.opponent = 1
self.start()
Here is where the function returnCard is at:
class AI():
def __init__(self, Name, Health):
self.Name = Name
self.Health = Health
self.inventory = []
def generate_inventory(self):
#Generate 6 Cards and 3 Power-ups
#rand_powerups = random.randint(min(len(powerup)), max(len(powerup)))
rand_cards = random.randint(0, 4)
#self.inventory.append(rand_powerups)
while len(self.inventory) != 4:
self.inventory.append(rand_cards)
if len(self.inventory) == 4:
break
def returnCard(self):
return self.inventory[random.randrange(0, 4)]
def returnCard(self):
return self.inventory[random.randrange(0, 4)]
returnCard returns a random item of self.inventory.
And self.inventory is filled by generate_inventory which does this:
# generate a random *INT*
rand_cards = random.randint(0, 4)
while len(self.inventory) != 4:
# append that *INT*
self.inventory.append(rand_cards)
# (note that this keeps adding the same number over and over)
So, of course, returnCard will return an int here:
Tcard = self.players[self.turn].returnCard()
So when you try to call attack you try to call it on an int:
Tcard.attack(self.players[self.opponent])
self.inventory = [] # a list
rand_cards = random.randint(0, 4)
self.inventory.append(rand_cards) # you add ints to the list
# you return an int
return self.inventory[random.randrange(0, 4)]
# you set Tcard equal to an int returned from ^^
Tcard = self.players[self.turn].returnCard()
On another note you should use range to add the random ints and keep calling randint or you will just get the same number added to your list:
def generate_inventory(self):
for _ in range(4):
self.inventory.append(random.randint(0, 4))
If you want to use the methods in your class, create an instance. I could give you an example but I have no idea where attack comes from.
First of all, Tcard becomes a variable due to this line:
Tcard = self.players[self.turn].returnCard()
By assigning Tcard the result of .returnCard() which will always be an integer since you made returnCard() to return an integer with:
return self.inventory[random.randrange(0, 4)]
So since an integer can't have any attributes, that will be an error. Thus the raised error saying that an int has no attribute.
Second, Tcard is not even a function. Only functions can have attributes thus adding more to the error. You need to create a function for Tcard to be able to work. Add something like:
class Tcard:
def attack():
#Do something

Changing the order of creation of instances is changing their behaviour Python

I have a class which takes a array and calculates an answer. The Class is as follows :
class Delish:
ing = []
rmax = []
rmin = []
lmax = []
lmin = []
answer = 0
def rightmax(self):
# sets rmax
def rightmin(self):
# sets rmin
def leftmax(self):
# sets lmax
def leftmin(self):
# sets lmin
def calculate(self):
#calulates answer
def __init__(self,array):
self.ing = list(array)
self.rightmax()
self.rightmin()
self.leftmax()
self.leftmin()
self.calculate()
Now this gives output 4 13 (which is correct)
b = Delish([1,1,-1,-1])
a = Delish([1,2,3,4,5])
print a.answer,b.answer
And this gives output 7 13 (which is wrong)
a = Delish([1,2,3,4,5])
b = Delish([1,1,-1,-1])
print a.answer,b.answer
I cannot put the full code as it is a part of a live programming contest. But I want to know what is causing this weird behaviour. All of the methods are working on self. variables only. Therefore all the objects should be independent from each other right?
I can add details if it doesn't gives much of the algorithm away. Thank you.
In Python, declare instance variables within the constructor
What you're actually doing is declaring class variables. If you want instance variables in Python, you will need to declare them them in your constructor:
class Delish:
# This is a class variable.
# All instances can refer to this as self.foo
foo = 42
def __init__(self,array):
self.ing = [] # This is an instance variable
self.rmax = []
self.rmin = []
self.lmax = []
self.lmin = []
self.answer = 0
self.ing = list(array)
self.rightmax()
self.rightmin()
self.leftmax()
self.leftmin()
self.calculate()
You are probably a C++/Java programmer.
All your fields, except for ing which is assigned and thus overwritten in __init__, are class fields, that is, they are shared between all the instances of yor class. Move your instance initialisation to __init__:
class Delish:
# Nothing here
def __init__(self, array):
self.ing = list(array)
rmax = []
rmin = []
lmax = []
lmin = []
answer = 0
self.rightmax()
self.rightmin()
self.leftmax()
self.leftmin()
self.calculate()

how to append item to a global list from within a procedure

I get a syntax error when i do this:
p = []
def proc(n):
for i in range(0,n):
C = i
global p.append(C)
Just change it to the following:
def proc(n):
for i in range(0,n):
C = i
p.append(C)
The global statement can only be used at the very top of a function, and it is only necessary when you are assigning to the global variable. If you are just modifying a mutable object it does not need to be used.
Here is an example of the correct usage:
n = 0
def set_n(i):
global n
n = i
Without the global statement in the above function this would just create a local variable in the function instead of modifying the value of the global variable.
The problem is you are trying to print list directly instead convert into a string before printing,and as array is a member of class Student, you need to reference it using 'self'.
The following code works:
class Student:
array = []
def addstudent(self,studentName):
print("New Student is added "+studentName)
self.array.append(studentName)
print(str(self.array))
def removeStudent(self,studentName):
print("Before Removing the Students from the list are "+ str(self.array))
self.array.remove(studentName)
print("After Removing the students from the list are "+ str(self.array))
if __name__ == '__main__':
studata = Student()
studata.addstudent("Yogeeswar")
studata.addstudent("Linga Amara")
studata.addstudent("Mahanti")
studata.removeStudent("Yogeeswar")

Categories