How to Use Global List in different function in Python? - python-3.x

I have a function: instanceDetails() in which I am trying to use global variables, global lists are declared in just after class definition.
class InstanceDescribe:
#both variables are global
all_instances_health = [0] #stores some ids such as ip-address
all_instances_health_index = [0] #against the IP address stores health of server
#some code goes here
def instanceDetails():
#some code goes here to find value of instance_role, instanceId and much more which is used as argument
if instance_role=='dispatcherpub' or instance_role=='dispatcheraut':
if instanceId in **all_instances_health**: #checking IP address is in global variable list
print("Yes instance in list, so not calling target gp health function")
position = **all_instances_health.index(instanceId)**
instanceDetailsresult_dict["Health Status"] = **all_instances_health_index[position]**
else: #if IP address is not there then calling another function and this function returns values
print("No instance is not in list, so calling target gp health function")
return_list = target_object.target_gp_health(instanceId,autoscaling_group_name,cross_account_cred_list)
instanceDetailsresult_dict["Health Status"] = return_list[0]
**all_instances_health** = return_list[1]
**all_instances_health_index** = return_list[2]
Now, could you please tell me, where I have to use global keyword so that my function starts working.
I have tried so many things but getting error such as:
name 'all_instances_health' is used prior to global declaration
and after some putting global keyword with list name under if and else block, am getting this error also:
name 'all_instances_health' is not defined
NOTE: other functionalities are working properly

Use it at the start of the functions. I tried that and it worked.
def instanceDetails():
global var1
global var2
...

Related

why is a functions parameter not fully the same inside and outside of the function

Why is a variable interpreted differently when inserted into a function?
my_variable = ['list_item1','another_list_item']
var_name = [ i for i, a in locals().items() if a == my_variable][0]
print("The variable name is:", var_name)
def print_and_logging(input):
var_name = [ i for i, a in locals().items() if a == input][0]
print("The variable name is:", var_name)
print_and_logging(my_variable)
#Output
'''
The variable name is: my_variable
The variable name is: input
'''
Let's decompose this.
my_variable is the name by which you refer to an object, specifically an array containing two strings, ['list_item1','another_list_item']
This name exists in the outermost context of your code, the global namespace.
Now, when you are calling the function print_and_logging with the name my_variable as argument, what you are passing to it is not the name, but the object to which the name refers. The object is hence introduced in the context of the function, which forms a local namespace. The name by which the array object is introduced into (and therefore known to) this namespace is input. But that is still the same object.
If you experiment a bit more, you'll find that you can actually use the name my_variable inside your function, but that the name input is unknown outside of the function.
I think you'll find this post informative. Going forward, you might also want to make research on the concept of namespace and look how arguments are passed in python.

Why can't I access a variable that's being returned from a function?

I am new to Python and am at a lost as to what I'm doing wrong. I am trying to use the fqdn variable that is being returned to the caller which is main() but I'm getting NameError: name 'fqdn' is not defined
I'm betting this is some type of global variable statement issue or something like that, but I've been researching this and can't figure it out.
If a function from a module returns a value, and the caller is main(), shouldn't main() be able to use that returned value???
Here's the layout:
asset.py
def import_asset_list():
# Open the file that contains FQDNs
openfile = open(r"FQDN-test.txt")
if openfile.mode == 'r':
# Remove CR from end of each item
fqdn = openfile.read().splitlines()
# Add https to the beginning of every item in list
fqdn = ["https://" + item for item in fqdn]
openfile.close()
return fqdn
tscan.py
def main():
import asset
asset.import_asset_list()
# Iterate through list
for i in fqdn:
if SCHEDULED_SCAN == 1:
create_scheduled_scan(fqdn)
launch_scan(sid)
check_status_scan(uuid)
else:
create_scan(fqdn)
launch_scan(sid)
check_status_scan(uuid)
Short Explanation
Yes, main() should be able to use the returned value, but it's only the value that is returned, not the variable name. You have to define a variable of your own name, to receive the value, and use that instead.
Long Explanation
The name of a variable inside any function is simply a "label" valid only within the scope of this function. A function is an abstraction which means "Give me some input(s), and I will give you some output(s)". Within the function, you need to reference the inputs somehow and, potentially, assign some additional variables to perform whatever it is you would like to. These variable names have no meaning whatsoever outside the function, other than to, at most, convey some information as to the intended use of the function.
When a function returns a value, it does not return the "name" of the variable. Only the value (or the reference in memory) of the variable. You can define your own variable at the point where you call the function, give it your own name and assign to it the returned result of the function, so you simply have to write:
def main():
import asset
my_asset_list = asset.import_asset_list()
# Iterate through list
for i in my_asset_list:
if SCHEDULED_SCAN == 1:
create_scheduled_scan(my_asset_list)
launch_scan(sid)
check_status_scan(uuid)
else:
create_scan(my_asset_list)
launch_scan(sid)
check_status_scan(uuid)
I don't know where the uuid and the sid variables are defined.
To make sure you have understood this properly, remember:
You can have multiple functions in the same file, and use identically-named variables within all those functions, this will be no problem because a variable (with its name) only exists within each specific function scope.
Variable names do not "cross" the boundaries of the scope, only variable values/references and to do this, a special construct is used, i.e. the return [something] statement.

Indirect variable modification not working withing class, but works outside of class (Python 3.7)

