restrict scopes of local variables in python - python

When there is a long function, how to limit the scope of variables within only a section of the function? I know in many languages one can do this with {}. How to do this in python?
I am aware that a separate function for just that section will encapsulate variables to its local namespace. But for a long, linear function, many people argue that it does not make sense to write many functions (and thus names) that are only called once.

Generally speaking, you can't. Python only creates scopes for modules (files, generally), classes, and functions; variables can have a more limited lifetime only in a few special cases, like the target_list in a list comprehension in Python 3. There's no block-level scope like in Perl.
So, your possible workarounds are:
Create single-use functions or classes. The function would have to be called, whereas the class would never have to be named again after its definition, because class definitions are executed immediately.
del variables when you're done with them.
Fun fact: coming to terms with this limitation of Python is what finally got us to get rid of let in Hy, because there's no way to make it work as one would expect. Update 5 years later: yet another version of let is implemented, and the way it works is by implementing our own entire system for tracking the scopes of variables, and enforcing it by issuing compile-time errors and adding nonlocal and global when needed. I guess there are no shortcuts here.

Related

Use function globally or locally?

In Python I have several functions that use the location of the user's directory as a way of determining where to put files.
I currently use a "global" variable for all the functions to use.
home = os.path.expanduser('~')
I'm wondering if this is good coding practice.
The upside of this is that the program only needs to execute this code only once.
I could also have each function call os.path.expanduser each time it is called.
Which is the more pythonic one? Or is there a pythonicer way?
There's nothing wrong with globals. It's a consequence of how you designed your program. You wrote a few functions and put them in a module, and globals are a way to share data between individual functions in a module.
For example, had you decided to go with an object oriented design, then one could argue that globals should be avoided and shared data should be encapsulated. But you didn't do that, so globals are fine.
It is ok to use global constants. At the end all the first-level function and classes defined in the same module are also "global" in this sense.
Using gobal variables becomes messy when different components of the system start re-assigning their values or mutate their content. In this case it's an obvious antipattern and can lead to a debugging hell.

Safest way of using global variables in python: module or "global" keyword?

I have to share around 10 variables between functions, which are contained in the same .py file. The variables will be modified in almost every function. I know that global variables are evil, but unfortunately for now I have to keep few of them as global, while the rest I have been able to change the implementation and to pass them as an argument.
One way of doing this would be using the "global" keyword, but I have run into another option, that would be placing them in an empty module, and importing the module every time.
I am just a beginner in python, what would be the best way to do this?
EDIT: This is a rewriting of a code based almost completely on global variables. Almost all the functions are now in a class, the variables are used with self.name_var. However, since we are using multiprocess with Array, few variables have to remain globals.
Thanks,
Andrea
Just do not do it, put all the functions, if they are related, in a class and make the variables accessible with self. Using a different module is worst.

how to prevent python function to read outer scope variable?

When defining a python function, I find it hard to debug if I had a typo in a variable name and that variable already exists in the outer scope. I usually use similar names for variables of the same type of data structure, so if that happens, the function still runs fine but just returns a wrong result. So is there a way to prevent python functions to read outer scope variables?
You're going against the point of having Scopes at all. We have local and global scopes for a reason. You can't prevent Python from seeing outer scope variables. Some other languages allow scope priority but Python's design principles enforce strong scoping. This was a language design choice and hence Python is the wrong language to try to prevent outer scope variable reading.
Just use better naming methodologies to ensure no confusion, you change up variable names by using the Find-Replace function that most text editors provide.
They say you should avoid usage of global variables if possible. Also, keep in mind, that python has rules on searching variables in the specific order.
So you can avoid checking global variables only if you will delete them, but it makes usage of global variables useless.

alternative for passing references around in python

I'm relatively new to python and oop, and i have a question around the design of my code for a hobby project.
I created a lot of variables in my main program. These variables are lists of objects (not configuration parameters and not constants). The objects in the lists are sprites.
I'm passing these variables around between objects, by calling methods and passing the variables around as arguments for a specific method. (pass-by-reference)
For example:
spritelist = [Sprite(...), Sprite(..)]
mycollisiondetector = CollisionDetector()
mycollisiondetector.check_collision(spritelist)
Then, in class CollisionDetector, spritelist is passed to "private" methods of the class. These private methods call other methods, and keep passing spritelist ... .
So, my question is just this: is there an alternative for endlessly passing variables around from one method to another ?
If you're dealing with instance variables (not configuration constants), it's considered bad practice to separate the variables into a module (a different file), since you're mixing instance state and global state.
If you have many references being passed around repeatedly, this is usually a indicator of bad class hierarchy design. You may want to consider subclassing, or defining a new class for your variables and passing a reference to it. The details will depend on your specific situation - it's hard to tell without seeing the code.

