Alternative to Passing Global Variables Around to Classes and Functions - python

I'm new to python, and I've been reading that using global to pass variables to other functions is considered noobie, as well as a bad practice. I would like to move away from using global variables, but I'm not sure what to do instead.
Right now I have a UI I've created in wxPython as its own separate class, and I have another class that loads settings from a .ini file. Since the settings in the UI should match those in the .ini, how do I pass around those values? I could using something like: Settings = Settings() and then define the variables as something like self.settings1, but then I would have to make Settings a global variable to pass it to my UI class (which it wouldn't be if I assign in it main()).
So what is the correct and pythonic way to pass around these variables?
Edit: Here is the code that I'm working with, and I'm trying to get it to work like Alex Martelli's example. The following code is saved in Settings.py:
import ConfigParser
class _Settings():
#property
def enableautodownload(self): return self._enableautodownload
def __init__(self):
self.config = ConfigParser.ConfigParser()
self.config.readfp(open('settings.ini'))
self._enableautodownload=self.config.getboolean('DLSettings', 'enableautodownload')
settings = _Settings()
Whenever I try to refer to Settings.settings.enableautodownload from another file I get: AttributeError: 'module' object has no attribute 'settings'. What am I doing wrong?
Edit 2: Never mind about the issue, I retyped the code and it works now, so it must have been a simple spelling or syntax error.

