How to structure a large python program




















There are three levels at which data can be shared between Python code: module globals, class attributes, and object attributes. In this first example, f gets x from the module namespace.

In this third example, g overrides x, and h obtains x from within g , because h was defined within g :. In all cases, without a global declaration, assignments will simply create a new local variable of that name, and not modify the value in any other scope:. However, with a global definition, the outermost scope is used:. I generally suggest avoiding scope trickery as much as possible, in the interests of readability. There are two common patterns that I use when I have to deal with scope issues.

First, module globals are sometimes necessary. For one such case, imagine that you have a centralized resource that you must initialize precisely once, and you have a number of functions that depend on that resource. Then you can use a module global to keep track of the initialization state. A few points, however:. Consider a situation where you have to use a callback API: that is, someone has given you a library function that will call your own code in certain situations. The matching substring is replaced by whatever the function returns.

I told you it was contrived! We could simply rely on scoping:. At this point advanced Pythoneers might sneer at me, because scoping is natural to Python, but nuts to them: readability and transparency is also very important. You could also do it this way:. The idea is to use keyword arguments on the function to pass in required information, thus making the information passing explicit.

I started discussing scope in the context of sharing data, but we got a bit sidetracked from data sharing. The key to thinking about data sharing in the context of code reuse is to think about how that data will be used. If you use a class attribute, then any object of that class type including inherited classes shares that data. And, if you use an object attribute, then every object of that class type will have its own version of that data.

How do you choose which one to use? My ground rule is to minimize the use of more widely shared data. In practice I almost never use class attributes, and infrequently use module globals.

Something that has been implicit in the discussion of scope and data sharing, above, is the order in which module code is executed. The reload function will reload the module and force re-execution at the top level:. For Example, consider the following code. You can fit your code in such a way that you do not have to scroll here and there.

Python allows you to write a single statement in multiple lines, also known as line continuation. Line continuation enhances readability as well. Bad Practice as width of this code is too much. Until then, the statement can be implicitly continued across lines without raising an error. In this method, you have to use a character that helps the interpreter to understand that the particular statement is spanning more than one lines.

Skip to content. Change Language. Related Articles. Table of Contents. Improve Article. Save Article. Like Article. Example 1. For example, a request may load an item in memory and mark it as read by a user.

If another request requires the deletion of this item at the same time, the deletion may actually occur after the first process loaded the item, and then we have to mark a deleted object as read. This and other issues led to the idea that using stateless functions is a better programming paradigm.

Another way to say the same thing is to suggest using functions and procedures with as few implicit contexts and side-effects as possible. Side-effects are the changes that a function makes to its implicit context. If a function saves or deletes data in a global variable or in the persistence layer, it is said to have a side-effect. Carefully isolating functions with context and side-effects from functions with logic called pure functions allows the following benefits:.

In summary, pure functions are more efficient building blocks than classes and objects for some architectures because they have no context or side-effects. A decorator is a function or a class that wraps or decorates a function or a method.

A good example of a piece of functionality that is better handled with decoration is memoization or caching: you want to store the results of an expensive function in a table and use them directly instead of recomputing them when they have already been computed.

This is clearly not part of the function logic. A context manager is a Python object that provides extra contextual information to an action. This extra information takes the form of running a callable upon initiating the context using the with statement, as well as running a callable upon completing all the code inside the with block. The most well known example of using a context manager is shown here, opening on a file:. There are two easy ways to implement this functionality yourself: using a class or using a generator.

This is just a regular Python object with two extra methods that are used by the with statement. The finally clause ensures that close is called whether or not there was an exception inside the with. Since the two approaches appear the same, we should follow the Zen of Python to decide when to use which. Python is dynamically typed, which means that variables do not have a fixed type.

In fact, in Python, variables are very different from what they are in many other languages, specifically statically-typed languages.

The dynamic typing of Python is often considered to be a weakness, and indeed it can lead to complexities and hard-to-debug code.

Using short functions or methods helps to reduce the risk of using the same name for two unrelated things. It is better to use different names even for things that are related, when they have a different type:.

There is no efficiency gain when reusing names: the assignments will have to create new objects anyway. Some coding practices, like functional programming, recommend never reassigning a variable. In Java this is done with the final keyword. Python does not have a final keyword and it would be against its philosophy anyway.

However, it may be a good discipline to avoid assigning to a variable more than once, and it helps in grasping the concept of mutable and immutable types. Mutable types are those that allow in-place modification of the content. Typical mutables are lists and dictionaries: All lists have mutating methods, like list. The same goes for dictionaries. Immutable types provide no method for changing their content.

Using properly mutable types for things that are mutable in nature and immutable types for things that are fixed in nature helps to clarify the intent of the code. For example, the immutable equivalent of a list is the tuple, created with 1, 2. This tuple is a pair that cannot be changed in-place, and can be used as a key for a dictionary.

One peculiarity of Python that can surprise beginners is that strings are immutable. This means that when constructing a string from its parts, appending each part to the string is inefficient because the entirety of the string is copied on each append.

Instead, it is much more efficient to accumulate the parts in a list, which is mutable, and then glue join the parts together when the full string is needed. List comprehensions are usually the fastest and most idiomatic way to do this.

One final thing to mention about strings is that using join is not always best. In the instances where you are creating a new string from a pre-determined number of strings, using the addition operator is actually faster. But in cases like above or in cases where you are adding to an existing string, using join should be your preferred method.

This opinionated guide exists to provide both novice and expert Python developers a best practice handbook to the installation, configuration, and usage of Python on a daily basis. All proceeds are being directly donated to the DjangoGirls organization. Dress for the job you want, not the job you have.

It should not be tucked away:. There is little reason for this to exist elsewhere. Starting out, a small test suite will often exist in a single file:. Sample Makefile: init : pip install - r requirements.



0コメント

  • 1000 / 1000