I am trying to access a global variable in python inside a function, but it's value is not changing inside the function as apparently it doesn't refer to the global variable but it considers it a new variable.
here as below, I want to change the value of is_new_namespace = Trueinside the functiontest`
This is what I did and it doesn't recognize the variable but considers it as a newly created variable inside the function itself.
And one thing I need again is, can I access this variable is_new_namespaceinside another python file in the same directory? if yes, how?
from BitesizeDecorator import BitesizeDecorator
import execute
import constants
import subprocess
from custom_check_kubectl import does_kubectl_work
class CreateNamesapce(BitesizeDecorator):
def __init__(self, createnamesapce):
super(CreateNamesapce, self).__init__(createnamesapce)
is_new_namespace = False #global variable
def test(self):
super(CreateNamesapce, self).test()
if does_kubectl_work(self) != 0: # works
does_namespace_available = execute.check_if_exists("kubectl get ns | grep -E \'(^|\s)"+constants.NAMESPACE+"($|\s)\'")
if does_namespace_available != "" and len(does_namespace_available) != 0 : #if exists
print(constants.ORANGE+"\n[6] "+ u'\u0021' +constants.NC+" - "+constants.ORANGE+"Namespace \"" + constants.NAMESPACE +"\" already exists...\n" + constants.NC)
print(does_namespace_available)
else:
is_new_namespace = True #function considers this as a newly created variable
namespace_output = execute.subprocess_execute_arr(["kubectl", "create", "namespace", constants.NAMESPACE])
if namespace_output == 0: # returns zero if executed successfully
print(constants.GREEN+"\n[6] " + u'\u2714' +constants.NC+" - "+constants.GREEN+" Namespace " + constants.NAMESPACE + " created successfully..." + constants.NC + "\n")
else:
print(constants.RED+"\n[6] " + u'\u274C' +constants.NC+" - "+constants.RED+"error creating namespace \"" + constants.NAMESPACE + "\""+constants.NC+"\n")
else:
print(constants.RED + constants.ICON_CROSS + " \"Kubectl\" commmands are not working\n" + constants.NC)
Please see my comments on your code below
class CreateNamesapce(BitesizeDecorator):
def __init__(self, createnamesapce):
super(CreateNamesapce, self).__init__(createnamesapce)
# 1. this is a variable in this class, so it only exists in this class
is_new_namespace = False
def test(self):
super(CreateNamesapce, self).test()
# 2. this is treated as a new variable in this function only
is_new_namespace = True
# 3. this would properly reference and update the variable for the entire class,
# because of self (see comment 1.)
self.is_new_namespace = True
Adding is_new_namespace = False ABOVE the class definition means you can use it anywhere in this same file as intended, without needing self.
To reference this variable in other files, you would need to import it from wherever it was first created. For example, if your current code is in a file called file_a.py and you are in a new file called file_b.py you would need
from file_a import is_new_namespace
Now you have the variable that you created in file_a
Also, it is good practice to declare class variables first thing in the class, above def __init__(self)
class CreateNamesapce(BitesizeDecorator):
# declare class variables here
is_new_namespace = False
def __init__(self, createnamesapce):
super(CreateNamesapce, self).__init__(createnamesapce)
Related
Python beginner question here. I'm trying to save and load objects using pickle in a text based game I'm making, and list variables are not loading as expected. This is the code I wrote to test the problem:
import pickle
class my_class(object):
def __init__(self, x):
self.x = x
self.y = [1,2,3]
a = [4,5,6]
b = 8
def save(object1):
print("Game saved")
pickle_out = open("saveobject1","wb")
pickle.dump(object1, pickle_out)
pickle_out.close()
def load():
print("Loading......")
pickle_in = open("saveobject1","rb")
object1 = pickle.load(pickle_in)
return object1
object1 = my_class(10)
print ("object1.x = " + str(object1.x))
print ("object1.y = " + str(object1.y))
print ("object1.a = " + str(object1.a))
print ("object1.b = " + str(object1.b))
print ("\n")
answer = input("Would you like to save (s) or load (l)?: ")
if answer == "s":
save(object1)
object1.x = 20
object1.y[2] = 6
object1.a[2] = 12
object1.b = 16
if answer == "l":
object1 = load()
print ("object1.x = " + str(object1.x))
print ("object1.y = " + str(object1.y))
print ("object1.a = " + str(object1.a))
print ("object1.b = " + str(object1.b))
print ("\n")
List variables within init save and load OK (y in this example) but list variables outside init do not (a in this example). However, non-list variables outside init do save and load. Thanks in advance for advice.
All variables within __init__ are instance variables, and so will be saved. Both the list and non-list variables outside __init__ are class variables, so won't be saved.
However, when you change object1.b that creates the instance variable b instead of setting the class variable, so it will be saved. However, when you modify object1.a, you are not reassigning it, just an element of it, so it is still an (unsaved) class variable.
If you want to save it, make it an instance variable or save the class variables separately.
I have created a simple renaming script but I would like to ask for some advice so that I can refine the coding as well as honing my python scripting. Below is a small portion of code for now...
Though this may not be an issue in my point of view, but other than the two functions I have stated below, I have came to realize that almost all my functions, they contains objects = cmds.ls(selection=True) Though I do not mind retyping over and over again but I do believe there is a better way to rectify this problem.
However, when I tried to make them global before the class function, it is able to run until when I tired to execute one of the functions, it prompts an error saying that global name 'objects' is not defined or 'objects are not defined' etc.
Pertaining to that, any suggestions?
class mainWindow(QDialog):
def __init__(self, parent=None):
super(mainWindow, self).__init__(parent)
self.resize(300,225)
self.initUI()
self.createConnections()
def searchReplace(self):
wordSearch = str(self.searchTxt.text())
wordReplace = str(self.replaceTxt.text())
objCnt = cmds.ls(sl=True, sn=True)
if len(objCnt) == 0:
self.searchTxt.clear()
self.replaceTxt.clear()
cmds.warning('Nothing is selected')
else:
for wordString in sorted(objCnt):
if wordSearch in wordString:
newWordString = wordString.replace(wordSearch, wordReplace)
cmds.rename(wordString, newWordString)
self.searchTxt.clear()
self.replaceTxt.clear()
print '%s' %wordString + " has changed to : " + "%s" %newWordString
def addPrefix(self):
objects = cmds.ls(selection=True)
pfx = str(self.prefixTxt.text())
for item in objects:
if pfx == "":
cmds.warning('No prefix values in the field')
else:
cmds.rename(item, pfx + "_" + item)
self.prefixTxt.clear()
print 'Prefix added: %s_' %pfx
def addSuffix(self):
objects = cmds.ls(selection=True)
sfx = str(self.suffixTxt.text())
for item in objects:
cmds.rename(item, item + "_" + sfx)
self.suffixTxt.clear()
print 'Suffix added: _%s' %sfx
def numPadding(self):
objects = pm.ls(selection=True)
num = self.numTxt.text()
padding = self.paddingTxt.text()
if num != "" and padding !="":
try:
for currentWordStr in objects:
pad = ("%%0%ii" % int(padding)) % int(num)
newWordStr = currentWordStr.rename(currentWordStr.name() + "_" + pad)
except Exception:
self.numTxt.clear()
self.paddingTxt.clear()
cmds.warning('Input numerical values only')
else:
cmds.warning('Entries of Num or Padding are empty')
def selectHierarchy(self):
sel = cmds.ls(selection = True)
selCnt = len(sel)
if int(selCnt) == 0:
cmds.warning('Nothing is selected')
else:
objHierarchy = cmds.listRelatives(ad=True, type='transform', fullPath=True)
cmds.select(sel, objHierarchy)
def clearHierarchy(self):
sel = cmds.ls(selection = True)
selCnt = len(sel)
if int(selCnt) != 0 :
objHierarchy = cmds.select(clear=True)
else:
cmds.warning('Selection is empty. Nothing to be cleared')
All right, I think I understand what you tried, going to take a shot at an answer.
First, take a look at the following posts, should get you up to speed on globals:
Using global variables in a function other than the one that created them (great, succinct summary)
Variable scope outside of classes (example with classes)
So, first off, you don't need to use the global keyword when first declaring objects outside of the class definition. So, instead of:
global objects
objects = cmds.ls(selection=True)
class mainWindow(QDialog):
...
You would do:
objects = cmds.ls(selection=True)
class mainWindow(QDialog):
...
Then, your functions can just refer to "objects". If you need to WRITE to objects from within your functions in the class, then you need to first use the global keyword (this code assumes objects was defined before the class):
def my_method(self):
global objects
objects = some_function()
That said, I'm not 100% sure how the above code is being invoked, so it's possible that something else is causing "objects" to be undefined.
You might be better served with a class attribute here. You could do this:
class mainWindow(QDialog):
objects = cmds.ls(selection=True)
def my_func(self):
for item in self.objects:
do_stuff()
Keep in mind that objects would be the same for all instances of mainWindow, and any updates to objects in one instance will affect all other instances. That should be fine from what I can tell, but you should definitely become familiar with instance vs. class vs. module.
Hope that helps!
UPDATE: Whoops, changed the class attribute in one place, but not the other in the last example. Updated the example, it should make way more sense now.
This is my class:
class variable(object):
def __init__(self, name, name_alias, parents,values,table):
#name of the variable
self.name = ""
This is the function with problems:
f is a .txt file (opened in main function),
def read_problem(f):
list_of_variables=[]
entry=0;
for line in f:
words = line.split()
#enters only if it's not a comment
if (words[0]!='#'):
if (words[0]=="VAR"):
x=variable;
elif (words[0]=="name"):
x.name=words[1]
list_of_variables.append(x)
for i in range(len(list_of_variables)):
print(list_of_variables[i].name)
return
My .txt file is:
VAR
name MaryCalls
VAR
name JohnCalls
VAR
name Burglary
VAR
name Earthquake
VAR
name Alarm
What I get in that print(and thus, the list) is:
Alarm
Alarm
Alarm
Alarm
Alarm
But I wanted to have:
MaryCalls
JohnCalls
Burglary
Earthquake
Alarm
What's wrong? Why are all the previous entries of the list changing?
The line x=variable makes the x refer to the class variable. You never create any instances of that class, instead you repeatedly modify a class-level variable name.
At the end of the program, when you print, variable.name of course has the last value assigned to it, in this case 'Alarm'.
You'll see this if you do print(list_of_variables):
[<class '__main__.variable'>, <class '__main__.variable'>,
etc.
Change x = variable to x = variable(), and you'll see (for example):
[<__main__.variable object at 0x6ffffee65d0>, <__main__.variable object at 0x6ffffee6610>
etc.
1) If you want to initialize the name in the constructor of variable, you have to indent the assignment further.
def __init__(self, name, name_alias, parents,values,table):
#name of the variable
self.name = ""
2) Your main problem is, that you want to create a new instance of variable with this line:
x=variable;
You have to write:
x = variable();
The primary problem is when the code detects a line starting with "VAR" it assigns the class variable to x, not an instance of the class. To do that you need to call the class which ends up invoking the class' __init__() method if it has one. Yours does, but it expects 5 arguments, none of which are known at that time of creation.
The easiest thing to do in such a case is to assign each argument a default value that means "doesn't have a value yet", and assign those to the instance being created (self).
Here's what I mean:
class Variable(object):
def __init__(self, name="", name_alias="", parents=None, values=None,
table=None):
self.name = name
self.name_alias = name_alias
self.parents = parents
self.values = values
self.table = table
def read_problem(f):
list_of_Variables=[]
for line in f:
words = line.split()
# if not a comment
if words[0] != '#':
if words[0] == "VAR":
x = Variable() # construct empty Variable
elif words[0] == "name":
x.name = words[1]
list_of_Variables.append(x)
for var in list_of_Variables:
print(var.name)
return
def main():
filename = 'variables.txt'
with open(filename) as f:
read_problem(f)
main()
This question already has answers here:
Using global variables in a function
(25 answers)
Closed 3 years ago.
I am trying to change a variable further down the program. I have a global variable declared at the start of the program and I want to change the variable in different functions down the program. I can do this by declaring the variable inside the function again but I would like to know is there a better way of doing this. Some test code is below to explain what I mean.
ID = 'No'
project = ("Yep"+ID) # ID added with 'No' value which I later want to change
def pro():
ID = "YES"
print ID
def pro1(ID):
# I could declare project again to get this to work, but I would like to avoid this
print project # I want this to print with the new ID number.
if __name__ == '__main__':
pro()
pro1(ID)
Has anyone any ideas, thanks
I have tried the global variable but when I do this the project variable still prints out YepNo instead of YepYES. I want the new variable from the function proto change the variable in the project variable.
To update global variables you could use
global ID
ID="Yes"
before assigning variable to ID = "YES"
But changing ID will be no effect on project variable, project = ("Yep"+ID), because project is already a string
you need to make a function like
def getprojectname(ID):
return project+ID
The whole program may be like this
UPDATE:
... removed
Beware, you're doing it wrong multiple times.
Even though you could use the global statement to change a global (it is discouraged since it's better to use function parameters and return values), that would NOT change other already assigned values. E.g. even though you reassign ID, you would NOT reassign project. Also: your functions return nothing, there's no point in assigning a name to their return value, and it's a BAD habit using an all-uppercase name (ID) for a variable since it's a convention to use them for constants.
This should clarify you the way global works:
myid = ''
project = ("Yep"+myid) #ID added with no value which I later want to change
def mutate_id():
global myid
myid = "YES"
def mutate_project():
global project
project = ("YEP" + myid)
if __name__ == '__main__':
print "myid", myid
print "project ", project
print
mutate_id()
print "myid", myid
print "project ", project
print
mutate_project()
print "myid", myid
print "project ", project
print
But the best way is to do WITHOUT globals:
def get_new_id(old):
return "YES"
def get_new_project(old):
return ("YEP" + myid)
if __name__ == '__main__':
myid = ''
project = ("Yep"+myid)
print "myid", myid
print "project ", project
print
myid = get_new_id(myid)
print "myid", myid
print "project ", project
print
project = get_new_project(project)
print "myid", myid
print "project ", project
print
This will make all code interaction clear, and prevent issues related to global state change.
Use the global statement.
The global statement is a declaration which holds for the entire current code block. It means that the listed identifiers are to be interpreted as globals.
Example: http://www.rexx.com/~dkuhlman/python_101/python_101.html#SECTION004340000000000000000
P.S.
But don't use global too often, see http://www.youtube.com/watch?v=E_kZDvwofHY#t=10m45
In your code you have two problems. The first about changing ID variable, which could be solved by using global.
The second that your code calculate project string and after that project don't know about ID.
To avoid code duplication you can define function to calc project.
So we have:
ID = 'No'
def GetProject():
return "Yep"+ID
def pro():
global ID
ID = "YES"
print ID
print GetProject()
pro()
print GetProject()
You can mutate without reassigning:
variables = {}
def pro():
if variables['ID'] == '':
variables['ID'] = 'default'
Why not use a dictionary?
>>> attr = {'start':'XXX', 'myid':'No'}
>>>
>>> def update_and_show(D, value = None):
... if value: D['myid'] = value
... print D['start'] + ' ' + D['myid']
...
>>> update_and_show(attr)
XXX No
>>> update_and_show(attr, 'Yes')
XXX Yes
>>> update_and_show(attr, 'No')
XXX No
>>>
I built (just for fun) 3 classes to help me log some events in my work.
here are them:
class logMessage:
def __init__(self,objectName,message,messageType):
self.objectName = objectName
self.message = message
self.messageType = messageType
self.dateTime = datetime.datetime.now()
def __str__(self):
return str(self.dateTime) + "\nObjeto de valor " + str(self.objectName) + " gerou uma mensagem do tipo: " + self.messageType + "\n" + self.message + "\n"
class logHandler():
def __init__(self):
self.messages = []
def __getitem__(self,index):
return self.messages[index]
def __len__(self):
return len(self.messages)
def __str__(self):
colecaoString = ""
for x in self.messages:
colecaoString += str(x) + "\n"
return colecaoString
def dumpItem(self,index):
temp = self.messages[index]
del self.messages[index]
return str(temp)
def append(self,log):
if isinstance(log,logMessage.logMessage):
self.messages.append(log)
else:
self.newLogMessage(log, "Wrong object type. Not a log message. Impossible to log.","Error")
def newLogMessage(self,objectInstance,message,messageType):
newMessage = logMessage.logMessage(objectInstance,message,messageType)
self.append(newMessage)
Here is my question:
Imagine i have other classes, such as Employee, and i want to log an event that happened INSIDE that class.
How can i do that without always passing a logHandler instance to every other class i want to log? My idea would be to pass a logHandler to every init function, and then use it inside it.
How can that be done, without doing what i specified?
How would it work with global logHandler? Is there a way to discover in runtime if there is a logHandler instance in the program, and use it to create the messages?
Thanks
Just create an instance of your classes in the module you posted. Then just import your logging module in every file you want to log from and do something like this:
yourloggingmodule.handler.newLogMessage(...)
Where handler is the name of the instance you created.
You could use the Borg pattern, meaning you can create local instances of your logger object and yet have them access the same state. Some would say that is elegant, others may say it's confusing. You decide. :)