The alternatives to global variables are many -- mostly:
explicit arguments to functions, classes called to create one of their instance, etc (this is usually the clearest, since it makes the dependency most explicit, when feasible and not too repetitious);
instance variables of an object, when the functions that need access to those values are methods on that same object (that's OK too, and a reasonable way to use OOP);
"accessor functions" that provide the values (or an object which has attributes or properties for the values).
Each of these (esp. the first and third ones) is particularly useful for values whose names must not be re-bound by all and sundry, but only accessed. The really big problem with global is that it provides a "covert communication channel" (not in the cryptographic sense, but in the literal one: apparently separate functions can actually be depending on each other, influencing each other, via global values that are not "obvious" from the functions' signatures -- this makes the code hard to test, debug, maintain, and understand).
For your specific problem, if you never use the global statement, but rather access the settings in a "read-only" way from everywhere (and you can ensure that more fully by making said object's attributes be read-only properties!), then having the "read-only" accesses be performed on a single, made-once-then-not-changed, module-level instance, is not too bad. I.e., in some module foo.py:
class _Settings(object):
#property
def one(self): return self._one
#property
def two(self): return self._two
def __init__(self, one, two):
self._one, self._two = one, two
settings = _Settings(23, 45)
and from everywhere else, import foo then just access foo.settings.one and foo.settings.two as needed. Note that I've named the class with a single leading underscore (just like the two instance attributes that underlie the read-only properties) to suggest that it's not meant to be used from "outside" the module -- only the settings object is supposed to be (there's no enforcement -- but any user violating such requested privacy is most obviously the only party responsible for whatever mayhem may ensue;-).

Related

Does the existence of a derived class modify a base class, even if the derived class is never used?

I have a base class, Sample and a derived class SignalSample, and the code for both of these classes normally resides within the same file Sample.py.
I import these classes into my main script in the usual way: from Sample import Sample, SignalSample
While chasing down a bug within one of these classes, I noticed some unusual behavior: deleting the code for the SignalSample derived class changed the behavior of the Signal base class.
So my question is, can the existence of a derived class alter a base class, even if the derived class is never instantiated?
To be concrete, I tried the following combinations.
The code for Sample and SignalSample are both in Sample.py. from Sample import Sample, SignalSample is used in my main script to load these classes. Sample objects are instantiated, there are no SignalSample objects instantiated, the code is just there and unused. In this scenario, I get an error which I will call "type 1".
Delete the code for SignalSample inside Sample.py, and remove the ... import SignalSample statement. In this case, I get a different error which I'll call "type 2".
Note that I don't think the errors are coming from the classes themselves (although they may be), it was more that I found it interesting that the behavior of the code seemed to change because there was an inherited class, even though that class was not used.
This is a stripped-down example of my setup, note that this is not an MWE of the source of my bug, as at the moment I don't know where it is coming from, and so I can't even narrow it down. It's not the solution to the bug I'm looking for, just more information on this seemingly strange behavior of class inheritance.
# file Sample.py
class Sample:
def __init__(self):
self._tfile = None
self._filepath = None
def calculate_filepath(self):
return "my/file/path"
__calculate_filepath = calculate_filepath # private copy
def get_histogram(self, histogram_name):
if not self._filepath:
self._filepath = self.calculate_filepath()
if not self._tfile:
from ROOT import TFile # this is a special filetype
self._tfile = TFile.Open(self._filepath, "READ")
histo = self._tfile.Get(histogram_name)
histo.SetDirectory(0)
self._tfile.Close()
return histo
class SignalSample(Sample):
def __init__(self):
# Inherit
Sample.__init__(self)
self._filepath = self.calculate_filepath()
def calculate_filepath(self):
# Overloaded version of the function in Sample
return "my/very/special/filepath"
Note that I chose to call the calculate_filepath method inside get_histogram because I wanted to avoid possible namespace clashes with the derived class. This is also why I try to make the method "private" with the namespace mangling. This is also why I open the special TFile file inside the get_histogram method, although it is nice that I can then also Close this file inside the same function. Perhaps this isn't the correct usage and maybe this related to the source of my problem?
get_histogram looks potentially broken if it is called more than once. You assign the opened file to the instance (on self._tfile), but then close it before returning... that means that next time the method is called not self._tfile will probably (*) evaluate to False, meaning that you then try to call Get on a closed file. If you are using a sane library this would probably throw a nice error telling you this, but I see you're using ROOT so who knows what might happen :)
Probably simplest would be not to store the file on Sample, and just open the file whenever get_histogram is called?
(*) Implicit booliness is sometimes worth avoiding. In particular when what you actually want to check is whether something is None, prefer writing if x is None: ( https://legacy.python.org/dev/peps/pep-0008/#programming-recommendations )
Incidentally, in this example, __calculate_filepath = calculate_filepath # private copy isn't doing anything, since you never actually use it.

python: manipulating the global name space vs explicit assignment of object reference

I've been reading plenty of posts here stating that one should never manipulate the global namespace. I understand the concerns WRT good coding practice (I.e., keep things localized where you can, avoid side effects etc., etc.). But many comments also point to issues WRT performance (i.e. that doing so bloats the globals dict). However, I am curious whether the following two cases are indeed treated differently by the python interpreter
# let's assume the following two classes
class someclass1():
def __init__(self,name):
self.n = name
class someclass2():
def __init__(self,name):
import builtins
self.n = name
setattr(builtins,name,self)
# now we create the instances as
SC1 = someclass1("SC1")
someclass2("SC2")
Both versions will create new object handles (SC1 and SC2) in the global namespace. Does it truly matter how I create them? Note, I am fully aware that this can be handled by a dict but let's keep the discussion of why I want to do this for another thread.

Python: Passing a class instance to an external function

I have come across a python project that commonly calls external functions from class methods and passes the class instance and some other parameters to the external function.
The method used is shown in method_one below and I have never come across this implementation before. Using locals to get both the local method parameters and the self class instance seems strange to say the least. The code then relies upon the dictionary keys being named correctly i.e. the same as the parameters of the external function (some_function).
To me, the obvious, simpler direct alternative is method_two but even over that I would prefer either
making some_function a method of ExampleClass1 so it has direct access to self, or
passing only the required attributes of the ExampleClass1 instance to some_function.
Example code:
class ExampleClass1(object):
def __init__(self, something):
self.something = something
def method_one(self, param_1, param_2):
all_params = locals()
all_params['example_self'] = all_params.pop('self')
some_function(**all_params)
def method_two(self, param_1, param_2):
some_function(self, param_1, param_2)
def some_function(example_self, param_1, param_2):
print(example_self.something, param_1, param_2)
e = ExampleClass1("do")
e.method_one(1, "a")
e.method_two(2, "b")
So,
Is there any reason to be using method_one that I'm not aware of?
How would you offer advice on the best practice for this situation?
Passing self as a parameter to external functions is a totally standard practice. I'm a little unclear why the call to locals() is used and why keys are being shuffled around, but that's a separate matter. In general, I find that if you're using locals(), then 9 times out of 10 the code you're writing can be simpler. Notable exception being metaprogramming, which is another topic.
One example that I use this for is when you want to separate out code into several modules rather than have one large class with a bunch of methods. There's a lot of ways to organize code, but one approach that I use is to segregate functions to other modules based on their domain, and then pass self to those functions for their use.
Concrete example: a server object accepting requests can have the routes handling those requests live elsewhere, and then delegate the actual business logic to the external route functions. If those routes need the server object, though, then you may want to pass self (being the server) to them. You could make an argument they should just be methods then, but that's a matter of code style and depends a lot on exact use case.
In general, passing self around isn't a bad practice when used appropriately.

What is dynamic dispatch and duck typing?

When using Pycharm, It often points out an error, saying:
Unresolved reference 'name'. This inspection detects names that should
resolve but don't. Due to dynamic dispatch and duck typing, this is
possible in a limited but useful number of cases. Top-level and
class-level items are supported better than instance items.
I've snooped around about this, but most questions and information I find is about preventing the message from being shown. what I want to know is:
What is dynamic dispatch/duck typing?
What are (or an example of) these "useful number of cases"?
Python uses a duck typing convention. This means that you do not have to specify what type a name is. Unlike in Java, for example, where you must specify explicitly that variable may be type int or Object. Essentially, type checking is done at runtime.
"If it walks like a duck and it quacks like a duck, then it must be a duck."
In Python everything will seem to work until you use try to manipulate an object in a way that it is not designed to. Basically, an object may not have a certain method or attribute that another might, and you won't find this out until Python throws an error upon trying it.
Dynamic Dispatch is the practice of the compiler or environment choosing which version of a polymorphic function to use at runtime. If you have multiple implementations of a method, you can use them in different ways despite the methods having the same or similar properties/attributes. Here's an example:
class Foo:
def flush():
pass
class Bar:
def flush():
pass
Both classes have a flush() method but the correct name is chosen at runtime.
Python is not the best example of this process since methods can take multiple parameters and don't have to be reimplemented. Java is a better example, but I'm not fluent enough in it to provide a correct example.
The warning means that you're using a variable that PyCharm doesn't recognise, but due to Python's dynamic nature it can't be sure if it's right or you're right.
For example you may have the following code:
class myClass():
def myfunc(self):
print(self.name)
PyCharm will probably complain that self.name can't be resolved. However, you may use the class like this:
my_class = myClass()
my_class.name = "Alastair"
my_class.myfunc()
which is perfectly valid (albeit brittle).
The message goes on to say that it's more confident about attribute and methods that are less ambiguous. For example:
class myClass():
my_instance_var = "Al"
def myfunc(self):
print(self.my_instance_var)
As my_instance_var is defined in the source code (a class attribute), PyCharm can be confident it exists.
(Don't use class attributes unless you know what you're doing!)

Scattered declaration of class/instance variable names in Python due to combining declaration with useage

I'm very new to python so please don't be displeased if I missed some thing.
It seems that class and instance variables in python simply sprint into existence when they are used, this combination of use and declaration of instance variables results in the declaration of a class no longer being the only place that a class's data structures can be defined. consequently given a class Cls one cannot tell what data structures been created for it for one to access simply by tracing up stream to the class's declaration, as one can do with languages such as C and Java. Instead, one is compel to search all modules that might have used/define variables for that class.
As a result when a class is used by multiple modules, although you know of some data structure belong to that class must have been defined, to know it's name and type, you have to search through all the imported files that might have used that class (in a way that create new variables) to see just where was it used/defined.
example
declaration:
class Cls:
pass
module1:
Cls.m = 2.3
module_n:
print Cls.m
And again the issue being for those who operate on module_n, before they write that print statement, they don't know whether the variable name will be defined in module1 or some other module in the import list that could have used Cls , but if they can't find where the variable's defined they can't use it, since they don't know the name of that variable, or even its existence.
As someone less than a day into Python who is reading a rather lengthy project, I want to know if there's any trick to solve this, both as a reader and as the writer, how can such headaches be avoided

Categories