diff --git a/README.md b/README.md
index 043cba4..b4205fe 100644
--- a/README.md
+++ b/README.md
@@ -79,6 +79,7 @@ If you want to translate this book in any other language then kindly let [me kno
- [Russian](https://github.com/lancelote/interpy-ru)
- [Korean](https://github.com/DDanggle/interpy-kr)
- [Portuguese](https://github.com/joanasouza/intermediatePython)
+- [Spanish](https://github.com/cursospython/LibroPython)
License:
-------
diff --git a/_templates/breadcrumbs.html b/_templates/breadcrumbs.html
index 4992447..f3f3b94 100644
--- a/_templates/breadcrumbs.html
+++ b/_templates/breadcrumbs.html
@@ -25,13 +25,14 @@
{% endif %}
-
-
Note
-
Hi! My name is Yasoob. I am the author of this book. I regularly write Python posts on Python Tips. Everything else finds its way to my personal blog. I would love it if you can give them a read. I also announce my new projects there :)
-
+
New book released!
+
Hi! I just released the alpha version of my new book; Practical Python Projects.
+ Learn more about it
+ on my blog. In 325+ pages, I will teach you how to implement 12 end-to-end projects.
+ You can buy it from Feldroy.com.
+
-
{% block breadcrumbs %}
- {{ _('Docs') }} »
diff --git a/args_and_kwargs.rst b/args_and_kwargs.rst
index 544742e..85ed174 100644
--- a/args_and_kwargs.rst
+++ b/args_and_kwargs.rst
@@ -3,21 +3,20 @@
I have come to see that most new python programmers have a hard time
figuring out the \*args and \*\*kwargs magic variables. So what are they
-? First of all let me tell you that it is not necessary to write \*args
+? First of all, let me tell you that it is not necessary to write \*args
or \*\*kwargs. Only the ``*`` (asterisk) is necessary. You could have
also written \*var and \*\*vars. Writing \*args and \*\*kwargs is just a
-convention. So now lets take a look at \*args first.
+convention. So now let's take a look at \*args first.
Usage of \*args
^^^^^^^^^^^^^^^
\*args and \*\*kwargs are mostly used in function definitions. \*args
-and \*\*kwargs allow you to pass a variable number of arguments to a
-function. What variable means here is that you do not know beforehand
-how many arguments can be passed to your function by the user
-so in this case you use these two keywords. \*args is used to send a
-**non-keyworded** variable length argument list to the function. Here's
-an example to help you get a clear idea:
+and \*\*kwargs allow you to pass an unspecified number of arguments to a
+function, so when writing the function definition, you do not need to
+know how many arguments will be passed to your function. \*args is used to
+send a **non-keyworded** variable length argument list to the function.
+Here's an example to help you get a clear idea:
.. code:: python
diff --git a/classes.rst b/classes.rst
index 4d45cf2..9485307 100644
--- a/classes.rst
+++ b/classes.rst
@@ -159,7 +159,7 @@ its ``__init__`` method is called. For example:
# called
You can see that ``__init__`` is called immediately after an instance is
-created. You can also pass arguments to the class during it's
+created. You can also pass arguments to the class during its
initialization. Like this:
.. code:: python
diff --git a/collections.rst b/collections.rst
index af0aa5c..f668ca6 100644
--- a/collections.rst
+++ b/collections.rst
@@ -9,7 +9,7 @@ The ones which we will talk about are:
- ``defaultdict``
- ``OrderedDict``
-- ``counter``
+- ``Counter``
- ``deque``
- ``namedtuple``
- ``enum.Enum`` (outside of the module; Python 3.4+)
@@ -119,7 +119,7 @@ the end of the dictionary.
# Blue 160
# Insertion order is preserved
-``counter``
+``Counter``
^^^^^^^^^^^^^^^
Counter allows us to count the occurrences of a particular item. For
diff --git a/context_managers.rst b/context_managers.rst
index 79d944f..261ebd6 100644
--- a/context_managers.rst
+++ b/context_managers.rst
@@ -36,7 +36,7 @@ Let's see how we can implement our own Context Manager. This should allow
us to understand exactly what's going on behind the scenes.
Implementing a Context Manager as a Class:
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
At the very least a context manager has an ``__enter__`` and
``__exit__`` method defined. Let's make our own file-opening Context
@@ -153,8 +153,10 @@ Let's see a basic, useless example:
@contextmanager
def open_file(name):
f = open(name, 'w')
- yield f
- f.close()
+ try:
+ yield f
+ finally:
+ f.close()
Okay! This way of implementing Context Managers appear to be more
intuitive and easy. However, this method requires some knowledge about
@@ -167,7 +169,7 @@ Let's dissect this method a little.
1. Python encounters the ``yield`` keyword. Due to this it creates a
generator instead of a normal function.
2. Due to the decoration, contextmanager is called with the function
- name (``open_file``) as it's argument.
+ name (``open_file``) as its argument.
3. The ``contextmanager`` decorator returns the generator wrapped by the
``GeneratorContextManager`` object.
4. The ``GeneratorContextManager`` is assigned to the ``open_file``
diff --git a/debugging.rst b/debugging.rst
index 58af25a..5e591f8 100644
--- a/debugging.rst
+++ b/debugging.rst
@@ -2,14 +2,14 @@ Debugging
---------
Debugging is also something which once mastered can greatly enhance your
-bug hunting skills. Most of the newcomers neglect the importance of the
+bug hunting skills. Most newcomers neglect the importance of the
Python debugger (``pdb``). In this section I am going to tell you only a
few important commands. You can learn more about it from the official
documentation.
-**Running from commandline**
+**Running from the command line**
-You can run a script from the commandline using the Python debugger.
+You can run a script from the command line using the Python debugger.
Here is an example:
.. code:: python
@@ -58,3 +58,7 @@ function.
These are just a few commands. ``pdb`` also supports post mortem. It is
also a really handy function. I would highly suggest you to look at the
official documentation and learn more about it.
+
+**Note:**
+
+It might seem unintuitive to use `pdb.set_trace()` if you are new to this. Fortunately, if you are using Python 3.7+ then you can simply use the `breakpoint()` [built-in function](https://docs.python.org/3/library/functions.html#breakpoint). It automatically imports `pdb` and calls `pdb.set_trace()`.
diff --git a/decorators.rst b/decorators.rst
index 1b83032..30509fe 100644
--- a/decorators.rst
+++ b/decorators.rst
@@ -273,7 +273,7 @@ Now let's take a look at the areas where decorators really shine and
their usage makes something really easy to manage.
Authorization
-~~~~~~~~~~~~
+~~~~~~~~~~~~~
Decorators can help to check whether someone is authorized to use an
endpoint in a web application. They are extensively used in Flask web
@@ -296,7 +296,7 @@ authentication:
return decorated
Logging
-~~~~~~~~~~~~
+~~~~~~~
Logging is another area where the decorators shine. Here is an example:
@@ -329,7 +329,7 @@ Come to think of it, isn't ``@wraps`` also a decorator? But, it takes an
argument like any normal function can do. So, why can't we do that too?
This is because when you use the ``@my_decorator`` syntax, you are
-applying a wrapper function with a single function as a parameter
+applying a wrapper function with a single function as a parameter.
Remember, everything in Python is an object, and this includes
functions! With that in mind, we can write a function that returns
a wrapper function.
@@ -354,6 +354,7 @@ us specify a logfile to output to.
with open(logfile, 'a') as opened_file:
# Now we log to the specified logfile
opened_file.write(log_string + '\n')
+ return func(*args, **kwargs)
return wrapped_function
return logging_decorator
diff --git a/enumerate.rst b/enumerate.rst
index 277b679..3bcd2f6 100644
--- a/enumerate.rst
+++ b/enumerate.rst
@@ -7,12 +7,19 @@ advanced programmers are unaware of it. It allows us to loop over
something and have an automatic counter. Here is an example:
.. code:: python
+
+ my_list = ['apple', 'banana', 'grapes', 'pear']
+ for counter, value in enumerate(my_list):
+ print counter, value
- for counter, value in enumerate(some_list):
- print(counter, value)
+ # Output:
+ # 0 apple
+ # 1 banana
+ # 2 grapes
+ # 3 pear
-And there is more! ``enumerate`` also accepts an optional argument which
-makes it even more useful.
+And there is more! ``enumerate`` also accepts an optional argument that
+allows us to specify the starting index of the counter.
.. code:: python
@@ -26,9 +33,9 @@ makes it even more useful.
# 3 grapes
# 4 pear
-The optional argument allows us to tell ``enumerate`` from where to
-start the index. You can also create tuples containing the index and
-list item using a list. Here is an example:
+An example of where the optional argument of ``enumerate`` comes in handy
+is creating tuples containing the index and list item using a list. Here
+is an example:
.. code:: python
diff --git a/exceptions.rst b/exceptions.rst
index d6fae82..ebeb0d5 100644
--- a/exceptions.rst
+++ b/exceptions.rst
@@ -5,9 +5,11 @@ Exception handling is an art which once you master grants you immense
powers. I am going to show you some of the ways in which we can handle
exceptions.
-In basic terminology we are aware of ``try/except`` clause. The code
-which can cause an exception to occur is put in the ``try`` block and
+In basic terminology we are aware of the ``try/except`` structure. The code
+that can cause an exception to occur is put in the ``try`` block and
the handling of the exception is implemented in the ``except`` block.
+The code in the ``except`` block will only execute if the ``try`` block
+runs into an exception.
Here is a simple example:
.. code:: python
@@ -60,8 +62,16 @@ trapping ALL exceptions:
# Some logging if you want
raise e
-This can be helpful when you have no idea about the exceptions which may
-be thrown by your program.
+This can be helpful when you have no idea about the exceptions that may
+be thrown by your program. If you are just looking to catch all execptions,
+but don't actually care about what they are, you can even exclude the
+``Exception as e`` part.
+
+Note:: catching all exceptions may have unintended consequences because catching
+all exceptions may also catch the ones you want to occur; for example, in
+many command-line based programs, pressing control+c will terminate the program,
+but if you catch all excepts, the ``KeyboardInterrupt`` will be caught as an
+exception, so pressing control+c will NOT terminate the program.
``finally`` clause
~~~~~~~~~~~~~~~~~~
diff --git a/for_-_else.rst b/for_-_else.rst
index 9a68363..f7fbe82 100644
--- a/for_-_else.rst
+++ b/for_-_else.rst
@@ -1,5 +1,5 @@
``for/else``
-----------
+------------
Loops are an integral part of any language. Likewise ``for`` loops are
an important part of Python. However there are a few things which most
@@ -22,7 +22,7 @@ That is the very basic structure of a ``for`` loop. Now let's move on to
some of the lesser known features of ``for`` loops in Python.
``else`` Clause
-^^^^^^^^^^^^^^^^^^^^
+^^^^^^^^^^^^^^^
``for`` loops also have an ``else`` clause which most of us are unfamiliar
with. The ``else`` clause executes after the loop completes normally.
diff --git a/generators.rst b/generators.rst
index dd983c3..23cd1b0 100644
--- a/generators.rst
+++ b/generators.rst
@@ -134,10 +134,10 @@ element of a sequence. So let's test out our understanding:
As we can see that after yielding all the values ``next()`` caused a
``StopIteration`` error. Basically this error informs us that all the
-values have been yielded. You might be wondering that why don't we get
-this error while using a ``for`` loop? Well the answer is simple. The
+values have been yielded. You might be wondering why we don't get
+this error when using a ``for`` loop? Well the answer is simple. The
``for`` loop automatically catches this error and stops calling
-``next``. Do you know that a few built-in data types in Python also
+``next``. Did you know that a few built-in data types in Python also
support iteration? Let's check it out:
.. code:: python
diff --git a/global_&_return.rst b/global_&_return.rst
index 39a75d4..0661752 100644
--- a/global_&_return.rst
+++ b/global_&_return.rst
@@ -1,9 +1,9 @@
-Global & Return
+Global and Return
---------------
-You might have encountered some functions written in python which have a
+You might have encountered some functions written in Python which have a
``return`` keyword in the end of the function. Do you know what it does? It
-is similar to return in other languages. Lets examine this little
+is similar to return in other languages. Let's examine this little
function:
.. code:: python
@@ -15,7 +15,7 @@ function:
print(result)
# Output: 8
-The function above takes two values as input and then output their
+The function above takes two values as input and then outputs their
addition. We could have also done:
.. code:: python
@@ -28,11 +28,11 @@ addition. We could have also done:
print(result)
# Output: 8
-So first lets talk about the first bit of code which involves the
+So first let's talk about the first bit of code which involves the
``return`` keyword. What that function is doing is that it is assigning
the value to the variable which is calling that function which in our
-case is ``result``. In most cases and you won't need to use the
-``global`` keyword. However lets examine the other bit of code as well
+case is ``result``. In most cases you won't need to use the
+``global`` keyword. However, let's examine the other bit of code as well
which includes the ``global`` keyword. So what that function is doing is
that it is making a global variable ``result``. What does global mean
here? Global variable means that we can access that variable outside the
@@ -125,11 +125,11 @@ Or by more common convention:
print(profile_age)
# Output: 30
-Keep in mind that even in the above example we are returning a tuple (despite the lack of paranthesis) and not separate multiple values. If you want to take it one step further, you can also make use of `namedtuple `_. Here is an example:
+Keep in mind that even in the above example we are returning a tuple (despite the lack of parenthesis) and not separate multiple values. If you want to take it one step further, you can also make use of `namedtuple `_. Here is an example:
.. code:: python
- from collections import namedtuple
+ from collections import namedtuple
def profile():
Person = namedtuple('Person', 'name age')
return Person(name="Danny", age=31)
@@ -157,4 +157,4 @@ Keep in mind that even in the above example we are returning a tuple (despite th
print(age)
#31
-This is a better way to do it along with returning ``lists`` and ``dicts``. Don't use ``global`` keyword unless you know what you are doing. ``global`` might be a better option in a few cases but is not in most of them.
+This is a better way to do it, along with returning ``list`` and ``dict``. Don't use ``global`` keyword unless you know what you are doing. ``global`` might be a better option in a few cases but is not in most of them.
diff --git a/index.rst b/index.rst
index 224ae75..b45de64 100644
--- a/index.rst
+++ b/index.rst
@@ -50,6 +50,7 @@ Table of Contents
virtual_environment
collections
enumerate
+ zip
object_introspection
comprehensions
exceptions
diff --git a/lambdas.rst b/lambdas.rst
index 73328b8..756e260 100644
--- a/lambdas.rst
+++ b/lambdas.rst
@@ -39,5 +39,5 @@ they are used in the wild:
.. code:: python
data = zip(list1, list2)
- data.sort()
+ data = sorted(data)
list1, list2 = map(lambda t: list(t), zip(*data))
diff --git a/python_c_extension.rst b/python_c_extension.rst
index 368d60b..f4cf5d4 100644
--- a/python_c_extension.rst
+++ b/python_c_extension.rst
@@ -6,7 +6,7 @@ implementation is the ease of interfacing C code to Python.
There are three key methods developers use to call C functions from
their python code - ``ctypes``, ``SWIG`` and ``Python/C API``. Each
-method comes with it's own merits and demerits.
+method comes with its own merits and demerits.
Firstly, why would you want to interface C with Python?
@@ -36,8 +36,6 @@ Simple C code to add two numbers, save it as ``add.c``
//sample C file to add 2 numbers - int and floats
- #include
-
int add_int(int, int);
float add_float(float, float);
@@ -194,7 +192,7 @@ Python/C API
---------------
The `C/Python API `__ is probably the
-most widely used method - not for it's simplicity but for the fact that
+most widely used method - not for its simplicity but for the fact that
you can manipulate python objects in your C code.
This method requires your C code to be specifically written for
@@ -229,7 +227,7 @@ the addList module is not written in Python at all, but rather in C.
Next we'll have a look at the C code that get's built into the
``addList`` Python module. This may seem a bit daunting at first, but
once you understand the various components that go into writing the C
-file, it's pretty straight forward.
+file, it's pretty straightforward.
*adder.c*
diff --git a/ternary_operators.rst b/ternary_operators.rst
index 7e7dec2..6f9cbbc 100644
--- a/ternary_operators.rst
+++ b/ternary_operators.rst
@@ -12,7 +12,7 @@ expressions.
.. code:: python
- condition_if_true if condition else condition_if_false
+ value_if_true if condition else value_if_false
**Example:**
@@ -100,4 +100,14 @@ This is helpful in case where you quickly want to check for the output of a func
>>> print(msg)
No data returned
+Or as a simple way to define function parameters with dynamic default values:
+.. code:: python
+
+ >>> def my_function(real_name, optional_display_name=None):
+ >>> optional_display_name = optional_display_name or real_name
+ >>> print(optional_display_name)
+ >>> my_function("John")
+ John
+ >>> my_function("Mike", "anonymous123")
+ anonymous123
diff --git a/zip.rst b/zip.rst
new file mode 100644
index 0000000..947fe2a
--- /dev/null
+++ b/zip.rst
@@ -0,0 +1,71 @@
+Zip and unzip
+-------------
+
+**Zip**
+
+Zip is a useful function that allows you to combine two lists easily.
+
+After calling zip, an iterator is returned. In order to see the content wrapped inside, we need to first convert it to a list.
+
+Example:
+
+.. code:: python
+
+ first_name = ['Joe','Earnst','Thomas','Martin','Charles']
+
+ last_name = ['Schmoe','Ehlmann','Fischer','Walter','Rogan','Green']
+
+ age = [23, 65, 11, 36, 83]
+
+ print(list(zip(first_name,last_name, age)))
+
+ # Output
+ #
+ # [('Joe', 'Schmoe', 23), ('Earnst', 'Ehlmann', 65), ('Thomas', 'Fischer', 11), ('Martin', 'Walter', 36), ('Charles', 'Rogan', 83)]
+
+One advantage of zip is that it improves readability of for loops.
+
+For example, instead of needing multiple inputs, you only need one zipped list for the following for loop:
+
+.. code:: python
+
+ first_name = ['Joe','Earnst','Thomas','Martin','Charles']
+ last_name = ['Schmoe','Ehlmann','Fischer','Walter','Rogan','Green']
+ age = [23, 65, 11, 36, 83]
+
+ for first_name, last_name, age in zip(first_name, last_name, age):
+ print(f"{first_name} {last_name} is {age} years old")
+
+ # Output
+ #
+ # Joe Schmoe is 23 years old
+ # Earnst Ehlmann is 65 years old
+ # Thomas Fischer is 11 years old
+ # Martin Walter is 36 years old
+ # Charles Rogan is 83 years old
+
+**Unzip**
+
+We can use the `zip` function to unzip a list as well. This time, we need an input of a list with an asterisk before it.
+
+The outputs are the separated lists.
+
+Example:
+
+.. code:: python
+
+ full_name_list = [('Joe', 'Schmoe', 23),
+ ('Earnst', 'Ehlmann', 65),
+ ('Thomas', 'Fischer', 11),
+ ('Martin', 'Walter', 36),
+ ('Charles', 'Rogan', 83)]
+
+ first_name, last_name, age = list(zip(*full_name_list))
+ print(f"first name: {first_name}\nlast name: {last_name} \nage: {age}")
+
+ # Output
+
+ # first name: ('Joe', 'Earnst', 'Thomas', 'Martin', 'Charles')
+ # last name: ('Schmoe', 'Ehlmann', 'Fischer', 'Walter', 'Rogan')
+ # age: (23, 65, 11, 36, 83)
+