Initialize variables when they're not already declared in python - python

I'm trying to use a simple try statement and a for loop statement to initialize a list of variables that were not defined previously.
Here's the code I wrote:
for i in ['var1', 'var2', 'var3']:
try:
i
except NameError:
i = []
It doesn't work as I expect it to. After running it, I want to have var1 = [], var2=[] and var3=[] if these variables haven't been defined previously.
Here' a little more detail on what I'm trying to accomplish. A scheduled task is supposed to run every 60 seconds and I want to keep track of progress:
def run_schduled():
for i in ['var1', 'var2', 'var3']:
try:
i
except NameError:
i = []
var1.append(random.randint(0,100))
var2.append(random.randint(0,100))
var3.append(random.randint(0,100))
schedule.every(60).seconds.do(run_schduled)
while True:
schedule.run_pending()
time.sleep(30)

One solution is to use a defaultdict:
from collections import defaultdict
my_dict = defaultdict(lambda: [])
my_dict['var1'].append(1)
print(my_dict['var1']) # prints '[1]'
This would not allow you to simply do print(var1), however, because it would still be undefined in your local (or global) namespace as a tagged value. It would only exist in the defaultdict instance as key.
Another option would be to use a class:
class TaskRunner:
def __init__(self, var1=None, var2=None, var3=None):
self.var1 = var1 or []
self.var2 = var2 or []
self.var3 = var3 or []
def run_scheduled(self):
for i in [self.var1, self.var2, self.var3]:
i.append(random.randrange(1, 10000000))
runner = TaskRunner()
schedule.every(60).seconds.do(runner.run_scheduled)
You can also use pickle to save instances to load later (i.e., in subsequent runs of your job).

Try globals:
In [82]: for i in ['var1', 'var2', 'var3']:
...: if i in globals():
...: print(f'{i} already present in the global namespace')
...: else:
...: globals()[i] = []
...:
In [83]: var1
Out[83]: []

Related

New to using functions in Python

I am trying to understand why newNameList is not defined:
ListofNames1 = ['Mark', 'Andrew']
ListofNames2 = ['Anjela', 'Lora']
names = ListofNames1
def greeting(names):
newNameList = []
for item in names:
newNameList.append(str(names))
return (names)
print(greeting(names))
def function2(newNameList):
for each in newNameList:
newNameList2.append(newNameList.upper())
return (newNameList2)
print(function2(newNameList))
The output
['Mark', 'Andrew']
...
NameError: name 'newNameList' is not defined.
The name error occurs on the last line in the code.
newNameList is only defined within the scope of function2. Since the print statement is not indented at the same level of function2 then newNameList is not visible to it. The three variables defined at a top-level scope are ListofNames1, ListofNames1, and names. These are the only three variables that can be passed to function2 in the print statement.
Yes, You can do it.
For example:
def use_greeting_function(name):
new_list_name = greeting(name)
Now new_list_name has the output of greeting function and you can use it in the function afterwards.
NameError: name 'newNameList' is not defined.
tells you what's wrong. You should have defined newNameList outside the greetings() function.
I have rewritten your code:
ListofNames1 = ['Mark', 'Andrew']
ListofNames2 = ['Anjela', 'Lora']
names = ListofNames1
newNameList = []
def greeting(names):
for item in names:
newNameList.append(names)
return names
print(greeting(names))
def function2(newNameList):
newNameList2 = []
for each in newNameList:
newNameList2.append(str(newNameList).upper())
return newNameList2
print(function2(newNameList))
And using the upper() method on a list doesn't work. Convert it to str first.

Global variable producing nothing in python

I have a program that has a global dictionary, "d", and I can print it out fine in a function but when I add or remove a value from it nothing happens.
d = {}
def main():
global d
# ADD SCORES
leadFile = open("leaderboard.txt","r")
leads = []
lead = leadFile.readline()
while lead != "":
leads.append(lead)
lead = leadFile.readline()
leadFile.close()
for lead in leads:
fields = lead.split(",")
d[fields[0]] = fields[1]
print(d)
main()
This works:
leaderboard.txt:
a,10
b,20
c,30
d,40
e,50
running your code:
$ python test.py
{'a': '10\n', 'b': '20\n', 'c': '30\n', 'd': '40\n', 'e': '50\n'}
test.py contains a copy/paste of your posted code. There are definitely some areas for improvement in the code, but this was taken as posted.
For what it's worth, you could simplify the code like this:
d = {}
def main():
global d
d.update(dict(item.split(',') for item in open('leaderboard.txt', 'r')))
print(d)
main()
If you don't have a very specific need to use the global variable, it's usually considered cleaner to pass objects as function parameters:
d = {}
def main(my_dict):
my_dict.update(dict(item.split(',') for item in open('leaderboard.txt', 'r')))
print(my_dict)
main(d)
I'd like to present an alternative to the "simplified" code in the other answer.
d = {}
def main():
with open("leaderboard.txt", "r") as leader_file:
d.update(dict(line.strip().split(',') for line in leader_file))
print(d)
main()
print(d)
As you can see you don't need global. As a bonus this code strips the line ends from the data.
Nevertheless I wouldn't use a global variable here but use a parameter if you want to use an existing dictionary.
d = {}
def main(data):
with open("leaderboard.txt", "r") as leader_file:
data.update(dict(line.strip().split(',') for line in leader_file))
main(d)

