This question already has answers here:
Short description of the scoping rules?
(9 answers)
Closed 6 years ago.
I am working through an example Python script from the book "Doing Math with Python" and I keep running up against a NameError which tells me my variable isn't defined, when, it looks to me like it is defined.
I'm using Python 3.4 and the code is
'''
Gravitational Calculations
'''
import matplotlib.pyplot as plt
#Draw the graph
def draw_graph(x,y):
plt.plot(x,y,marker='o')
plt.xlabel('Distance (m)')
plt.ylabel('Force (N)')
plt.title("Gravitational force as a function of distance")
def generate_F_r():
#Generate values for r
r=range(100,1001,50)
#Empty list to store F values
F=[]
#G Constant
G=6.674*(10**-11)
#Two masses
m1=0.5
m2=1.5
#Calculate F and append it into the F-list
for dist in r:
force=G*m1*m2/(dist**2)
F.append(force)
#Call the Draw Plot Function
draw_graph(r,F)
if __name__=='__main__':
generate_F_r()
The error it gives me is:
NameError name 'r' is not defined
Isn't it defined in the line that states r=range(100,1001,50)?
Why isn't it taking this as a definition?
I'm sure there is something glaringly simple and incredibly stupid I'm doing but I am at my wits end as to how such a simple thing could be so hard.
Thanks!
Code in functions is not executed until the function is called. You don't call generate_Fr() until after you have already tried to reference r. Even if you did call the function first, though, r is still just a local variable. You need to make it global with global r at the beginning of the function.
Related
This question already has answers here:
How to link multiple scripts?
(3 answers)
Closed 2 years ago.
I'm supposed to write a vending machine program, divided into three scripts (machine-user interaction, purchases and stocks).
I'm trying to create a variable stocklist in the stock file, so that I can call it for functions in the machine script.
machine script:
if stockchoice == 1:
import stock
stock.stocklist
stock.stockchoice1(stocklist)
stock script:
stocklist = []
def stockchoice1(lista):
print("Insira o compartimento, quantidade, produto e valor:")
stock1 = input()
lista += stock1
print(lista)
I'm getting the error name 'stocklist' is not defined.
How can I use the variable / functions across the different scripts?
stocklist as a standalone name is in fact undefined. You need to refer to it as an attribute of its module:
stock.stockchoice1(stock.stocklist)
Or, depending on your goal, you might prefer to define it as a standalone name, like this:
stocklist = stock.stocklist
stock.stockchoice1(stocklist)
or
from stock import stocklist
stock.stockchoice1(stocklist)
This question already has an answer here:
Python - AttributeError: 'int' object has no attribute 'randint'
(1 answer)
Closed 5 years ago.
I am a beginner Python user. I was wondering why I am unable to use two randint() functions. I've done a little research on the issue, and it seems as though "I can only have one random module active at any time". Is there any way to get around this so I can have two "random values"?
Also, this is my first question ever, so criticism towards the question, sample code and answer are all welcome.
import random
random = random.randint(1, 5)
random_2 = random.randint(7, 11)
print(random)
print(random_2)
What's happening is that Python is confusing random (the number) with random (the module). Also, don't name the file random.py because it's going to search the module in the local directory, first.
And it's not a bug.
I'm doing simulations for scientific computing, and I'm almost always going to want to be in the interactive interpreter to poke around at the output of my simulations. I'm trying to write classes to define simulated objects (neural populations) and I'd like to formalize my testing of these classes by calling a script %run test_class_WC.py in ipython. Since the module/file containing the class is changing as I try to debug it/add features, I'm reloading it each time.
./test_class_WC.py:
import WC_class # make sure WC_class exists
reload(WC_class) # make sure it's the most current version
import numpy as np
from WC_class import WC_unit # put the class into my global namespace?
E1 = WC_unit(Iapp=100)
E1.update() # see if it works
print E1.r
So right off the bat I'm using reload to make sure I've got the most current version of the module loaded so I've got the freshest class definition-- I'm sure this is clunky as heck (and maybe more sinister?), but it saves me some trouble from doing %run WC_class.py and having to do a separate call to %run test_WC.py
and ./WC_class:
class WC_unit:
nUnits = 0
def __init__(self,**kwargs):
self.__dict__.update(dict( # a bunch of params
gee = .6, # i need to be able to change
ke=.1,the=.2, # in test_class_WC.py
tau=100.,dt=.1,r=0.,Iapp=1.), **kwargs)
WC_unit.nUnits +=1
def update(self):
def f(x,k=self.ke,th=self.the): # a function i define inside a method
return 1/(1+np.exp(-(x-th)/k)) # using some of those params
x = self.Iapp + self.gee * self.r
self.r += self.dt/self.tau * (-self.r + f(x))
WC_unit basically defines a bunch of default parameters and defines an ODE that updates using basic Euler integration. I expect that test_class_WC sets up a global namespace containing np (and WC_unit, and WC_class)
When I run it, I get the following error:
In [14]: %run test_class_WC.py
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/Users/steeles/Desktop/science/WC_sequence/test_class_WC.py in <module>()
8
9 E1 = WC_unit(Iapp=100)
---> 10 E1.update()
11
12 # if bPlot:
/Users/steeles/Desktop/science/WC_sequence/WC_class.py in update(self)
19 return 1/(1+np.exp(-(x-th)/k))
20 x = self.Iapp + self.gee * self.r
---> 21 self.r += self.dt/self.tau * (-self.r + f(x))
22
23 # #class_method
/Users/steeles/Desktop/science/WC_sequence/WC_class.py in f(x, k, th)
17 def update(self):
18 def f(x,k=self.ke,th=self.the):
---> 19 return 1/(1+np.exp(-(x-th)/k))
20 x = self.Iapp + self.gee * self.r
21 self.r += self.dt/self.tau * (-self.r + f(x))
NameError: global name 'np' is not defined
Now I can get around this by just importing numpy as np in top of the WC_class module, or even by doing from numpy import exp in test_class_WC and change the update() method to contain exp() instead of np.exp()... but I'm not trying to do this because it's easy, I want to learn how all this namespace/module stuff works so I stop being a python idiot. Why is np getting lost in the WC_unit namespace? Is it because I'm dealing with two different files/modules? Does the call to np.exp inside a function have to do with it?
I'm also open to suggestions regarding improving my workflow and file structure, as it seems to be not particularly pythonic. My background is in MATLAB if that helps anyone understand. I'm editing my .py files in SublimeText2. Sorry the code is not very minimal, I've been having a hard time reproducing the problem.
The correct approach is to do an import numpy as np at the top of your sub-module as well. Here's why:
The key thing to note is that in Python, global actually means "shared at a module-level", and the namespaces for each module exist distinct from each other except when a module explicitly imports from another module. An imported module definitely cannot reach out to its 'parent' module's namespace, which is probably a good thing all things considered, otherwise you'll have modules whose behavior depends entirely on the variables defined in the module that imports it.
So when the stack trace says global name 'np' is not defined, it's talking about it at a module level. Python does not let the WC_Class module access objects in its parent module by default.
(As an aside, effbot has a quick note on how to do inter-module globals)
Another key thing to note is that even if you have multiple import numpy as np in various modules of your code, the module actually only gets loaded (i.e. executed) once. Once loaded, modules (being Python objects themselves) can be found in the dictionary sys.modules, and if a module already exists in this dictionary, any import module_to_import statement simply lets the importing module access names in the namespace of module_to_import. So having import numpy as np scattered across multiple modules in your codebase isn't wasteful.
Edit: On deeper digging, effbot has an even deeper (but still pretty quick and simple) exploration of what actually happens in module imports. For deeper exploration of the topic, you may want to check the import system discussion newly added in the Python 3 documentation.
It is normal in Python to import each module that is needed with in each. Don't count on any 'global' imports. In fact there isn't such a thing. With one exception. I discovered in
Do I have to specify import when Python script is being run in Ipython?
that %run -i myscript runs the script in the Ipython interactive namespace. So for quick test scripts this can save a bunch of imports.
I don't see the need for this triple import
import WC_class # make sure WC_class exists
reload(WC_class) # make sure it's the most current version
...
from WC_class import WC_unit
If all you are using from WC_class just use the last line.
This question already has answers here:
UnboundLocalError trying to use a variable (supposed to be global) that is (re)assigned (even after first use)
(14 answers)
Closed 9 years ago.
I need help figuring out why I am getting the following error:
Traceback (most recent call last):
File "prawtest3.py", line 25, in <module>
commentMatcher()
File "prawtest3.py", line 13, in commentMatcher
commentCollection.append(comment)
UnboundLocalError: local variable 'commentCollection' referenced before assignment
This is my code. For background information, I am trying to create a reddit bot that compares a persons comments and then pms a user when the person they are monitoring submits a new comment. If you see a problem with the functionality as well, feel free to share your input. I just need to diagnose my code first to get rid of the syntactical errors before worrying about the semantic ones.
import praw
import time
r = praw.Reddit('PRAW related-question monitor by u/testpurposes v 1.0.')
r.login()
user = r.get_redditor('krumpqueen')
commentCollection = []
commentComparison = []
def commentMatcher():
comments = user.get_comments(limit = 4)
for comment in comments:
commentCollection.append(comment)
time.sleep(60)
comments = user.get_comments(limit = 4)
for comment in comments:
commentComparision.append(comment)
if commentCollection[1] != commentComparision[1]:
r.send_message('krumpqueen', 'just made a new comment', 'go check now')
commentCollection = list(commentComparision)
else:
r.send_message('krumpqueen', 'did not made a new comment', 'sorry')
while(True):
commentMatcher()
Your use of commentCollection makes python (incorrectly1) assume that commentCollection is a local (since you have an assignment to it later and no global statement). When you try to append to the local (which hasn't been created yet) python throws the UnboundLocalError.
1Of course, it's not python making an incorrect assumption, That's how the language is designed to work.
You do commentCollection = list(commentComparision) inside of commentMatcher. Because you've done this, Python concludes you have a local name commentCollection.
Your code fails for the same reason that the code
def foo():
bar.append(3)
bar = []
would fail.
To get commentCollection = list(commentComparision) to a) rebind the global name commentCollection, and b) not make it look like this is a local name at all, add global commentCollection as the first line in the definition of commentMatcher.
In serious code, you wouldn't want to manage your state as globals like this, but rather you'd make an object.
I got an issue which is, in my code,anyone can help will be great.
this is the example code.
from random import *
from numpy import *
r=array([uniform(-R,R),uniform(-R,R),uniform(-R,R)])
def Ft(r):
for i in range(3):
do something here, call r
return something
however I found that in python shell, every time I run function Ft, it gives me different
result.....seems like within the function, in each iterate of the for loop,call r once, it gives random numbers once... but not fix the initial random number when I call the function....how can I fix it?
how about use b=copy(r) then call b in the Ft function?
Thanks
Do you mean that you want the calls to randon.uniform() to return the same sequence of values each time you run the function?
If so, you need to call random.seed() to set the start of the sequence to a fixed value. If you don't, the current system time is used to initialise the random number generator, which is intended to cause it to generate a different sequence every time.
Something like this should work
random.seed(42) # Set the random number generator to a fixed sequence.
r = array([uniform(-R,R), uniform(-R,R), uniform(-R,R)])
I think you mean 'list' instead of 'array', you're trying to use functions when you really don't need to. If I understand you correctly, you want to edit a list of random floats:
import random
r=[random.uniform(-R,R) for x in range(3)]
def ft(r):
for i in range(len(r)):
r[i]=???