Since I get variable definitions from an external text file i need to modify my local variables indirectly.
What I want to do is basically working, but not once I try to implement it within a class.
X = "0"
vars()["X"]+="1"
print(X) #gives "01" as expected
class Test:
def __init__(self):
x = "0"
vars()["x"]+="1"
self.x = x
test = Test()
print(test.x) # gives "0", but why?
While the procedual code snip produces the expected result "01", the code inside the class does not ("0"). Why?
Here is what the manuals says about vars (https://docs.python.org/3/library/functions.html#vars):
Return the dict attribute for a module, class, instance, or any other object with a dict attribute.
Objects such as modules and instances have an updateable dict attribute; however, other objects may have write restrictions on their dict attributes (for example, classes use a types.MappingProxyType to prevent direct dictionary updates).
Without an argument, vars() acts like locals(). Note, the locals dictionary is only useful for reads since updates to the locals dictionary are ignored.
In other words, when writing directly you are at the module level that has a writable __dict__, not so when you are inside a method.
Although this is bad practice and is not recommended, but this can help you get going:
class Test:
def __init__(self):
self.x = '0'
self.__dict__['x']+='1'
test = Test()
print(test.x) # gives "01"
You are mixing a lot of things here. First I will comment on your code:
X = "0"
vars()["X"]+="1"
print(X) #gives "01" as expected
class Test:
def __init__(self):
global X
x = "0" # this is a local variable inside __init__()
vars()["X"]+="1" # vars() only shows local variables, will lead to an key error because vars()['X'] does not exist
self.x = x # assign member variable with value of local variable
test = Test()
print(test.x) # gives "0", because you just assigned self.x = x, which is "0"
You could use the global keyword to make X visible inside init() but this is considered bad practice.
X = "0"
class Test(object):
def __init__(self):
global X
self.x = X + "1"
test = Test()
print(test.x) # gives "01"
You better initalize Test with the variable needed:
X = "0"
class Test(object):
def __init__(self, myvar: str):
self.x = myvar + "1"
test = Test(X)
print(test.x) # gives "01"
The documenation for vars() without an argument says:
Without an argument, vars() acts like locals(). Note, the locals dictionary is only useful for reads since updates to the locals dictionary are ignored.
But that is incomplete. The documentation for locals() says:
Note that at the module level, locals() and globals() are the same dictionary.
And changes to the dictionary returned by globals() are not ignored as it is the actual symbol table:
Return a dictionary representing the current global symbol table. This is always the dictionary of the current module (inside a function or method, this is the module where it is defined, not the module from which it is called).
So by this really strange design, vars() when used at module level actually does return the writeable symbol table -- and anywhere else, it uses a view on which writes are ignored.
None of this really matters, as using these functions is usually a good sign that you're doing something wrong, but still, here it is.

How to use a variable "holding" a string value as list name?

One of the parameter the I want to pass to a Class init is a variable with a string value. this string value is a name of a list. The init should use this string value to append the class object to that list. what I'm doing wrong?
I've tried using the locals() and globals() but it ended with "TypeError: unhashable type: 'list'". tried also vars() with no use as well.
refList = []
cmpList = []
class Part(object):
def __init__(self, origin, name, type, listName):
self.origin = origin
self.name = name
self.type = type
partListName = locals()[listName]
partListName.append(self)
#... some file parsing..
part1 = Part((str(origin), str(name) ,str(type), 'refList')
# ... some other file parsing ...
part2 = Part((str(origin), str(name) ,str(type), 'cmpList')
Welcome to SO Ram! I think you should rethink your code because this is not a good approach to do it always. It is better for example pass directly the list or something related.
However your issue with your code is that you should use the globals() function. I really recommend you see the next post in order to get more knowledge about how/when use this useful functionality of Python3.
Also, you must declarate your variables with global keywoard because you are going to reference this variables from your Part class.
global refList = []
global cmpList = []
Said all this, your critical code line should look like:
partListName = globals()[listName]

NameError when running in `main` module

I am attempting to grab all the .md files recursively within files.To complish it,I define a recursive function which run in a main module.
The code:
import os
def walk(dirname):
for name in os.listdir(dirname):
path = os.path.join(dirname, name)
if os.path.isfile(path):
if '.md' in path:
path_list.append(path)
else:
walk(path)
return path_list
def main():
dir = '/Users/Documents/Diary'
path_list = []
path = walk(dir)
if __name__ == '__main__':
main()
When running, it reports:
NameError: name 'path_list' is not defined
However, if running without of main(), it works:
In [80]: path_list = []
...: def walk(dirname):
...: for name in os.listdir(dirname):
...: path = os.path.join(dirname, name)
...: if os.path.isfile(path):
...: if '.md' in path:
...: path_list.append(path)
...: else:
...: walk(path)
...: return path_list
output:
dir = '/Users/Documents/Diary'
walk(dir)
Out[81]:
['/Users/Documents/Diary/py4.1.If_statements.md',
'/Users/Documents/Diary/pyName_and_object:.md',
...]
I have no idea what's the bug.
Your second option declares path_list as a global variable, so it is known in all functions.
You could also declare it in the walk() function, the only place where it is needed. But, as commented, since that function is called recursively, that would reset the list every time, instead of aggregating the results.
See more at "Notes on Python variable scope".
Global variables are accessible inside and outside of functions.
Local variables are only accessible inside the function.
If I set a variable in a function with the same name as a global variable, I am actually creating a new local variable.
The problem here is that of scope of object.
When you make a main() function, you are declaring path_list in the local scope of main(). Hence it is not available to walk() function.
You have to pass path_list as an argument to walk or declare it globally as you did latter to make it available. As of current, path_list is out of scope of walk().
You need to declare path_list in the walk function, as it is the function that is operating on it. You get an error because you don't have any path_list pre-declared in that function.
Moreover, you don't need to define any path_list in the main function because it does not operate on it an doesn't need it.
When you declare it globally, it is available to all the functions, even the walk function. It uses that global variable and you don't get any error.

Resources