I am trying to write a function that reads keywords from a file (in the format that each keyword is on a new line inside the text file)
I want the function to put the keywords into a global set() called "desiredItems".
desiredItems = set()
def populateDesired():
for line in open("desireditems.txt"):
addableLine = line.rstrip("\n")
global desiredItems.add(addableLine)
For some reason my development environment (Pycharm) tells me that desiredItems.add is invalid syntax.
(sorry If I have inserted code snippet incorrectly etc)
Thanks in advance
You don't need to use global at all, just remove it.
If you need to modify the binding of a global variable, the syntax is like this
def populateDesired():
global desiredItems
for line in open("desireditems.txt"):
addableLine = line.rstrip("\n")
desiredItems.add(addableLine)
Since you are not modifying the binding - merely calling a method, there is no need for global here at all
def populateDesired():
for line in open("desireditems.txt"):
addableLine = line.rstrip("\n")
desiredItems.add(addableLine)
Related
I'm a bit confused about a code in the book "Learning Python", p. 539.
As far as I know assignments within a function are only in this local scope. So if I want to change a global one I first have to declare it global. But why does the following code change the builtin.open() to custom completely once called?
import builtins
def makeopen(id):
original = builtins.open
def custom(*pargs, **kargs):
print('Custom open call %r: ' % id, pargs, kargs)
return original(*pargs, **kargs)
builtins.open = custom
If I call makeopen('spam') and a F = open('text.txt') afterwards I get the custom call. So the builtin.open() has been changed in the whole script after the makeopen('spam'). Why?
And if I would make some more makeopen('xx') one builtin.open('text.txt') would print the custom call for every created makeopen. Why?
Comparing this code to
x = 99
def changing():
x = 88
changing()
print(x)
doesnt even help me. Isn't it the same but with an x instead of builtin.open()?
A variable is considered local if you assign to it anywhere in the function, unless you declare it global.
In your first piece of code, you never assign anything to builtins, so it's not considered local. You just change one of its attributes, open.
The rule is respected!
In your second piece of code, you assign something to x in x = 88, so it is considered local.
When you call makeopen, you replace the original, global open with custom. custom, when executed, prints its name and calls the original open.
If you call makeopen a second time, it will create a second, different custom function, and make the name builtins.open refer to it. When you call this function, it will print its name, then call original, which is what builtins.open referred to when it was created - and that is your first custom function, which will print its name and call the original open.
So, successive calls to makeopen create a chain of functions, and calling open will make each of them run and call its predecessor.
I was reading a question in StackOverflow where the user applied the "with" statement twice in a row, pipelining the results from a variable declared inside the first with statement into the second. Like so (simple example):
with open('first_file.txt', 'r') as f:
loaded_file = f.readlines()
#...Prepare a csv file somehow - loaded_file is not declared outside with...
with open("second_file.csv", "w") as f:
for line in loaded_file:
f.write(line+"\n")
Considering variable scopes, why does it work?
Only one statement creates a new scope: the def statement. Any other assignment creates a name that is local to the current function body.
The exceptions are:
A name declared global refers to the (module) global scope rather than the local function body.
A name declared nonlocal refers to the name defined in the closest containing function scope (or global scope if no other name is found)
The Python interpreter itself can define names.
In your example, f is either a local variable or a global, depending on the scope where the with statement occurs. In no way is f local to any other particular statement.
No, "with" statements does not create a new scope.
The "With" statement is a resource developed by the Python Dev team to generalize a common (and heavily recommended) practice of closing opened resources even after an exception ocurred. Imagine the following situation:
try:
f = open('file.txt', 'w')
#Do some processing that can raise exceptions and leave 'f' open, eventually locking the file or having trash data loaded into RAM.
#To avoid this situation, a mindful developer will do the following:
finally:
f.close()
It gets verbose easily.
To solve the problem, python dev team proposed the use of some dunder methods which encapsule this process: __enter__() and __exit__() - these are invoked "under the hood" when you use a "with" statement.
You can even implement them in your own classes!
class controlled_execution:
def __enter__(self):
set things up
return thing
def __exit__(self, type, value, traceback):
tear things down
with controlled_execution() as thing:
some code
In the end, a with statement, even though there's identation, is not a separate block of code. It is just an ellegant try...finaly block. It abstracts a "contained" piece of code.
This can be easily comprehended by looking at a try...except statement with variables declared inside the try:
x = 10
try:
y = load_using_failable_function()
z = 5
except FunctionFailureException:
y = 10
#If you treat it properly, there's nothing wrong with doing:
x = x + y + z
I hope it is clear to anyone else looking for this reason.
Consulted websites:
https://www.geeksforgeeks.org/with-statement-in-python/
https://effbot.org/zone/python-with-statement.htm
I am unsure of why the variable totalspeed variable is not being passed correctly to the function startgame as the startgame function is called after the gettotalspeed function.
Exerpt from call function:
gettotalspeed(party_ids)
NoOfEvents=0
startgame(party_ids,totalspeed,distance,NoOfEvents)
Functions
def gettotalspeed(party_ids):
#Get selected party members IDS
print(party_ids)
#Obtain Speeds
ids_string = ','.join(str(id) for id in party_ids)
mycursor.execute("SELECT startspeed FROM characters WHERE CharID IN ({0})".format(ids_string))
myspeeds=mycursor.fetchall()
totalspeed=0
for speedval in myspeeds:
totalspeed=totalspeed + speedval[0]
print("totalspeed is: ",totalspeed)
return totalspeed
def startgame(party_ids,totalspeed,distance,NoOfEvents):
#Check if game end
print(totalspeed)
while distance!=0:
#Travel...
distance=distance-totalspeed
NoOfEvents=NoOfEvents+1
#Generate Random Encounter
genevent(NoOfEvents)
return NoOfEvents
Error Produced:
NameError: name 'totalspeed' is not defined
Outputs (ignoring party_ids)
totalspeed is: 15
I suspect that your problem is self-evident from the main program:
gettotalspeed(party_ids)
NoOfEvents=0
startgame(party_ids,totalspeed,distance,NoOfEvents)
Of the variables you pass to your functions, only NoOfEvents is defined. party_ids, totalspeed, and distance have no definitions.
Work through a tutorial on Python scoping rules. Most of all, note that a function defines a scoping block. Variables inside the function are reclaimed when you leave the function; their names do not apply outside of that block. Your posted program has three independent totalspeed variables.
You forgot to make totalspeed a global variable like global totalspeed in your gettotalspeed() function. You might also be confused about what return does. If you wanted to do it the "proper" way, you could do totalspeed = gettotalspeed(party_ids). Hope this helps!
I am writing a program and keep on getting trouble with the error:
File "C:/Users//Documents///", line 47, in <module>
print(operations(sorted_list_desc))
NameError: name 'sorted_list_desc' is not defined
Even though you can not see the file I am working with, I have provided my code. I am supposed to loop the years and randomly choose an operator for each of the years. However, I keep on getting the error above. Any ideas why I keep on getting it?
import csv
#List to store different operators
list_operators = ["+","-","*","/"]
#Function to read file of list
def read_file():
#List to store data
sorted_list_desc = []
year = csv_file.readline()
population = csv_file.readline()
return sorted_list_desc
print(read_file())
def operations(sorted_list_desc):
for i in range(len(sorted_list_desc)):
operator = random.choice(list_operator)
return operator
print(operations(sorted_list_desc))
##
sorted_list_desc is generated by read_file(). Change your last line to:
print(operations(read_file()))
The line:
print(read_file())
does not magically created a global object withe name sorted_list_desc.
You need to hand it over explicitly to operations().
Alternatively, you could write:
sorted_list_desc = read_file()
print(operations(sorted_list_desc))
You have only assigned sorted_list_desc inside your function read_file(). Thus, your error is telling you that sorted_list_desc is not assigned to anything outside your function's scope. See Python scoping rules, and notice that you don't even need to pass sorted_list_desc as a parameter because it is assigned inside your function anyways.
Looks like sorted_list_desc is defined within the scope of your read_file() function and thus you can't reference it outside of that function. You can call print(operations(sorted_list_desc)) within 'read_file()', or you can define sorted_list_desc = [] at a global scope.
I know this kind of question gets asked all the time but either i've been unable to come across the answer i need, or i've been unable to understand it when i did.
I want to be able to do something like:
spam = StringVar()
spam.set(aValue)
class MyScale(Scale):
def __init__(self,var,*args,**kwargs):
Scale.__init__(self,*args,**kwargs)
self.bind("<ButtonRelease-1>",self.getValue)
self.set(var.get())
def getValue(self,event):
## spam gets changed to the new value set
## by the user manipulating the scale
var.set(self.get)
eggs = MyScale(spam,*args,**kwargs)
eggs.pack()
Of course, i get back "NameError: global name 'var' is not defined."
How do i get around the inability to pass arguments to getValue? I've been warned against using global variables but is that my only option? Is it setting up a separate scale class for each variable i want to change? I get the feeling i'm missing something thats right under my nose...
edit:
is this what you mean?
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python26\lib\lib-tk\Tkinter.py", line 1410, in __call__
return self.func(*args)
File "C:\...\interface.py", line 70, in getValue
var.set(self.get)
NameError: global name 'var' is not defined
Sorry, I've only been programming a month and some of the jargon still escapes me.
Please give this a shot.
Lots of example code out there generously uses globals, like your "var" variable.
I have used your var argument to act as a pointer back to the original spam object; assigned to self.var_pointer within the MyScale class.
The code below will change the value of 'spam' (and 'eggs') on the scale's ButtonRelease.
You can check out the value by typing eggs.get() or spam.get() to see the changed value.
from Tkinter import *
root = Tk()
aValue = "5"
spam = StringVar()
spam.set(aValue)
class MyScale(Scale):
def __init__(self,var,*args,**kwargs):
self.var_pointer = var
Scale.__init__(self,*args,**kwargs)
self.bind("<ButtonRelease-1>",self.getValue)
self.set(var.get())
def getValue(self,event):
## spam gets changed to the new value set
## by the user manipulating the scale
self.var_pointer.set(self.get())
eggs = MyScale(spam)
eggs.pack(anchor=CENTER)
Let's look at this method function
def getValue(self,event):
## spam gets changed to the new value set
## by the user manipulating the scale
var.set(self.get)
The var.set(self.get) line has exactly two local variables available:
self
event
The variable var is not local to this method function. Perhaps it was used elsewhere in the class or script, but it's not local here.
It may, possibly, be global, but that's a bad practice.
I'm not sure why you'd think the variable var would be known in this context.