Let's create a single class that mimics our dict, and get's passed to these methods instead of operating on a global variable, and you can tell me if this is more what you're looking for. The fact of the matter is, you are already using a bit of object oriented programming and don't know it (the dict class)
Step 1: The Dict Class
Python Object Oriented Programming revolves around Classes, which can get instantiated one or more times, and these use functions defined on them. Then we call the methods with classname.class_method(input_variables) and get a return value just like if we called a non-bound function. In fact, there is a well defined difference between a global function and a function explicitly tied to a class instance. This is the difference between a 'bound' and 'unbound' method, and is where we get the magic name, self.
class ExampleDict(object):
#Called when a new class instance is created
def __init__(self, test):
self.dict = {}
self.dict["test"] = test
#Called when len() is called with a class instance as an argument
def __len__(self):
return len(self.dict)
#Called when the internal dict is accessed by instance_name[key]
def __getitem__(self, key):
return self.dict[key]
#Called when a member of the internal dict is set by
#instance_name[key] = value
def __setitem__(self, key, value):
self.dict[key] = value
#Called when a member of the internal dict is removed by del instance[key]
def __delitem__(self, key):
del self.dict[key]
#Return an iterable list of (key, value) pairs
def get_list(self):
return self.dict.items()
#Replace your global function with a class method
def check_value(self, key):
if not self.dict.has_key(value):
raise argparse.ArgumentTypeError("%s is invalid." % value)
return value
A few notes:
- This class definition must appear before any instances are created
- A Class instance is created with the following syntax:
d = ExampleDict()
Step 2: Removing Global Variables
Now, we want to remove the use of global variables. In many cases, as you see above, we can turn your methods into class methods. In cases where this isn't appropriate, you can accept an object as an argument to a global function. In this case, we want your method to accept the dict it operates on as an argument rather than operating on a global variable directly
def check_value_global(inp_dict, value):
if not inp_dict.has_key(value):
raise argparse.ArgumentTypeError("%s is invalid." % value)
return value
Step 3: Declaring Instances of the Class & Using them
Now, let's define what happens when we run the script and declare some class instances, then pass them to the method or execute their class methods:
if __name__ == "__main__":
#Declare an instance of the class
ex = ExampleDict("testing")
print(ex["test"])
ex["test2"] = "testing2"
check_value_global(ex, "test")
print("At next section")
ex.check_value("test2")
print("At final section")
For a more in-depth discussion of the power of object-oriented programming in Python, please see here
Edit Based on Comment
Ok so let's look at argparse in particular. This is going to parse command line arguments fed to the script (an alternative here would simply be reading from sys.argv).
In theory, we could include this anywhere, but we really should include it either directly after if __name__=="__main__":, or in a method called after this statement. Why?
Anything after this statement is run only if the python script is called directly from the command line, rather than imported as a module. Let's say you wanted to import your script into another python script and use it there. You don't require command line arguments in this case, so you don't want to try and parse them.
With all this said, we now know that we have both a dict object and an argparse object initialized in the main segment (after if __name__=="__main__":). How do we pass those to functions and classes defined above them in the program?
Well we have many options, the most common I utilize are:
- Where appropriate, we can redefine the dict class we are using to allow methods to be called as class methods after initialization
- We can pass objects to functions, as shown in step 2 above
- We can define a singleton class, which takes arguments of the dict and argparse object and stores them. Then, all major program flow in the relevant area runs through the singleton and these references are always available
Here's an example:
class SingletonExample(object):
def __init__(self, dict_obj, arg_obj):
self.dict = dict_obj
self.args = arg_obj
def some_script_function(self):
pass
#Use your self.dict and self.args arguments
The fact of the matter is that you are really talking about Design Patterns, and the way you solve this problem will be dictated by the design you choose. For instance, the third solution here is commonly referred to as the singleton pattern. Decide what pattern best suits the task at hand, do some research on it, and this will tell you how to structure your objects and methods.