
Good day, Habrahabr. Today on the wing brought another translation by me (
pdf -googo Google
style guide laid out). Although, who knows, if someone appreciates this work, there may be a sequel. One day alone, my colleague
Scraplesh, well-known in narrow circles, offered me to read the resource -
The Hitchhiker's Guide to Python! called. I liked this resource. Liked the tips given out there. I liked the outline of the story and generally liked the direction of thought of the author. And if something is good for your taste, then you need to pass it from mouth to mouth :) So, I decided to translate this resource. But not all at once - at first there will be a trial article “to the response” of the habrasocommunity. If respected geeks like this subject and presentation - we will try to produce new parts. On the first “response” I chose the section - “
Writing Great Code ” and in it there are two subitems “Structure is Key” and “Modules”. Let's respond under the cut.
But before plunging into other people's thoughts about your favorite Python, you need to submit the actual author of the resource. His name is
Kenneth Reitz . As I understood from the information collected, he is a professional photographer (we can find out about this on his personal
website ), an evangelist of the Python language and just a guru of various kinds of development. He works at the moment (according to unconfirmed reports) in Heroku. I also call upon everyone to fork his project on a
githab .
Kenneth PhotographyKenneth Reitz at PyCon in Australia (2012)

Next is the article itself. (If you find errors, as usual - immediately shout about them! Errors require correction.)
Structure your project
By structure, we mean the decisions you made regarding how your project can achieve its goals. We need to consider how best to use the functional features of the Python language to write clean and efficient code. From a practical point of view, the concept of "structure" means the creation (writing) of a net when, in which, the logic and dependencies are as clear as the organization of files and folders in the file system.
What functions should be moved to which modules? How will the data flow through the project? What features and functions can be grouped together and isolated? By answering such questions, you can start planning how the finished product will look.
In this section, we take a closer look at the system of modules and imports in Python, because they are a central element in ensuring the structuring of your project. Then, we will discuss different points of view on how to build code that can be extended and reliably tested.
')
Structure decides
Due to the fact that imports and modules are processed in Python, it is relatively easy to structure a project written in this language. The word “simple” in this context means that you will not create unnecessary restrictions, and that the model of the imported module is easy to understand. Thus, you need to concentrate on a purely architectural task, namely, to work on the creation of various parts of your project and their interaction.
Just a structured project means that you can also create a poorly structured project. Some signs of a poorly structured project:
- Multiple and dirty cyclic dependencies. If your
Table
and Chair
classes need to import the Carpenter
class from the workers.py
module, to answer the question table.isdoneby()
, and vice versa, if the Carpenter
class needs to import the Table
class and Chair
class to answer the carpenter.whatdo()
question carpenter.whatdo()
- you get a circular dependency. In this case, you will have to resort to tricky tricks, such as using the import statement inside methods or functions. - Hidden connections. Each and every change in the class
Table
fails 20 tests in unrelated tests, because it distorts the execution of the code of the Carpenter
class, which requires a surgically fine adaptive change of the code. This means that you have too many “arrangements” for the Table class in the code of the Carpenter
class or vice versa. - Intensive use of the global namespace or context. Instead of explicitly passing (height, width, type, tree) to each other variables in the
Table
and Carpenter
classes, you rely on global variables that can be changed and modified on the fly by various “comrades”. You should carefully examine all the places where you can access these global variables, to understand why the rectangular table became square and find that the remote code was also changed in this context by changing the table size. - Spaghetti code. Several pages of nested
if
constructions and for
loops with a large number of duplicate code and no segmented code, known as spaghetti. Due to meaningful indents in Python (one of the most discussed features), it is very difficult to write such code in a given language. So there is good news - you will not watch such a code often. - Ravioli code. Such code is more typical for Python. It consists of hundreds of identical (or similar to each other) pieces of logic, classes, or objects without proper structuring. If you can’t remember not to use
FurnitureTable
, AssetTable
or Table
, or even TableNew
to solve your problem, you will bathe in the ravioli code.
Modules
Modules in Python are one of the main layers of abstraction that are available, and are probably the most native to the language. Levels of abstraction allow you to divide the code into parts processing the relevant data and containing any functionality.
For example, one project layer can handle user interaction, while the other will handle low-level data manipulation. The most natural way to separate these two levels is to put all the functionality in one file, and all low-level operations in the other. In this case, the interface file will need to import a file with low-level functionality. This is done using the
import
and
from ... import
expressions.
As soon as you start using the import statement, you start using modules. These can be built-in modules, such as
os
and
sys
, third-party modules that you installed in your environment, or internal modules of your project.
To adhere to the leadership style, try giving the modules short names that contain only lowercase letters and make sure that you do not use special characters, such as a dot (.) Or a question mark (?). Since the file name is similar to my.spam.py, you should avoid it. Naming in this way will prevent Python from looking for modules.
In this example, Python expects to find "
spam.py
" in a folder called "
my
", which does not exist. There is an example of how dot notation should be used in Python documents.
If you want, you can name the file
my_spam.py
, but even our friend — Underline — should not be used often in module names.
In addition to some naming restrictions, the file does not need anything else to become a Python module, but the import mechanism needs to be understood in order to use this concept properly and avoid some problems.
Frankly, the import statement will look for the corresponding module.py file in the same directory as the import file. If it is not found, the Python interpreter will search
module.py
in the "
path
" variable recursively and throw an
ImportError
exception if the latter is not found.
After
module.py
is found, the Python interpreter will execute the module in an isolated scope. Any top-level declaration in the
module.py
file will be executed, including nested imports, if any. Declarations of functions and classes will be saved in the module dictionary
Then the module variables, functions, and classes will be available for calling through the module namespace — a central programming concept that is particularly powerful and useful in Python.
In many languages, the file is included directly using the preprocessor to find all the code in the file and “copy” it into the code of the calling module. This is different from the behavior of the Python language, in which the plug-in code is isolated within the scope of its module, which means that you may not worry that including code can have undesirable consequences, for example, overriding existing functions with the same name.
This allows you to model more standard behavior using the special syntax of the import:
from module import *
expression. This is usually considered a bad practice. Using "
import *
" makes the code difficult to read and makes dependencies less fragmented.
Using
from module import func
is a way to specify the function that you want to import and place in global scope. And it is also less harmful for the code than "
import *
", since it clearly shows what is being imported into the global scope, the advantage of a simpler import module entry is to save keystrokes.
As stated in the style section, readability is one of the main features of Python. Readability means avoiding the use of useless text content and clutter in the code, so usually some effort is spent on trying to achieve a certain level of code brevity. But brevity and simplicity have certain limits, where the reduction of the code should stop. Being able to immediately tell where this or that class or function begins, as well as the ideology of
module.func
, which significantly improves the readability of the code and its transparency in all but the simplest, separate projects “in one file”.