What's a good way to keep track of class instance variables in Python?

I'm a C++ programmer just starting to learn Python. I'd like to know how you keep track of instance variables in large Python classes. I'm used to having a .h file that gives me a neat list (complete with comments) of all the class' members. But since Python allows you to add new instance variables on the fly, how do you keep track of them all?
I'm picturing a scenario where I mistakenly add a new instance variable when I already had one - but it was 1000 lines away from where I was working. Are there standard practices for avoiding this?
Edit: It appears I created some confusion with the term "member variable." I really mean instance variable, and I've edited my question accordingly.
I would say, the standard practice to avoid this is to not write classes where you can be 1000 lines away from anything!
Seriously, that's way too much for just about any useful class, especially in a language that is as expressive as Python. Using more of what the Standard Library offers and abstracting away code into separate modules should help keeping your LOC count down.
The largest classes in the standard library have well below 100 lines!
First of all: class attributes, or instance attributes? Or both? =)
Usually you just add instance attributes in __init__, and class attributes in the class definition, often before method definitions... which should probably cover 90% of use cases.
If code adds attributes on the fly, it probably (hopefully :-) has good reasons for doing so... leveraging dynamic features, introspection, etc. Other than that, adding attributes this way is probably less common than you think.
pylint can statically detect attributes that aren't detected in __init__, along with many other potential bugs.
I'd also recommend writing unit tests and running your code often to detect these types of "whoopsie" programming mistakes.
Instance variables should be initialized in the class's __init__() method. (In general)
If that's not possible. You can use __dict__ to get a dictionary of all instance variables of an object during runtime. If you really need to track this in documentation add a list of instance variables you are using into the docstring of the class.
It sounds like you're talking about instance variables and not class variables. Note that in the following code a is a class variable and b is an instance variable.
class foo:
a = 0 #class variable
def __init__(self):
self.b = 0 #instance variable
Regarding the hypothetical where you create an unneeded instance variable because the other one was about one thousand lines away: The best solution is to not have classes that are one thousand lines long. If you can't avoid the length, then your class should have a well defined purpose and that will enable you to keep all of the complexities in your head at once.
A documentation generation system such as Epydoc can be used as a reference for what instance/class variables an object has, and if you're worried about accidentally creating new variables via typos you can use PyChecker to check your code for this.
This is a common concern I hear from many programmers who come from a C, C++, or other statically typed language where variables are pre-declared. In fact it was one of the biggest concerns we heard when we were persuading programmers at our organization to abandon C for high-level programs and use Python instead.
In theory, yes you can add instance variables to an object at any time. Yes it can happen from typos, etc. In practice, it rarely results in a bug. When it does, the bugs are generally not hard to find.
As long as your classes are not bloated (1000 lines is pretty huge!) and you have ample unit tests, you should rarely run in to a real problem. In case you do, it's easy to drop to a Python console at almost any time and inspect things as much as you wish.
It seems to me that the main issue here is that you're thinking in terms of C++ when you're working in python.
Having a 1000 line class is not a very wise thing anyway in python, (I know it happens alot in C++ though),
Learn to exploit the dynamism that python gives you, for instance you can combine lists and dictionaries in very creative ways and save your self hundreds of useless lines of code.
For example, if you're mapping strings to functions (for dispatching), you can exploit the fact that functions are first class objects and have a dictionary that goes like:
d = {'command1' : func1, 'command2': func2, 'command3' : func3}
#then somewhere else use this list to dispatch
#given a string `str`
func = d[str]
func() #call the function!
Something like this in C++ would take up sooo many lines of code!
The easiest is to use an IDE. PyDev is a plugin for eclipse.
I'm not a full on expert in all ways pythonic, but in general I define my class members right under the class definition in python, so if I add members, they're all relative.
My personal opinion is that class members should be declared in one section, for this specific reason.
Local scoped variables, otoh, should be defined closest to when they are used (except in C--which I believe still requires variables to be declared at the beginning of a method).
Consider using slots.
For example:
class Foo:
__slots__ = "a b c".split()
x = Foo()
x.a =1 # ok
x.b =1 # ok
x.c =1 # ok
x.bb = 1 # will raise "AttributeError: Foo instance has no attribute 'bb'"
It is generally a concern in any dynamic programming language -- any language that does not require variable declaration -- that a typo in a variable name will create a new variable instead of raise an exception or cause a compile-time error. Slots helps with instance variables, but doesn't help you with, module-scope variables, globals, local variables, etc. There's no silver bullet for this; it's part of the trade-off of not having to declare variables.

Categories