How do you initialize a global variable only when its not defined?

I have a global dictionary variable that will be used in a function that gets called multiple times. I don't have control of when the function is called, or a scope outside of the function I'm writing. I need to initialize the variable only if its not initialized. Once initialized, I will add values to it.
global dict
if dict is None:
dict = {}
dict[lldb.thread.GetThreadID()] = dict[lldb.thread.GetThreadID()] + 1
Unfortunately, I get
NameError: global name 'dict' is not defined
I understand that I should define the variable, but since this code is called multiple times, by just saying dict = {} I would be RE-defining the variable every time the code is called, unless I can somehow check if it's not defined, and only define it then.
Catching the error:
try:
_ = myDict
except NameError:
global myDict
myDict = {}
IMPORTANT NOTE:
Do NOT use dict or any other built-in type as a variable name.
A more idiomatic way to do this is to set the name ahead of time to a sentinel value and then check against that:
_my_dict = None
...
def increment_thing():
global _my_dict
if _my_dict is None:
_my_dict = {}
thread_id = lldb.thread.GetThreadID()
_my_dict[thread_id] = _my_dict.get(thread_id, 0) + 1
Note, I don't know anything about lldb -- but if it is using python threads, you might be better off using a threading.local:
import threading
# Thread local storage
_tls = threading.local()
def increment_thing():
counter = getattr(_tls, 'counter', 0)
_tls.counter = counter + 1

python mock functions with parameters

I want to mock a function that calls an external function with parameters.
I know how to mock a function, but I can't give parameters. I tried with #patch, side_effects, but no success.
def functionToTest(self, ip):
var1 = self.config.get(self.section, 'externalValue1')
var2 = self.config.get(self.section, 'externalValue2')
var3 = self.config.get(self.section, 'externalValue3')
if var1 == "xxx":
return False
if var2 == "yyy":
return False
[...]
In my test I can do this:
def test_functionToTest(self):
[...]
c.config = Mock()
c.config.get.return_value = 'xxx'
So both var1, var2 and var3 take "xxx" same value, but I don't know how to mock every single instruction and give var1, var2 and var3 values I want
(python version 2.7.3)
Use side_effect to queue up a series of return values.
c.config = Mock()
c.config.get.side_effect = ['xxx', 'yyy', 'zzz']
The first time c.config.get is called, it will return 'xxx'; the second time, 'yyy'; and the third time, 'zzz'. (If it is called a fourth time, it will raise a StopIteration error.)

Global variable's value lost between function calls in python

I know I must have missed something basic -- just want to make sure I get the precise answer.
I have the following code. Why CACHE_KEYS is still None after load() while CACHE is not?
import bisect
import csv
DB_FILE = "GeoLiteCity-Location.csv"
# ['locId', 'country', 'region', 'city', 'postalCode', 'latitude', 'longitude', 'metroCode', 'areaCode']
CACHE = []
CACHE_KEYS = None
def load():
R = csv.reader(open(DB_FILE))
for line in R:
CACHE.append(line)
# sort by city
CACHE.sort(key=lambda x: x[3])
CACHE_KEYS = [x[3] for x in CACHE]
if __name__ == "__main__":
load()
# test
# print get_geo("Ruther Glen")
I think making it global would work. Any variable defined in the global scope which is to be edited should be specified as global in that function. Your code just makes a local variable CACHE_KEYS and stores the information correctly. But, to make sure that it is copied to the global variable, declare the variable as global in the function. You call the append function on CACHE and hence that works fine. Your code after the changes.
import bisect
import csv
DB_FILE = "GeoLiteCity-Location.csv"
# ['locId', 'country', 'region', 'city', 'postalCode', 'latitude', 'longitude', 'metroCode', 'areaCode']
CACHE = []
CACHE_KEYS = None
def load():
R = csv.reader(open(DB_FILE))
for line in R:
CACHE.append(line)
# sort by city
CACHE.sort(key=lambda x: x[3])
global CACHE_KEYS
CACHE_KEYS = [x[3] for x in CACHE]
if __name__ == "__main__":
load()
Anytime you assign a value to a global variable you have to declare it as global. See the following code snippet.
listOne = []
def load():
listOne+=[2]
if __name__=="__main__":
load()
The above code has an assignment and not an append call. This gives the following error.
UnboundLocalError: local variable 'listOne' referenced before assignment
But, executing the following snippet.
listOne = []
def load():
listOne.append(2)
if __name__=="__main__":
load()
gives the following output.
>>> print listOne
[2]
The thing is in
CACHE_KEYS = [x[3] for x in CACHE]
CACHE_KEYS is defined in the global scope. In the above line, you are assigning it a new value, bringing it into the local scope, In order to manipulate the variable in a function (and keep it's value later), global it :
def load():
global CACHE_KEYS
...
CACHE.sort(key=lambda x: x[3])
CACHE_KEYS = [x[3] for x in CACHE]

Categories