Skip to content

Commit 95c010d

Browse files
author
Kenneth Reitz
committed
Merge pull request realpython#134 from guibog/master
Adding decorators, typing and (im)mutability
2 parents e730af5 + d62b2d7 commit 95c010d

File tree

1 file changed

+142
-0
lines changed

1 file changed

+142
-0
lines changed

docs/writing/structure.rst

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,148 @@ things that are manipulated (windows, buttons, avatars, vehicles) have a
249249
relatively long life of their own in the computer's memory.
250250

251251

252+
Decorators
253+
----------
254+
255+
Python language provides a simple yet powerful syntax called 'decorators'.
256+
A decorator is a function or a class that wraps (or decorate) a function
257+
or a method. The 'decorated' function or method will replace the original
258+
'undecorated' function or method. Because function are first-class objects
259+
in Python it can be done 'manually' but using the @decorator syntax is
260+
clearer and thus prefered.
261+
262+
.. code-block:: Python
263+
264+
def foo():
265+
# do something
266+
267+
def decorator(func):
268+
# manipulate func
269+
return func
270+
271+
foo = decorator(foo) # Manually decorate
272+
273+
@decorator
274+
def bar():
275+
# Do something
276+
# bar() is decorated
277+
278+
Using this mechanism is useful for separating concerns and avoiding
279+
external un-related logic to 'pollute' the core logic of the function
280+
or method. A good example of a functionality that is better handled
281+
with decoration is memoization or caching: you want to store the results of an
282+
expensive function in a table and use them directly instead of recomputing
283+
them when they have already been computed. This is clearly not part
284+
of the function logic.
285+
286+
Dynamic typing
287+
--------------
288+
289+
Python is said to be dynamically typed, which means that variables
290+
do not have a fixed type. In fact, in Python, variables are very
291+
different from what they are in many other languages, specifically
292+
strongly-typed languages: variables are not a segment of the computer's
293+
memory where some value ir written, they are 'tags' or 'names' pointing
294+
to objects. It is therefore possible for the variable 'a' to be set to
295+
the value 1, then to the value 'a string', then to a function.
296+
297+
The dynanic typing of Python is often considered as a weakness, and indeed
298+
it can lead to complexities and to hard-to-debug code, where something
299+
named 'a' can be set to many different things, and the developer or the
300+
maintainer need to track this name in the code to make sure it has not
301+
been set to a completely unrelated object.
302+
303+
Some guidelines allow to avoid this issue:
304+
305+
- Avoid using variables for different things.
306+
307+
**Bad**
308+
309+
.. code-block:: Python
310+
311+
a = 1
312+
a = 'a string'
313+
def a():
314+
pass # Do something
315+
316+
**Good**
317+
318+
.. code-block:: python
319+
320+
count = 1
321+
msg = 'a string'
322+
def func()
323+
pass # Do something
324+
325+
Using short functions or methods helps writing good code for many
326+
reasons, one being that their local scope is clearer, and the risk
327+
of using the same name for two unrelated things is lowered.
328+
329+
It is better to use different names even for things that are related,
330+
when they have a different type:
331+
332+
**Bad**
333+
334+
.. code-block:: python
335+
336+
items = 'a b c d' # This is a string...
337+
items = items.split(' ') # ...becoming a list
338+
items = set(items) # ...and then a set
339+
340+
There is no efficiency gain when reusing names: the assignments
341+
will have to create new objects anyway. However, when the complexity
342+
grows are each assignment are separated by other lines of code, including
343+
'if' branches and loops, it becomes harder to acertain which type is the
344+
variable at hand.
345+
346+
Some coding practices, like functional programming, even recommend to never re-assign a variable, which
347+
is done in Java with the keyword final. Python do not have such a keyword,
348+
and it would be against its philosophy anyway, but it may be a good
349+
discipline to avoid setting more than once any variable, and it helps
350+
in grasping the concept of mutable and immutable types.
351+
352+
Mutable and immutable types
353+
---------------------------
354+
355+
Python has two kinds of built-in or user-defined types.
356+
357+
Mutable types are those that allow in-place modification
358+
of the content. Typical mutables are lists and dictionaries:
359+
All lists have muting methods, like append() or pop(), and
360+
can be modified in place. Same for dictionaries.
361+
362+
Immutable types provide no method for changing their content.
363+
For instance, the variable x set to the integer 6 has no "increment" method. If you
364+
want to computed x + 1, you have to create another integer and give it
365+
a name.
366+
367+
.. code-block:: python
368+
369+
my_list = [1, 2, 3]
370+
my_list[0] = 4
371+
print my_list # [4, 2, 3] <- The same list as changed
372+
373+
x = 6
374+
x = x + 1 # The new x is another object
375+
376+
One consequence of this difference in behavior is that mutable
377+
types are not "stable", and therefore cannot be used as dictionary
378+
keys.
379+
380+
Using properly mutable types for things that are mutable in nature
381+
and immutable types for things that are fixed in nature
382+
helps to clarify the intent of the code.
383+
384+
For example, the immutable equivalent of a list is the tuple, created
385+
with ``(1, 2)``. This tuple is a pair that cannot be changed in-place,
386+
and can be used as a key for a dictionary.
387+
388+
One particularity of Python that can surprise in the beginning is that
389+
string are immutable. This means that when constructing a string from
390+
its parts, it is much more efficient to accumulate the parts in a list,
391+
which is mutable, and then glue ('join') the parts together when the
392+
full string is needed.
393+
252394
Vendorizing Dependencies
253395
------------------------
254396

0 commit comments

Comments
 (0)