Quantcast
Channel: Planet Python
Viewing all 22419 articles
Browse latest View live

Mike Driscoll: Python 101: Learning About Lists

$
0
0

Lists are a fundamental data type in the Python programming language. A list is a mutable sequence that is typically a collection of homogeneous items. Mutable means that you can change a list after its creation. You will frequently see lists that contain other lists. These are known as nested lists. You will also see lists that contain all manner of other data types, such as dictionaries, tuples or objects.

Let’s find out how you can create a list!

Creating Lists

There are several ways to create a list. You may construct a list in any of the following ways:

  • Using a pair of square brackets with nothing inside creates an empty list: []
  • Using square brackets with comma-separated items: [1, 2, 3]
  • Using a list comprehension: [x for x in iterable]
  • Using the list() function: list(iterable)

An iterable is a sequence, a container that supports iteration or an iterator object. Lists themselves are sequences as are strings.

Let’s look at a few examples of creating a list so you can see it in action:

>>> my_list = [1, 2, 3]
>>> my_list
[1, 2, 3]

This first example is pretty straight-forward. Here you create a list with 3 numbers in it. Then you print it out to verify that it contains what you think it should.

The next way to create a list is by using Python’s built-in list() function:

>>> list_of_strings = list('abc')
>>> list_of_strings
['a', 'b', 'c']

In this case, you pass a string of three letters to the list() function. It automatically iterates over the characters in the string to create a list of three string, where each string is a single character.

The last example to look at is how to create empty lists:

>>> empty_list = []
>>> empty_list
[]
>>> another_empty_list = list()
>>> another_empty_list
[]

The quickest way to create an empty list is by using the square brackets without putting anything inside them. The second easiest way is to call list() without any arguments. The nice thing about using list() in general is that you can use it to cast a compatible data type to a list, as you did with the string, “abc”, in the example earlier.

List Methods

A Python list has several methods that you can call. Here is a listing of the methods you can use with a list:

  • append()
  • clear()
  • copy()
  • count()
  • extend()
  • index()
  • insert()
  • pop()
  • remove()
  • reverse()
  • sort()

Most of these will be covered in the following sections. Let’s talk about the ones that aren’t covered in a specific section first.

You can use count() to count the number of instances of the object that you passed in.

Here is an example:

>>> my_list = list('abcc')
>>> my_list.count('a')
1
>>> my_list.count('c')
2

This is a simple way to count the number of occurrences of an item in a list.

The index() method is useful for finding the first instance of an item in a list:

>>> my_list = list('abcc')
>>> my_list.index('c')
2
>>> my_list.index('a')
0

Python lists are zero-indexed, so “a” is in position 0, “b” is at position 1, etc.

You can use the reverse() method to reverse a list in-place:

>>> my_list = list('abcc')
>>> my_list.reverse()
>>> my_list
['c', 'c', 'b', 'a']

Note that the reverse() method returns None. What that means is that if you try to assign the reversed list to a new variable, you may end up with something unexpected:

>>> x = my_list.reverse()
>>> print(x)
None

Here you end up with None instead of the reversed list. That is what in-place means. The original list is reversed, but the reverse() method itself doesn’t return anything.

Now let’s find out what you can do with the other list methods!

Adding to a List

There are three list methods that you can use to add to a list. They are as follows:

  • append()
  • extend()
  • insert()

The append() method will add an item to the end of a pre-existing list:

>>> my_list = list('abcc')
>>> my_list
['a', 'b', 'c', 'c']
>>> my_list.append(1)
>>> my_list
['a', 'b', 'c', 'c', 1]

First you create a list that is made up of four one-character strings. Then you append an integer to the end of the list. Now the list should have 5 items in it with the 1 on the end.

You can use Python’s built-in len() function to check the number of items in a list:

>>> len(my_list)
5

So this tells you that you do in fact have five items in the list. But what if you wanted to add an element somewhere other than the end of the list?

You can use insert() for that:

>>> my_list.insert(0, 'first')
>>> my_list
['first', 'a', 'b', 'c', 'c', 1]

The insert() method takes two arguments:

  • The position at which to insert
  • The item to insert

In the code above, you tell Python that you want to insert the string, “first”, into the 0 position, which is the first position in the list.

There are two other ways to add items to a list. You can add an iterable to a list using extend():

>>> my_list = [1, 2, 3]
>>> other_list = [4, 5, 6]
>>> my_list.extend(other_list)
>>> my_list
[1, 2, 3, 4, 5, 6]

Here you create two lists. Then you use my_list‘s extend() method to add the items in other_list to my_list. extend() will iterate over the items in the passed in list and add each of them to the list.

You can also combine lists using concatenation:

>>> my_list = [1, 2, 3]
>>> other_list = [4, 5, 6]
>>> combined = my_list + other_list
>>> combined
[1, 2, 3, 4, 5, 6]

In this case, you create two lists and then combine them using Python’s + operator.

You can also use += with Python lists:

>>> my_list = [1, 2, 3]
>>> other_list = [4, 5, 6]
>>> my_list += other_list
>>> my_list
[1, 2, 3, 4, 5, 6]

This is a somewhat simpler way to combine the two lists.

Now let’s learn how to access and change elements within a list.

Accessing and Changing List Elements

Lists are made to be worked with. You will need to learn how to access individual elements as well as how to change them.

Let’s start by learning how to access an item:

>>> my_list = [1, 2, 3]
>>> my_list[0]
1
>>> my_list[2]
3

To access an item in a list, you need to use square braces and pass in the index of the item that you wish to access. In the example above, you access the first and third elements.

Lists also support accessing items in reverse by using negative values:

>>> my_list[-1]
3

This example demonstrates that when you pass in -1, you get the last item in the list returned. Try using some other values and see if you can get the first item using negative indexing.

If you try to use an index that does not exist in the list, you will get an IndexError:

>>> my_list[-5]
Traceback (most recent call last):
Python Shell, prompt 41, line 1
builtins.IndexError: list index out of range

Now let’s learn about removing items!

Deleting From a List

Deleting items from a list is pretty straight-forward. There are 4 primary methods of removing items from a list:

  • clear()
  • pop()
  • remove()
  • del

You can use clear() to remove everything from the list. Let’s see how that works:

>>> my_list = [1, 2, 3]
>>> my_list.clear()
>>> my_list
[]

After calling clear(), the list is now empty. This can be useful when you have finished working on the items in the list and you need to start over from scratch. Of course, you could also do this instead of clear():

>> my_list = []

This will create a new empty list. If it is important for you to always use the same object, then using clear() would be better. If that does not matter, then setting it to an empty list will work well too.

If you would rather remove individual items, then you should check out pop() or remove(). Let’s start with pop():

>>> my_list = [1, 2, 3]
>>> my_list.pop()
3
>>> my_list
[1, 2]

You can pass an index to pop() to remove an item and return it. Or you can call pop() without an argument like in the example above and it will default to removing the last item in the list and returning it. pop() is the most flexible way of removing items from a list.

If the list is empty or you pass in an index that does not exist, pop() will throw an exception:

>>> my_list.pop(10)
Traceback (most recent call last):
  Python Shell, prompt 50, line 1
builtins.IndexError: pop index out of range

Now let’s take a look at how remove() works:

>>> my_list = [1, 2, 3]
>>> my_list.remove(2)
>>> my_list
[1, 3]

remove() will delete the first instance of the passed in item. So in this case, you tell the list to remove the first occurrence of the number 2.

If you tell remove() to delete an item that is not in the list, you will receive an exception:

>>> my_list.remove(4)
Traceback (most recent call last):
  Python Shell, prompt 51, line 1
builtins.ValueError: list.remove(x): x not in list

You can also use Python’s built-in del keyword to delete items from a list:

>>> my_list.remove(4)
Traceback (most recent call last):
  Python Shell, prompt 51, line 1
builtins.ValueError: list.remove(x): x not in list

You can also use Python’s built-in del keyword to delete items from a list:

>>> my_list = [1, 2, 3]
>>> del my_list[1]
>>> my_list
[1, 3]

You will receive an error if you try to remove an index that does not exist:

>>> my_list = [1, 2, 3]
>>> del my_list[6]
Traceback (most recent call last):
  Python Shell, prompt 296, line 1
builtins.IndexError: list assignment index out of range

Now let’s learn about sorting a list!

Sorting a List

Lists in Python can be sorted. You can use the built-in sort() method to sort a list in-place or you can use Python’s sorted() function.

Let’s create a list and try sorting it:

>>> my_list = [4, 10, 2, 1, 23, 9]
>>> my_list.sort()
>>> my_list
[1, 2, 4, 9, 10, 23]

Here you create a list with 6 integers in a pretty random order. To sort the list, you call its sort() method, which will sort it in-place. What that means is that sort() does not return anything.

A common misconception with Python is that if you call sort(), you can assign the result to a variable, like this:

>>> sorted_list = my_list.sort()
>>> print(sorted_list)
None

However, when you do that, you will see that sort() doesn’t actually return a sorted list. It always returns None.

Fortunately you can use Python’s built-in sorted() method for this too:

>>> my_list = [4, 10, 2, 1, 23, 9]
>>> sorted_list = sorted(my_list)
>>> sorted_list
[1, 2, 4, 9, 10, 23]

If you use sorted(), it will return a new list, sorted ascending by default. The sorted() function will also allow you to sort by a specified key and you can tell it to sort ascending or descending by setting its reversed flag.

Let’s sort this list in descending order instead:

>>> my_list = [4, 10, 2, 1, 23, 9]
>>> sorted_list = sorted(my_list, reverse=True)
>>> sorted_list
[23, 10, 9, 4, 2, 1]

When you have a more complicated data structure, such as a nested list or a dictionary, you can use sorted() to sort in special ways, such as by key or by value.

List Slicing

Python lists support the idea of slicing. Slicing a list is done by using square brackets and entering a start and stop value. For example, if you had my_list[1:3], you would be saying that you want to create a new list with the element starting at index one through 3 but not including index 3.

Here is an example:

>>> my_list = [4, 10, 2, 1, 23, 9]
>>> my_list[1:3]
[10, 2]

This slice returns index 1 (10) and index 2 (2) as a new list.

You can also use negative values to slice:

>>> my_list = [4, 10, 2, 1, 23, 9]
>>> my_list[-2:]
[23, 9]

In this example, you didn’t specify an end value. That means you want to start at the second to last item in the list, 23, and take it to the end of the list.

Let’s try another example where you specify only the end index:

>>> my_list = [4, 10, 2, 1, 23, 9]
>>> my_list[:3]
[4, 10, 2]

In this example, you want to grab all the values starting at index 0 up to but not including index 3.

Copying a List

Occasionally you will want to copy a list. One simple way to copy your list is to use the copy method:

>>> my_list = [1, 2, 3]
>>> new_list = my_list.copy()
>>> new_list
[1, 2, 3]

This successfully creates a new list and assigns it to the variable, new_list.

However note that when you do this, you are creating what is known as a “shallow copy”. What that means is that if you were to have objects in your list, they can be changed and it will affect both lists. For example, if you had a dictionary in your list and the dictionary was modified, both lists will change, which may not be what you want.

You can also copy a list by using this funny syntax:

>>> my_list = [1, 2, 3]
>>> new_list = my_list[:]
>>> new_list
[1, 2, 3]

This example is telling Python to create a slice from the 0 (first) element to the last, which in effect is the copy of the whole list.

You could also use Python’s list() function to copy a list:

>>> my_list = [1, 2, 3]
>>> new_list = list(my_list)
>>> new_list
[1, 2, 3]

No matter which method you choose though, whether it by [:], copy() or list(), all three will do a shallow copy. If you run into weird issues where changing one list affects the copied list, then you should use deepcopy method from the copy module instead.

Wrapping Up

In this article, you learned all about Python’s wonderful list data type. You will be using lists extensively when you are programming in Python. Here you learned how to create lists, edit them and remove items from them. You learned how to clear a list completely. You discovered how to sort a list as well as how to slice a list. Finally, you learned all about copying lists and the pitfalls that can happen when you do so.

The post Python 101: Learning About Lists appeared first on The Mouse Vs. The Python.


NumFOCUS: Statement on Coronavirus

$
0
0

As you are aware, the Coronavirus (COVID-19) is a topic of frequent and ongoing discussions. We would like to provide an update on our status and policies as well as provide resources for additional information. As of today, our event schedule remains as posted on event sites. Any changes or updates will be immediately shared. […]

The post Statement on Coronavirus appeared first on NumFOCUS.

PyCoder’s Weekly: Issue #411 (March 10, 2020)

$
0
0

#411 – MARCH 10, 2020
View in Browser »

The PyCoder’s Weekly Logo


Post-Mortem Python Plotting

Who loves debugging things that only fail occasionally? Just me? Maybe you need to check out Andy Jones’ extract() function that “magically” extracts a caller’s environment into an IPython interpreter session. Mix in a little post-mortem debugging with Jupyter’s %debug magic command, and you’ll be painlessly debugging finicky code in no time.
ANDY JONES

How to Use Jupyter Notebooks in 2020

In this first of a three-part blog post, LJ Miranda surveys the data science landscape and discusses the forces that push data science tools to evolve.
LJ MIRANDA

Python Developers Are in Demand on Vettery

alt

Vettery is an online hiring marketplace that’s changing the way people hire and get hired. Ready for a bold career move? Make a free profile, name your salary, and connect with hiring managers from top employers today →
VETTERYsponsor

Thinking psycopg3

A core maintainer of the popular psycopg2 PostgreSQL adapter for Python discusses breaking changes he would like to see in a hypothetical pyscopg3 project, including better query/parameter separation, more sensible context manager behavior with connections, and async support.
DANIELE VARRAZZO

Alexa Python Development: Build and Deploy an Alexa Skill

In this tutorial, you’ll become an Alexa Python developer by deploying your own Alexa skill. You’ll build an application that users will interact with using voice commands to Amazon Alexa devices. Your skill will respond back with a random joke when invoked by the user!
REAL PYTHON

PyCon 2020 Update on COVID-19

“PyCon continues to closely monitor the Coronavirus (also known as COVID-19) situation. As of March 6, PyCon 2020 in Pittsburgh, Pennsylvania is scheduled to take place.”
PYCON.BLOGSPOT.COM

Discussions

About the “Add Python 3.X to PATH” Checkbox in the Windows CPython Installer…

An epic Twitter thread. It’s still active almost two weeks later, with tons of heavyweights chiming in.
TWITTER.COM/BITECODE_DEV

What Causes [*a] to Overallocate?

Stefan Pochmann investigates memory allocation for three methods of creating a list from an iterable a: list(a), [x for x in a], and [*a]. The last method, [*a], always overallocates memory for the list.
STACK OVERFLOW

Python Jobs

Senior Python/Django Software Engineer (London, UK)

Zego

Senior Python Software Engineer (London, UK)

Tessian

Senior Software Engineer Backend (Denver, CO, USA)

CyberGRX

More Python Jobs >>>

Articles & Tutorials

Python in GitHub Actions

“GitHub’s own CI called GitHub Actions has been out of closed beta for a while and offers generous free quotas and a seamless integration with the rest of the site. Let’s have a look on how to use it for an open source Python package.”
HYNEK SCHLAWACK

Mocking Asynchronous Functions in Python

As the adoption of asynchronous Python grows, the ability to reliably test asynchronous code is increasingly important. In this tutorial, Dino Costa shows you how to leverage Future objects in Python 3.7 and the AsyncMock object added in Python 3.8 to easily test asynchronous functions.
DINO COSTA

Become a Python Guru With PyCharm

alt

PyCharm is the Python IDE for Professional Developers by JetBrains providing a complete set of tools for productive Python, Web and scientific development. Be more productive and save time while PyCharm takes care of the routine →
JETBRAINSsponsor

Syntactic Unification Is Easy!

Syntactic unification is the process of solving equations between symbolic expressions. Unification has applications in type systems and logic programming. In this article, Cassie Jones shows you how to implement a unification algorithm in just 30 lines of Python!
CASSIE JONES

Defining Your Own Python Functions

In this beginner tutorial, you’ll learn how to define and call your own Python functions. You’ll also learn about passing data to your function, and returning data from your function back to its calling environment.
REAL PYTHON

One Impact of the Dropping of Python 2 From Linux Distributions

“Everyone’s insistence on getting rid of Python 2 is magically transforming all of this perfectly functional and useful Python 2 code we have from an asset to a liability. You can imagine how I feel about that.”
CHRIS SIEBENMANNopinion

Understand Django: Views On Views

Django URLs expect to send a response back to a user.  Where does that response come from?  A Django view. This article looks into the fundamentals of views and how to use them in your project.
MATT LAYMAN• Shared by Matt Layman

Gradient Descent From Scratch

Gradient descent is one of the most fundamental optimization techniques used in machine learning. Learn the ins and outs of gradient descent by implementing it from scratch in Python.
PHILIPP MUENS

We Have to Talk About This Python, Gunicorn, Gevent Thing

“Here’s what happens when you build around Python, Gunicorn, Gevent, and web requests instead of something more sensible.” Although pessimistic, this was an interesting read.
RACHELBYTHEBAY.COMopinion

Defining Main Functions in Python

Learn how Python main functions are used and some best practices to organize your code so it can be executed as a script and imported from another module.
REAL PYTHONvideo

Open Source AutoML for Developers

Building & deploying machine learning can be painful. MindsDB enables developers to easily integrate ML into their projects without the need to involve a data scientist or ML expert. Check out our project on GitHub.
MINDSDBsponsor

Episode #171: Chilled Out Python Decorators With PEP 614

Real Python and PyCoder’s own David Amos guest hosts Python Bytes, talking about PEP 614, macOS menu bar apps with Python, test coverage, and more.
PYTHON BYTESpodcast

Bundling Python Dependencies in a ZIP Archive

Shipping dependencies for your scripts as a single file, built with shiv.
JÜRGEN HERMANN• Shared by Jürgen Hermann

Projects & Code

Events

PyMNTos

March 12, 2020
PYTHON.MN

Python Miami

March 14 to March 15, 2020
PYTHONDEVELOPERSMIAMI.COM


Happy Pythoning!
This was PyCoder’s Weekly Issue #411.
View in Browser »

alt

[ Subscribe to 🐍 PyCoder’s Weekly 💌 – Get the best Python news, articles, and tutorials delivered to your inbox once a week >> Click here to learn more ]

eGenix.com: PyDDF Python Spring Sprint 2020

$
0
0

The following text is in German, since we're announcing a Python sprint in Düsseldorf, Germany.

Ankündigung

PyDDF Python Spring Sprint 2020 in
Düsseldorf


Samstag, 28.03.2020, 10:00-18:00 Uhr
Sonntag, 29.03.2020, 10:00-18:00 Uhr

trivago N.V., Kesselstrasse 5-7, 40221 Düsseldorf

Informationen

Das Python Meeting Düsseldorf (PyDDF) veranstaltet mit freundlicher Unterstützung der trivago N.V. ein Python Sprint Wochenende.

Der Sprint findet am Wochenende 28./29.3.2020 in der trivago Niederlassung im Medienhafen Düsseldorf statt (Achtung: Nicht mehr am Karl-Arnold-Platz).Folgende Themengebiete sind als Anregung bereits angedacht:
    • Aufzugsimulator
    • Wegeheld
    Natürlich kann jeder Teilnehmer weitere Themen vorschlagen und umsetzen.

      Anmeldung und weitere Infos

      Alles weitere und die Anmeldung findet Ihr auf der Sprint Seite:

      WICHTIG: Ohne Anmeldung können wir kein Badge für den Gebäudezugang bereitstellen lassen. Eine spontane Anmeldung am Sprint Tag wird daher vermutlich nicht funktionieren. Also bitte unbedingt mit vollen Namen bis spätestens Mittwoch, 25.03., anmelden.

      Teilnehmer sollten sich zudem auf der PyDDF Liste anmelden, da wir uns dort koordinieren:

        Über das Python Meeting Düsseldorf

        Das Python Meeting Düsseldorf ist eine regelmäßige Veranstaltung in Düsseldorf, die sich an Python Begeisterte aus der Region wendet.

        Einen guten Überblick über die Vorträge bietet unser PyDDF YouTube-Kanal, auf dem wir Videos der Vorträge nach den Meetings veröffentlichen.

        Veranstaltet wird das Meeting von der eGenix.com GmbH, Langenfeld, in Zusammenarbeit mit Clark Consulting & Research, Düsseldorf.

        Viel Spaß !

        Marc-Andre Lemburg, eGenix.com

        Anarcat: Font changes

        $
        0
        0

        I have worked a bit on the fonts I use recently. From the main font I use every day in my text editor and terminals to this very website, I did a major and (hopefully) thoughtful overhaul of my typography, in the hope of making things easier to use and, to be honest, just prettier.

        Monospace font: Fira mono

        This all started when I found out about the JetbrainsMono font. I found the idea of ligatures fascinating: the result is truly beautiful. So I do what I often do (sometimes to the despair of some fellow Debian members) and filed a RFP to document my research.

        As it turns out, Jetbrains Mono is not free enough to be packaged in Debian, because it requires proprietary tools to build. I nevertheless figured I could try another font so I looked at other monospace alternatives. I found the following packages in debian:

        Those are also "programmer fonts" that caught my interest but somehow didn't land in Debian yet:

        Because Fira code had ligatures, i ended up giving it a shot. I really like the originality of the font. See, for example, how the @ sign looks when compared to my previous font, Liberation Mono:

        A dark
terminal window showing the prompt
'[SIGPIPE]anarcat@angela:~(master)$' in the Liberation Mono font Liberation Mono

        A dark
terminal window showing the prompt
'[SIGPIPE]anarcat@angela:~(master)$' in the Fira mono font Fira Mono

        Interestingly, a colleague (thanks ahf!) pointed me to the Practical Typography post "Ligatures in programming fonts: hell no", which makes the very convincing argument that ligatures are downright dangerous to programming environment. In my experiences with the fonts, it was also not always giving the result I would expect. I also remembered that the Emacs Haskell mode would have this tendency of inserting crazy syntactic sugar like this in source code without being asked, which I found extremely frustrating.

        Besides, Emacs doesn't support ligatures, unless you count such horrendous hacks which hack at the display time. That's because Emacs' display layer is not based on a modern rendering library like Pango but some scary legacy code that very few people understand. On top of the complexity of the codebase, there is also resistance in including a modern font.

        So I ended up using Fira mono everywhere I use fixed-width fonts, even though it's not packaged in Debian. That involves the following configuration in my .Xresources (no, I haven't switched to Wayland):

        ! font settings
        Emacs*font: Fira mono
        rofi*font: Fira mono 12
        ! Symbola is to get emojis to display correctly, apt install fonts-symbola
        !URxvt*font: xft:Monospace,xft:Symbola
        URxvt*font: xft:Fira mono,xft:Symbola
        

        I also dropped this script in ~/.local/share/fonts/download.sh, for lack of a better way, to download all the fonts I'm interested in:

        #!/bin/sh
        
        set -e
        set -u
        
        wget --no-clobber --continue https://practicaltypography.com/fonts/charter.zip
        unzip -u charter.zip
        wget --no-clobber --continue https://github.com/adobe-fonts/source-serif-pro/releases/download/3.001R/source-serif-pro-3.001R.zip
        unzip -u source-serif-pro-3.001R.zip
        wget --no-clobber --continue https://github.com/adobe-fonts/source-sans-pro/releases/download/3.006R/source-sans-pro-3.006R.zip
        unzip -u source-sans-pro-3.006R.zip
        wget --no-clobber --continue https://github.com/adobe-fonts/source-code-pro/releases/download/2.030R-ro%2F1.050R-it/source-code-pro-2.030R-ro-1.050R-it.zip
        unzip -u source-code-pro-2.030R-ro-1.050R-it.zip
        wget --no-clobber --continue -O Fira-4.202.zip https://github.com/mozilla/Fira/archive/4.202.zip || true
        unzip -u Fira-4.202.zip
        

        Website font changes

        That "hell no" article got me interested in the Practical Typography web book, which I read over the weekend. It was an eye opener and I realized I had already some of those concepts implanted; in fact it's probably after reading the Typography in ten minutes guide that I ended up trying Fira sans a few years ago. I have removed that font since then, however, after realising it was taking up an order of magnitude more bandwidth space than the actual page content.

        I really loved the book, so much that I actually bought it. I liked the concept of it, the look, and the fact that it's a living document. There's a lot of typography work I would need to do on this site to catchup with the recommendations from Matthew Butterick. Switching fonts is only one part of this, but it's something I was excited to work on. So I sat down and reviewed the free fonts Butterick recommends and tried out a few. I ended up settling on Charter, a relatively old (in terms of computing) font designed by Matthew Carter (of Verdana fame) in 1987.

        Charter really looks great and is surprisingly small. While a single version of Fira varies between 96KiB (Fira Sans Condensed) and 308KiB (Fira Sans Medium Italic), Charter is only 28KiB! While it's still about as large as most of my articles, I found it was a better compromise and decided to make the jump. This site is now in Serif, which is a huge change for me.

        The change was done with the following CSS:

        h1, h2, h3, h4, h5, body {
            /* 
             * Charter: Butterick's favorite, freely available, found on https://practicaltypography.com/free-fonts.html
             * Palatino: Mac OS
             * Palatino Linotype: Windows
             * Noto serif: Android, packaged in Debian
             * Liberation serif: Linux fallback
             * Serif: fallback
             */
            font-family: Charter, Palatino, "Palatino Linotype", "Noto serif", "Liberation serif", serif;
            /* Charter is available from https://practicaltypography.com/charter.html under the liberal Bitstream license */
        }
        

        I have also decided to outline headings by making them slanted, using the beautiful italic version of Charter:

        h1, h2, h3, h4, h5 {
            font-style: italic;
        }
        

        I also made the point size larger, if the display is large enough:

        /* enlarge body point size for charter for larger displays */
        @media (min-device-width: 750px) {
            body {
                font-size: 20px;
                line-height: 1.3; /* default in FF is ~1.48 */
            }
        }
        

        Modern display (including fonts) have a much higher resolution and the point size on my website was really getting too small to be readable. This, in turn, required a change to the max-width:

        #content {
            /* about 2.5 alphabets with charter */
            max-width: 35em;
        }
        

        I have kept the footers and "UI" elements in sans-serif though, and kept those aligned on operating system defaults or "system fonts":

        /* some hacking at typefaces to get some fresh zest in here
         * fallbacks from:
         * https://en.wikipedia.org/wiki/List_of_typefaces_included_with_Microsoft_Windows
         * https://en.wikipedia.org/wiki/List_of_typefaces_included_with_macOS
         */
        .navbar, .footer {
            /*
             * Avenir: Mac, quite different but should still be pretty
             * Gill sans: Mac, Windows, somewhat similar to Avenir (indulge me)
             * Noto sans: Android, packaged in Debian
             * Open sans: Texlive extras AKA Linux, packaged in Debian
             * Fira sans: Mozilla's Firefox OS
             * Liberation sans: Linux fallback
             * Helvetica: general fallback
             * Sans-serif: fallback
             */
            font-family: Avenir, "Gill sans", "Noto sans", "Open sans", "Fira sans", "Liberation sans", Helvetica, sans-serif;
            /* Fira is available from https://github.com/mozilla/Fira/ under the SIL Open Font License */
            /* alternatively, just use system fonts for "controls" instead:
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
            gitlab uses: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Noto Sans", Ubuntu, Cantarell, "Helvetica Neue", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"
            */
        }
        

        I've only done some preliminary testing of how this will look like. Although I tested on a few devices (my phone, e-book tablet, an iPad, and of course my laptop), I fully expect things to break on your device. Do let me know if things look better or worse. For future comparison, my site is well indexed in the Internet Wayback Machine and can be used to look at the site before the change.

        The changes to the theme are of course available in my custom ikiwiki bootstrap theme (see in particular commits 0bca0fb7 and d1901fb8), as usual.

        Enjoy, and let me know what you think!

        PS: I considered just setting the Charter font in CSS and not adding it as a @font-face. I'm still considering that option and might do so if the performance cost is too big. The Fira mono font is actually set like this for the preformatted sections of the site, but because it's more common (and it's too big) I haven't added it as a font-face. You might want to download the font locally to benefit from the full experience as well.

        Karim Elghamrawy: Private Methods in Python

        $
        0
        0

        Let me preface this article by emphasizing that understanding object-oriented programming (OOP) is crucial if you want to learn Python. One aspect of OOP is to learn how to define and use private methods. In this article, I will teach you how to create private methods, when to use them, and why they are necessary. [...]

        The post Private Methods in Python appeared first on Afternerd.

        Test and Code: 105: TAP: Test Anything Protocol - Matt Layman

        $
        0
        0

        The Test Anything Protocol, or TAP, is a way to record test results in a language agnostic way, predates XML by about 10 years, and is still alive and kicking.

        Matt Layman has contributed to Python in many ways, including his educational newsletter, and his Django podcast, Django Riffs.

        Matt is also the maintainer of tap.py and pytest-tap, two tools that bring the Test Anything Protocol to Python.

        In this episode, Matt and I discuss TAP, it's history, his involvement, and some cool use cases for it.

        Special Guest: Matt Layman.

        Sponsored By:

        Support Test & Code : Python Testing for Software Engineers

        Links:

        <p>The Test Anything Protocol, or TAP, is a way to record test results in a language agnostic way, predates XML by about 10 years, and is still alive and kicking.</p> <p>Matt Layman has contributed to Python in many ways, including his educational newsletter, and his Django podcast, Django Riffs.</p> <p>Matt is also the maintainer of tap.py and pytest-tap, two tools that bring the Test Anything Protocol to Python.</p> <p>In this episode, Matt and I discuss TAP, it&#39;s history, his involvement, and some cool use cases for it.</p><p>Special Guest: Matt Layman.</p><p>Sponsored By:</p><ul><li><a href="https://testandcode.com/pycharm" rel="nofollow">PyCharm Professional</a>: <a href="https://testandcode.com/pycharm" rel="nofollow">Try PyCharm Pro for 4 months and learn how PyCharm will save you time.</a> Promo Code: TESTNCODE2020</li></ul><p><a href="https://www.patreon.com/testpodcast" rel="payment">Support Test & Code : Python Testing for Software Engineers</a></p><p>Links:</p><ul><li><a href="https://www.mattlayman.com/" title="mattlayman.com" rel="nofollow">mattlayman.com</a></li><li><a href="https://www.mattlayman.com/blog/2020/django-riffs-podcast/" title="Django Riffs, a podcast for learning Django · Matt Layman" rel="nofollow">Django Riffs, a podcast for learning Django · Matt Layman</a></li><li><a href="https://testanything.org/" title="Test Anything Protocol" rel="nofollow">Test Anything Protocol</a></li><li><a href="https://github.com/python-tap/pytest-tap" title="pytest-tap: Test Anything Protocol (TAP) reporting plugin for pytest" rel="nofollow">pytest-tap: Test Anything Protocol (TAP) reporting plugin for pytest</a></li><li><a href="https://tappy.readthedocs.io/en/latest/" title="tappy - TAP tools for Python " rel="nofollow">tappy - TAP tools for Python </a></li></ul>

        Quansight Labs Blog: Planned architectural work for PyData/Sparse

        $
        0
        0

        What have we been doing so far? 🤔

        Research 📚

        A lot of behind the scenes work has been taking place on PyData/Sparse. Not so much in terms of code, more in terms of research and community/team building. I've more-or-less decided to use the structure and the research behind the Tensor Algebra Compiler, the work of Fredrik Kjolstad and his collaborators at MIT. 🙇🏻‍♂️ To this end, I've read/watched the following talks and papers:

        Read more… (2 min remaining to read)


        Roberto Alsina: Episodio 34: Python moderno 5: 1,2,3,4 ... Probando Enums!

        $
        0
        0

        Enums en Python ni siquiera son tan nuevos, están desde Python 3.4 pero SE USAN DEMASIADO POCO.

        Y es una pena, porque permiten resolver muchos problemas de manera más robusta que lo que sea que estás haciendo ahora. Incluye un ejemplo de un "switch" basado en enums.

        Wing Tips: Goto-Definition From the Interactive Shells in Wing Pro

        $
        0
        0

        In this Wing Tip we'll take a quick look at a lesser-known but often useful feature in Wing Pro: Jumping from symbols in the integrated shells to their point of definition in source code. This makes it a snap to bridge from runtime symbols to the source code where they are actually defined and used.

        Debug Console Example

        In this example, the debugger is stopped and I'm working in the DebugConsole, which is an interactive shell that runs in the context of the currently selected debug stack frame. While trying to determine why handler.exit_status is None, I jump to its point of definition from the right-click context menu:

        /images/blog/goto-definition-in-shells/debug-console.gif

        From here, I could set a breakpoint and restart debug, or right-click on the editor to select FindPointsofUse to see all the points of use of exit_status.

        Python Shell Example

        Similarly, I can import a module in the PythonShell and jump to the point of definition of symbols in the module. Here I'm using this technique to bring up the source code for numpy's ndarray:

        /images/blog/goto-definition-in-shells/python-shell.gif

        In this case, I'm pressing F4 to go to the definition, rather than using the right-click context menu.

        Traversing Visit History

        To get back from the point of definition to the previously displayed code in the editor, use the browser-like forward/back arrow buttons in the top left of the editor:

        /images/blog/goto-definition-in-shells/back-arrows.png

        Pressing Alt-Left or using any other key binding for the command visit-history-previous also goes back in the editor's visit history.



        That's it for now! We'll be back soon with more Wing Tips for Wing Python IDE.

        As always, please don't hesitate to email support@wingware.com if you run into problems or have any questions.

        Real Python: Using the Python defaultdict Type for Handling Missing Keys

        $
        0
        0

        A common problem that you can face when working with Python dictionaries is to try to access or modify keys that don’t exist in the dictionary. This will raise a KeyError and break up your code execution. To handle these kinds of situations, the standard library provides the Python defaultdict type, a dictionary-like class that’s available for you in collections.

        The Python defaultdict type behaves almost exactly like a regular Python dictionary, but if you try to access or modify a missing key, then defaultdict will automatically create the key and generate a default value for it. This makes defaultdict a valuable option for handling missing keys in dictionaries.

        In this tutorial, you’ll learn:

        • How to use the Python defaultdict type for handling missing keys in a dictionary
        • When and why to use a Python defaultdict rather than a regular dict
        • How to use a defaultdict for grouping, counting, and accumulating operations

        With this knowledge under your belt, you’ll be in a better condition to effectively use the Python defaultdict type in your day-to-day programming challenges.

        To get the most out of this tutorial, you should have some previous understanding of what Python dictionaries are and how to work with them. If you need to freshen up, then check out the following resources:

        Free Bonus:Click here to get a Python Cheat Sheet and learn the basics of Python 3, like working with data types, dictionaries, lists, and Python functions.

        Handling Missing Keys in Dictionaries

        A common issue that you can face when working with Python dictionaries is how to handle missing keys. If your code is heavily based on dictionaries, or if you’re creating dictionaries on the fly all the time, then you’ll soon notice that dealing with frequent KeyError exceptions can be quite annoying and can add extra complexity to your code. With Python dictionaries, you have at least four available ways to handle missing keys:

        1. Use .setdefault()
        2. Use .get()
        3. Use the key in dict idiom
        4. Use a try and except block

        The Python docs explain .setdefault() and .get() as follows:

        setdefault(key[, default])

        If key is in the dictionary, return its value. If not, insert key with a value of default and return default. default defaults to None.

        get(key[, default])

        Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.

        (Source)

        Here’s an example of how you can use .setdefault() to handle missing keys in a dictionary:

        >>>
        >>> a_dict={}>>> a_dict['missing_key']Traceback (most recent call last):
          File "<stdin>", line 1, in <module>a_dict['missing_key']KeyError: 'missing_key'>>> a_dict.setdefault('missing_key','default value')'default value'>>> a_dict['missing_key']'default value'>>> a_dict.setdefault('missing_key','another default value')'default value'>>> a_dict{'missing_key': 'default value'}

        In the above code, you use .setdefault() to generate a default value for missing_key. Notice that your dictionary, a_dict, now has a new key called missing_key whose value is 'default value'. This key didn’t exist before you called .setdefault(). Finally, if you call .setdefault() on an existing key, then the call won’t have any effect on the dictionary. Your key will hold the original value instead of the new default value.

        Note: In the above code example, you get an exception, and Python shows you a traceback message, which tells you that you’re trying to access a missing key in a_dict. If you want to dive deeper into how to decipher and understand a Python traceback, then check out Understanding the Python Traceback.

        On the other hand, if you use .get(), then you can code something like this:

        >>>
        >>> a_dict={}>>> a_dict.get('missing_key','default value')'default value'>>> a_dict{}

        Here, you use .get() to generate a default value for missing_key, but this time, your dictionary stays empty. This is because .get() returns the default value, but this value isn’t added to the underlying dictionary. For example, if you have a dictionary called D, then you can assume that .get() works something like this:

        D.get(key, default) -> D[key] if key in D, else default
        

        With this pseudo-code, you can understand how .get() works internally. If the key exists, then .get() returns the value mapped to that key. Otherwise, the default value is returned. Your code never creates or assigns a value to key. In this example, default defaults to None.

        You can also use conditional statements to handle missing keys in dictionaries. Take a look at the following example, which uses the key in dict idiom:

        >>>
        >>> a_dict={}>>> if'key'ina_dict:... # Do something with 'key'...... a_dict['key']... else:... a_dict['key']='default value'...>>> a_dict{'key': 'default value'}

        In this code, you use an if statement along with the in operator to check if key is present in a_dict. If so, then you can perform any action with key or with its value. Otherwise, you create the new key, key, and assign it a 'default value'. Note that the above code works similar to .setdefault() but takes four lines of code, while .setdefault() would only take one line (in addition to being more readable).

        You can also walk around the KeyError by using a try and except block to handle the exception. Consider the following piece of code:

        >>>
        >>> a_dict={}>>> try:... # Do something with 'key'...... a_dict['key']... exceptKeyError:... a_dict['key']='default value'...>>> a_dict{'key': 'default value'}

        The try and except block in the above example catches the KeyError whenever you try to get access to a missing key. In the except clause, you create the key and assign it a 'default value'.

        Note: If missing keys are uncommon in your code, then you might prefer to use a try and except block (EAFP coding style) to catch the KeyError exception. This is because the code doesn’t check the existence of every key and only handles a few exceptions, if any.

        On the other hand, if missing keys are quite common in your code, then the conditional statement (LBYL coding style) can be a better choice because checking for keys can be less costly than handling frequent exceptions.

        So far, you’ve learned how to handle missing keys using the tools that dict and Python offer you. However, the examples you saw here are quite verbose and hard to read. They might not be as straightforward as you might want. That’s why the Python standard library provides a more elegant, Pythonic, and efficient solution. That solution is collections.defaultdict, and that’s what you’ll be covering from now on.

        Understanding the Python defaultdict Type

        The Python standard library provides collections, which is a module that implements specialized container types. One of those is the Python defaultdict type, which is an alternative to dict that’s specifically designed to help you out with missing keys. defaultdict is a Python type that inherits from dict:

        >>>
        >>> fromcollectionsimportdefaultdict>>> issubclass(defaultdict,dict)True

        The above code shows that the Python defaultdict type is a subclass of dict. This means that defaultdict inherits most of the behavior of dict. So, you can say that defaultdict is much like an ordinary dictionary.

        The main difference between defaultdict and dict is that when you try to access or modify a key that’s not present in the dictionary, a default value is automatically given to that key. In order to provide this functionality, the Python defaultdict type does two things:

        1. It overrides .__missing__().
        2. It adds .default_factory, a writable instance variable that needs to be provided at the time of instantiation.

        The instance variable .default_factory will hold the first argument passed into defaultdict.__init__(). This argument can take a valid Python callable or None. If a callable is provided, then it’ll automatically be called by defaultdict whenever you try to access or modify the value associated with a missing key.

        Note: All the remaining arguments to the class initializer are treated as if they were passed to the initializer of regular dict, including the keyword arguments.

        Take a look at how you can create and properly initialize a defaultdict:

        >>>
        >>> # Correct instantiation>>> def_dict=defaultdict(list)# Pass list to .default_factory>>> def_dict['one']=1# Add a key-value pair>>> def_dict['missing']# Access a missing key returns an empty list[]>>> def_dict['another_missing'].append(4)# Modify a missing key>>> def_dictdefaultdict(<class 'list'>, {'one': 1, 'missing': [], 'another_missing': [4]})

        Here, you pass list to .default_factory when you create the dictionary. Then, you use def_dict just like a regular dictionary. Note that when you try to access or modify the value mapped to a non-existent key, the dictionary assigns it the default value that results from calling list().

        Keep in mind that you must pass a valid Python callable object to .default_factory, so remember not to call it using the parentheses at initialization time. This can be a common issue when you start using the Python defaultdict type. Take a look at the following code:

        >>>
        >>> # Wrong instantiation>>> def_dict=defaultdict(list())Traceback (most recent call last):
          File "<stdin>", line 1, in <module>def_dict=defaultdict(list())TypeError: first argument must be callable or None

        Here, you try to create a defaultdict by passing list() to .default_factory. The call to list() raises a TypeError, which tells you that the first argument must be callable or None.

        With this introduction to the Python defaultdict type, you can get start coding with practical examples. The next few sections will walk you through some common use cases where you can rely on a defaultdict to provide an elegant, efficient, and Pythonic solution.

        Using the Python defaultdict Type

        Sometimes, you’ll use a mutable built-in collection (a list, dict, or set) as values in your Python dictionaries. In these cases, you’ll need to initialize the keys before first use, or you’ll get a KeyError. You can either do this process manually or automate it using a Python defaultdict. In this section, you’ll learn how to use the Python defaultdict type for solving some common programming problems:

        • Grouping the items in a collection
        • Counting the items in a collection
        • Accumulating the values in a collection

        You’ll be covering some examples that use list, set, int, and float to perform grouping, counting, and accumulating operations in a user-friendly and efficient way.

        Grouping Items

        A typical use of the Python defaultdict type is to set .default_factory to list and then build a dictionary that maps keys to lists of values. With this defaultdict, if you try to get access to any missing key, then the dictionary runs the following steps:

        1. Calllist() to create a new empty list
        2. Insert the empty list into the dictionary using the missing key as key
        3. Return a reference to that list

        This allows you to write code like this:

        >>>
        >>> fromcollectionsimportdefaultdict>>> dd=defaultdict(list)>>> dd['key'].append(1)>>> dddefaultdict(<class 'list'>, {'key': [1]})>>> dd['key'].append(2)>>> dddefaultdict(<class 'list'>, {'key': [1, 2]})>>> dd['key'].append(3)>>> dddefaultdict(<class 'list'>, {'key': [1, 2, 3]})

        Here, you create a Python defaultdict called dd and pass list to .default_factory. Notice that even when key isn’t defined, you can append values to it without getting a KeyError. That’s because dd automatically calls .default_factory to generate a default value for the missing key.

        You can use defaultdict along with list to group the items in a sequence or a collection. Suppose that you’ve retrieved the following data from your company’s database:

        DepartmentEmployee Name
        SalesJohn Doe
        SalesMartin Smith
        AccountingJane Doe
        MarketingElizabeth Smith
        MarketingAdam Doe

        With this data, you create an initial list of tuple objects like the following:

        dep=[('Sales','John Doe'),('Sales','Martin Smith'),('Accounting','Jane Doe'),('Marketing','Elizabeth Smith'),('Marketing','Adam Doe')]

        Now, you need to create a dictionary that groups the employees by department. To do this, you can use a defaultdict as follows:

        fromcollectionsimportdefaultdictdep_dd=defaultdict(list)fordepartment,employeeindep:dep_dd[department].append(employee)

        Here, you create a defaultdict called dep_dd and use a for loop to iterate through your dep list. The statement dep_dd[department].append(employee) creates the keys for the departments, initializes them to an empty list, and then appends the employees to each department. Once you run this code, your dep_dd will look something like this:

        >>>
        defaultdict(<class 'list'>, {'Sales': ['John Doe', 'Martin Smith'],                             'Accounting' : ['Jane Doe'],                             'Marketing': ['Elizabeth Smith', 'Adam Doe']})

        In this example, you group the employees by their department using a defaultdict with .default_factory set to list. To do this with a regular dictionary, you can use dict.setdefault() as follows:

        dep_d=dict()fordepartment,employeeindep:dep_d.setdefault(department,[]).append(employee)

        This code is straightforward, and you’ll find similar code quite often in your work as a Python coder. However, the defaultdict version is arguably more readable, and for large datasets, it can also be a lot faster and more efficient. So, if speed is a concern for you, then you should consider using a defaultdict instead of a standard dict.

        Grouping Unique Items

        Continue working with the data of departments and employees from the previous section. After some processing, you realize that a few employees have been duplicated in the database by mistake. You need to clean up the data and remove the duplicated employees from your dep_dd dictionary. To do this, you can use a set as the .default_factory and rewrite your code as follows:

        dep=[('Sales','John Doe'),('Sales','Martin Smith'),('Accounting','Jane Doe'),('Marketing','Elizabeth Smith'),('Marketing','Elizabeth Smith'),('Marketing','Adam Doe'),('Marketing','Adam Doe'),('Marketing','Adam Doe')]dep_dd=defaultdict(set)fordepartment,employeeinitems:dep_dd[department].add(employee)

        In this example, you set .default_factory to set. Sets are collections of unique objects, which means that you can’t create a set with repeated items. This is a really interesting feature of sets, which guarantees that you won’t have repeated items in your final dictionary.

        Counting Items

        If you set .default_factory to int, then your defaultdict will be useful for counting the items in a sequence or collection. When you call int() with no arguments, the function returns 0, which is the typical value you’d use to initialize a counter.

        To continue with the example of the company database, suppose you want to build a dictionary that counts the number of employees per department. In this case, you can code something like this:

        >>>
        >>> fromcollectionsimportdefaultdict>>> dep=[('Sales','John Doe'),... ('Sales','Martin Smith'),... ('Accounting','Jane Doe'),... ('Marketing','Elizabeth Smith'),... ('Marketing','Adam Doe')]>>> dd=defaultdict(int)>>> fordepartment,_indep:... dd[department]+=1>>> dddefaultdict(<class 'int'>, {'Sales': 2, 'Accounting': 1, 'Marketing': 2})

        Here, you set .default_factory to int. When you call int() with no argument, the returned value is 0. You can use this default value to start counting the employees that work in each department. For this code to work correctly, you need a clean dataset. There must be no repeated data. Otherwise, you’ll need to filter out the repeated employees.

        Another example of counting items is the mississippi example, where you count the number of times each letter in a word is repeated. Take a look at the following code:

        >>>
        >>> fromcollectionsimportdefaultdict>>> s='mississippi'>>> dd=defaultdict(int)>>> forletterins:... dd[letter]+=1...>>> dddefaultdict(<class 'int'>, {'m': 1, 'i': 4, 's': 4, 'p': 2})

        In the above code, you create a defaultdict with .default_factory set to int. This sets the default value for any given key to 0. Then, you use a for loop to traverse the strings and use an augmented assignment operation to add 1 to the counter in every iteration. The keys of dd will be the letters in mississippi.

        Note: Python’s augmented assignment operators are a handy shortcut to common operations.

        Take a look at the following examples:

        • var += 1 is equivalent to var = var + 1
        • var -= 1 is equivalent to var = var - 1
        • var *= 1 is equivalent to var = var * 1

        This is just a sample of how the augmented assignment operators work. You can take a look at the official documentation to learn more about this feature.

        As counting is a relatively common task in programming, the Python dictionary-like class collections.Counter is specially designed for counting items in a sequence. With Counter, you can write the mississippi example as follows:

        >>>
        >>> fromcollectionsimportCounter>>> counter=Counter('mississippi')>>> counterCounter({'i': 4, 's': 4, 'p': 2, 'm': 1})

        In this case, Counter does all the work for you! You only need to pass in a sequence, and the dictionary will count its items, storing them as keys and the counts as values. Note that this example works because Python strings are also a sequence type.

        Accumulating Values

        Sometimes you’ll need to calculate the total sum of the values in a sequence or collection. Let’s say you have the following Excel sheet with data about the sales of your Python website:

        ProductsJulyAugustSeptember
        Books1250.001300.001420.00
        Tutorials560.00630.00750.00
        Courses2500.002430.002750.00

        Next, you process the data using Python and get the following list of tuple objects:

        incomes=[('Books',1250.00),('Books',1300.00),('Books',1420.00),('Tutorials',560.00),('Tutorials',630.00),('Tutorials',750.00),('Courses',2500.00),('Courses',2430.00),('Courses',2750.00),]

        With this data, you want to calculate the total income per product. To do that, you can use a Python defaultdict with float as .default_factory and then code something like this:

         1 fromcollectionsimportdefaultdict 2  3 dd=defaultdict(float) 4 forproduct,incomeinincomes: 5 dd[product]+=income 6  7 forproduct,incomeindd.items(): 8 print(f'Total income for {product}: ${income:,.2f}')

        Here’s what this code does:

        • In line 1, you import the Python defaultdict type.
        • In line 3, you create a defaultdict object with .default_factory set to float.
        • In line 4, you define a for loop to iterate through the items of incomes.
        • In line 5, you use an augmented assignment operation (+=) to accumulate the incomes per product in the dictionary.

        The second loop iterates through the items of dd and prints the incomes to your screen.

        Note: If you want to dive deeper into dictionary iteration, check out How to Iterate Through a Dictionary in Python.

        If you put all this code into a file called incomes.py and run it from your command line, then you’ll get the following output:

        $ python3 incomes.py
        Total income for Books: $3,970.00Total income for Tutorials: $1,940.00Total income for Courses: $7,680.00

        You now have a summary of incomes per product, so you can make decisions on which strategy to follow for increasing the total income of your site.

        Diving Deeper Into defaultdict

        So far, you’ve learned how to use the Python defaultdict type by coding some practical examples. At this point, you can dive deeper into type implementation and other working details. That’s what you’ll be covering in the next few sections.

        defaultdict vs dict

        For you to better understand the Python defaultdict type, a good exercise would be to compare it with its superclass, dict. If you want to know the methods and attributes that are specific to the Python defaultdict type, then you can run the following line of code:

        >>>
        >>> set(dir(defaultdict))-set(dir(dict)){'__copy__', 'default_factory', '__missing__'}

        In the above code, you use dir() to get the list of valid attributes for dict and defaultdict. Then, you use a set difference to get the set of methods and attributes that you can only find in defaultdict. As you can see, the differences between these two classes are. You have two methods and one instance attribute. The following table shows what the methods and the attribute are for:

        Method or AttributeDescription
        .__copy__()Provides support for copy.copy()
        .default_factoryHolds the callable invoked by .__missing__() to automatically provide default values for missing keys
        .__missing__(key)Gets called when .__getitem__() can’t find key

        In the above table, you can see the methods and the attribute that make a defaultdict different from a regular dict. The rest of the methods are the same in both classes.

        Note: If you initialize a defaultdict using a valid callable, then you won’t get a KeyError when you try to get access to a missing key. Any key that doesn’t exist gets the value returned by .default_factory.

        Additionally, you might notice that a defaultdict is equal to a dict with the same items:

        >>>
        >>> std_dict=dict(numbers=[1,2,3],letters=['a','b','c'])>>> std_dict{'numbers': [1, 2, 3], 'letters': ['a', 'b', 'c']}>>> def_dict=defaultdict(list,numbers=[1,2,3],letters=['a','b','c'])>>> def_dictdefaultdict(<class 'list'>, {'numbers': [1, 2, 3], 'letters': ['a', 'b', 'c']})>>> std_dict==def_dictTrue

        Here, you create a regular dictionary std_dict with some arbitrary items. Then, you create a defaultdict with the same items. If you test both dictionaries for content equality, then you’ll see that they’re equal.

        defaultdict.default_factory

        The first argument to the Python defaultdict type must be a callable that takes no arguments and returns a value. This argument is assigned to the instance attribute, .default_factory. For this, you can use any callable, including functions, methods, classes, type objects, or any other valid callable. The default value of .default_factory is None.

        If you instantiate defaultdict without passing a value to .default_factory, then the dictionary will behave like a regular dict and the usual KeyError will be raised for missing key lookup or modification attempts:

        >>>
        >>> fromcollectionsimportdefaultdict>>> dd=defaultdict()>>> dd['missing_key']Traceback (most recent call last):
          File "<stdin>", line 1, in <module>dd['missing_key']KeyError: 'missing_key'

        Here, you instantiate the Python defaultdict type with no arguments. In this case, the instance behaves like a standard dictionary. So, if you try to access or modify a missing key, then you’ll get the usual KeyError. From this point on, you can use dd as a normal Python dictionary and, unless you assign a new callable to .default_factory, you won’t be able to use the ability of defaultdict to handle missing keys automatically.

        If you pass None to the first argument of defaultdict, then the instance will behave the same way you saw in the above example. That’s because .default_factory defaults to None, so both initializations are equivalent. On the other hand, if you pass a valid callable object to .default_factory, then you can use it to handle missing keys in a user-friendly way. Here’s an example where you pass list to .default_factory:

        >>>
        >>> dd=defaultdict(list,letters=['a','b','c'])>>> dd.default_factory<class 'list'>>>> dddefaultdict(<class 'list'>, {'letters': ['a', 'b', 'c']})>>> dd['numbers'][]>>> dddefaultdict(<class 'list'>, {'letters': ['a', 'b', 'c'], 'numbers': []})>>> dd['numbers'].append(1)>>> dddefaultdict(<class 'list'>, {'letters': ['a', 'b', 'c'], 'numbers': [1]})>>> dd['numbers']+=[2,3]>>> dddefaultdict(<class 'list'>, {'letters': ['a', 'b', 'c'], 'numbers': [1, 2, 3]})

        In this example, you create a Python defaultdict called dd, then you use list for its first argument. The second argument is called letters and holds a list of letters. You see that .default_factory now holds a list object that will be called when you need to supply a default value for any missing key.

        Notice that when you try to access numbers, dd tests if numbers is in the dictionary. If it’s not, then it calls .default_factory(). Since .default_factory holds a list object, the returned value is an empty list ([]).

        Now that dd['numbers'] is initialized with an empty list, you can use .append() to add elements to the list. You can also use an augmented assignment operator (+=) to concatenate the lists [1] and [2, 3]. This way, you can handle missing keys in a more Pythonic and more efficient way.

        On the other hand, if you pass a non-callable object to the initializer of the Python defaultdict type, then you’ll get a TypeError like in the following code:

        >>>
        >>> defaultdict(0)Traceback (most recent call last):
          File "<stdin>", line 1, in <module>defaultdict(0)TypeError: first argument must be callable or None

        Here, you pass 0 to .default_factory. Since 0 is not a callable object, you get a TypeError telling you that the first argument must be callable or None. Otherwise, defaultdict doesn’t work.

        Keep in mind that .default_factory is only called from .__getitem__() and not from other methods. This means that if dd is a defaultdict and key is a missing key, then dd[key] will call .default_factory to provide a default value, but dd.get(key) still returns None instead of the value that .default_factory would provide. That’s because .get() doesn’t call .__getitem__() to retrieve the key.

        Take a look at the following code:

        >>>
        >>> dd=defaultdict(list)>>> # Calls dd.__getitem__('missing')>>> dd['missing'][]>>> # Don't call dd.__getitem__('another_missing')>>> print(dd.get('another_missing'))None>>> dddefaultdict(<class 'list'>, {'missing': []})

        In this code fragment, you can see that dd.get() returns None rather than the default value that .default_factory would provide. That’s because .default_factory is only called from .__missing__(), which is not called by .get().

        Notice that you can also add arbitrary values to a Python defaultdict. This means that you’re not limited to values with the same type as the values generated by .default_factory. Here’s an example:

        >>>
        >>> dd=defaultdict(list)>>> dddefaultdict(<class 'list'>, {})>>> dd['string']='some string'>>> dddefaultdict(<class 'list'>, {'string': 'some string'})>>> dd['list'][]>>> dddefaultdict(<class 'list'>, {'string': 'some string', 'list': []})

        Here, you create a defaultdict and pass in a list object to .default_factory. This sets your default values to be empty lists. However, you can freely add a new key that holds values of a different type. That’s the case with the key string, which holds a str object instead of a list object.

        Finally, you can always change or update the callable you initially assign to .default_factory in the same way you would do with any instance attribute:

        >>>
        >>> dd.default_factory=str>>> dd['missing_key']''

        In the above code, you change .default_factory from list to str. Now, whenever you try to get access to a missing key, your default value will be an empty string ('').

        Depending on your use cases for the Python defaultdict type, you might need to freeze the dictionary once you finish creating it and make it read-only. To do this, you can set .default_factory to None after you finish populating the dictionary. This way, your dictionary will behave like a standard dict, which means you won’t have more automatically generated default values.

        defaultdict vs dict.setdefault()

        As you saw before, dict provides .setdefault(), which will allow you to assign values to missing keys on the fly. In contrast, with a defaultdict you can specify the default value up front when you initialize the container. You can use .setdefault() to assign default values as follows:

        >>>
        >>> d=dict()>>> d.setdefault('missing_key',[])[]>>> d{'missing_key': []}

        In this code, you create a regular dictionary and then use .setdefault() to assign a value ([]) to the key missing_key, which wasn’t defined yet.

        Note: You can assign any type of Python object using .setdefault(). This is an important difference compared to defaultdict if you consider that defaultdict only accepts a callable or None.

        On the other hand, if you use a defaultdict to accomplish the same task, then the default value is generated on demand whenever you try to access or modify a missing key. Notice that, with defaultdict, the default value is generated by the callable you pass upfront to the initializer of the class. Here’s how it works:

        >>>
        >>> fromcollectionsimportdefaultdict>>> dd=defaultdict(list)>>> dd['missing_key'][]>>> dddefaultdict(<class 'list'>, {'missing_key': []})

        Here, you first import the Python defaultdict type from collections. Then, you create a defaultdict and pass list to .default_factory. When you try to get access to a missing key, defaultdict internally calls .default_factory(), which holds a reference to list, and assigns the resulting value (an empty list) to missing_key.

        The code in the above two examples does the same work, but the defaultdict version is arguably more readable, user-friendly, Pythonic, and straightforward.

        Note: A call to a built-in type like list, set, dict, str, int, or float will return an empty object or zero for numeric types.

        Take a look at the following code examples:

        >>>
        >>> list()[]>>> set()set([])>>> dict(){}>>> str()''>>> float()0.0>>> int()0

        In this code, you call some built-in types with no arguments and get an empty object or zero for the numeric types.

        Finally, using a defaultdict to handle missing keys can be faster than using dict.setdefault(). Take a look a the following example:

        # Filename: exec_time.pyfromcollectionsimportdefaultdictfromtimeitimporttimeitanimals=[('cat',1),('rabbit',2),('cat',3),('dog',4),('dog',1)]std_dict=dict()def_dict=defaultdict(list)defgroup_with_dict():foranimal,countinanimals:std_dict.setdefault(animal,[]).append(count)returnstd_dictdefgroup_with_defaultdict():foranimal,countinanimals:def_dict[animal].append(count)returndef_dictprint(f'dict.setdefault() takes {timeit(group_with_dict)} seconds.')print(f'defaultdict takes {timeit(group_with_defaultdict)} seconds.')

        If you run the script from your system’s command line, then you’ll get something like this:

        $ python3 exec_time.py
        dict.setdefault() takes 1.0281260240008123 seconds.defaultdict takes 0.6704721650003194 seconds.

        Here, you use timeit.timeit() to measure the execution time of group_with_dict() and group_with_defaultdict(). These functions perform equivalent actions, but the first uses dict.setdefault(), and the second uses a defaultdict. The time measure will depend on your current hardware, but you can see here that defaultdict is faster than dict.setdefault(). This difference can become more important as the dataset gets larger.

        Additionally, you need to consider that creating a regular dict can be faster than creating a defaultdict. Take a look at this code:

        >>>
        >>> fromtimeitimporttimeit>>> fromcollectionsimportdefaultdict>>> print(f'dict() takes {timeit(dict)} seconds.')dict() takes 0.08921320698573254 seconds.>>> print(f'defaultdict() takes {timeit(defaultdict)} seconds.')defaultdict() takes 0.14101867799763568 seconds.

        This time, you use timeit.timeit() to measure the execution time of dict and defaultdict instantiation. Notice that creating a dict takes almost half the time of creating a defaultdict. This might not be a problem if you consider that, in real-world code, you normally instantiate defaultdict only once.

        Also notice that, by default, timeit.timeit() will run your code a million times. That’s the reason for defining std_dict and def_dict out of the scope of group_with_dict() and group_with_defaultdict() in exec_time.py. Otherwise, the time measure will be affected by the instantiation time of dict and defaultdict.

        At this point, you may have an idea of when to use a defaultdict rather than a regular dict. Here are three things to take into account:

        1. If your code is heavily base on dictionaries and you’re dealing with missing keys all the time, then you should consider using a defaultdict rather than a regular dict.

        2. If your dictionary items need to be initialized with a constant default value, then you should consider using a defaultdict instead of a dict.

        3. If your code relies on dictionaries for aggregating, accumulating, counting, or grouping values, and performance is a concern, then you should consider using a defaultdict.

        You can consider the above guidelines when deciding whether to use a dict or a defaultdict.

        defaultdict.__missing__()

        Behind the scenes, the Python defaultdict type works by calling .default_factory to supply default values to missing keys. The mechanism that makes this possible is .__missing__(), a special method supported by all the standard mapping types, including dict and defaultdict.

        Note: Note that .__missing__() is automatically called by .__getitem__() to handle missing keys and that .__getitem__() is automatically called by Python at the same time for subscription operations like d[key].

        So, how does .__missing__() work? If you set .default_factory to None, then .__missing__() raises a KeyError with the key as an argument. Otherwise, .default_factory is called without arguments to provide a default value for the given key. This value is inserted into the dictionary and finally returned. If calling .default_factory raises an exception, then the exception is propagated unchanged.

        The following code shows a viable Python implementation for .__missing__():

         1 def__missing__(self,key): 2 ifself.default_factoryisNone: 3 raiseKeyError(key) 4 ifkeynotinself: 5 self[key]=self.default_factory() 6 returnself[key]

        Here’s what this code does:

        • In line 1, you define the method and its signature.
        • In lines 2 and 3, you test to see if .default_factory is None. If so, then you raise a KeyError with the key as an argument.
        • In lines 4 and 5, you check if the key is not in the dictionary. If it’s not, then you call .default_factory and assign its return value to the key.
        • In line 6, you return the key as expected.

        Keep in mind that the presence of .__missing__() in a mapping has no effect on the behavior of other methods that look up keys, such as .get() or .__contains__(), which implements the in operator. That’s because .__missing__() is only called by .__getitem__() when the requested key is not found in the dictionary. Whatever .__missing__() returns or raises is then returned or raised by .__getitem__().

        Now that you’ve covered an alternative Python implementation for .__missing__(), it would be a good exercise to try to emulate defaultdict with some Python code. That’s what you’ll be doing in the next section.

        Emulating the Python defaultdict Type

        In this section, you’ll be coding a Python class that will behave much like a defaultdict. To do that, you’ll subclass collections.UserDict and then add .__missing__(). Also, you need to add an instance attribute called .default_factory, which will hold the callable for generating default values on demand. Here’s a piece of code that emulates most of the behavior of the Python defaultdict type:

         1 importcollections 2  3 classmy_defaultdict(collections.UserDict): 4 def__init__(self,default_factory=None,*args,**kwargs): 5 super().__init__(*args,**kwargs) 6 ifnotcallable(default_factory)anddefault_factoryisnotNone: 7 raiseTypeError('first argument must be callable or None') 8 self.default_factory=default_factory 9 10 def__missing__(self,key):11 ifself.default_factoryisNone:12 raiseKeyError(key)13 ifkeynotinself:14 self[key]=self.default_factory()15 returnself[key]

        Here’s how this code works:

        • In line 1, you import collections to get access to UserDict.

        • In line 3, you create a class that subclasses UserDict.

        • In line 4, you define the class initializer .__init__(). This method takes an argument called default_factory to hold the callable that you’ll use to generate the default values. Notice that default_factory defaults to None, just like in a defaultdict. You also need the *args and **kwargs for emulating the normal behavior of a regular dict.

        • In line 5, you call the superclass .__init__(). This means that you’re calling UserDict.__init__() and passing *args and **kwargs to it.

        • In line 6, you first check if default_factory is a valid callable object. In this case, you use callable(object), which is a built-in function that returns True if object appears to be a callable and otherwise returns False. This check ensures that you can call .default_factory() if you need to generate a default value for any missing key. Then, you check if .default_factory is not None.

        • In line 7, you raise a TypeError just like a regular dict would do if default_factory is None.

        • In line 8, you initialize .default_factory.

        • In line 10, you define .__missing__(), which is implemented as you saw before. Recall that .__missing__() is automatically called by .__getitem__() when a given key is not in a dictionary.

        If you feel in the mood to read some C code, then you can take a look at the full code for the Python defaultdict Type in the CPython source code.

        Now that you’ve finished coding this class, you can test it by putting the code into a Python script called my_dd.py and importing it from an interactive session. Here’s an example:

        >>>
        >>> frommy_ddimportmy_defaultdict>>> dd_one=my_defaultdict(list)>>> dd_one{}>>> dd_one['missing'][]>>> dd_one{'missing': []}>>> dd_one.default_factory=int>>> dd_one['another_missing']0>>> dd_one{'missing': [], 'another_missing': 0}>>> dd_two=my_defaultdict(None)>>> dd_two['missing']Traceback (most recent call last):
          File "<stdin>", line 1, in <module>dd_two['missing']  File "/home/user/my_dd.py", line 10, in __missing__    raise KeyError(key)KeyError: 'missing'

        Here, you first import my_defaultdict from my_dd. Then, you create an instance of my_defaultdict and pass list to .default_factory. If you try to get access to a key with a subscription operation, like dd_one['missing'], then .__getitem__() is automatically called by Python. If the key is not in the dictionary, then .__missing__() is called, which generates a default value by calling .default_factory().

        You can also change the callable assigned to .default_factory using a normal assignment operation like in dd_one.default_factory = int. Finally, if you pass None to .default_factory, then you’ll get a KeyError when trying to retrieve a missing key.

        Note: The behavior of a defaultdict is essentially the same as this Python equivalent. However, you’ll soon note that your Python implementation doesn’t print as a real defaultdict but as a standard dict. You can modify this detail by overriding .__str__() and .__repr__().

        You may be wondering why you subclass collections.UserDict instead of a regular dict for this example. The main reason for this is that subclassing built-in types can be error-prone because the C code of the built-ins doesn’t seem to consistently call special methods overridden by the user.

        Here’s an example that shows some issues that you can face when subclassing dict:

        >>>
        >>> classMyDict(dict):... def__setitem__(self,key,value):... super().__setitem__(key,None)...>>> my_dict=MyDict(first=1)>>> my_dict{'first': 1}>>> my_dict['second']=2>>> my_dict{'first': 1, 'second': None}>>> my_dict.setdefault('third',3)3>>> my_dict{'first': 1, 'second': None, 'third': 3}

        In this example, you create MyDict, which is a class that subclasses dict. Your implementation of .__setitem__() always sets values to None. If you create an instance of MyDict and pass a keyword argument to its initializer, then you’ll notice the class is not calling your .__setitem__() to handle the assignment. You know that because the key first wasn’t assigned None.

        By contrast, if you run a subscription operation like my_dict['second'] = 2, then you’ll notice that second is set to None rather than to 2. So, this time you can say that subscription operations call your custom .__setitem__(). Finally, notice that .setdefault() doesn’t call .__setitem__() either, because your third key ends up with a value of 3.

        UserDict doesn’t inherit from dict but simulates the behavior of a standard dictionary. The class has an internal dict instance called .data, which is used to store the content of the dictionary. UserDict is a more reliable class when it comes to creating custom mappings. If you use UserDict, then you’ll be avoiding the issues you saw before. To prove this, go back to the code for my_defaultdict and add the following method:

         1 classmy_defaultdict(collections.UserDict): 2 # Snip 3 def__setitem__(self,key,value): 4 print('__setitem__() gets called') 5 super().__setitem__(key,None)

        Here, you add a custom .__setitem__() that calls the superclass .__setitem__(), which always sets the value to None. Update this code in your script my_dd.py and import it from an interactive session as follows:

        >>>
        >>> frommy_ddimportmy_defaultdict>>> my_dict=my_defaultdict(list,first=1)__setitem__() gets called>>> my_dict{'first': None}>>> my_dict['second']=2__setitem__() gets called>>> my_dict{'first': None, 'second': None}

        In this case, when you instantiate my_defaultdict and pass first to the class initializer, your custom __setitem__() gets called. Also, when you assign a value to the key second, __setitem__() gets called as well. You now have a my_defaultdict that consistently calls your custom special methods. Notice that all the values in the dictionary are equal to None now.

        Passing Arguments to .default_factory

        As you saw earlier, .default_factory must be set to a callable object that takes no argument and returns a value. This value will be used to supply a default value for any missing key in the dictionary. Even when .default_factory shouldn’t take arguments, Python offers some tricks that you can use if you need to supply arguments to it. In this section, you’ll cover two Python tools that can serve this purpose:

        1. lambda
        2. functools.partial()

        With these two tools, you can add extra flexibility to the Python defaultdict type. For example, you can initialize a defaultdict with a callable that takes an argument and, after some processing, you can update the callable with a new argument to change the default value for the keys you’ll create from this point on.

        Using lambda

        A flexible way to pass arguments to .default_factory is to use lambda. Suppose you want to create a function to generate default values in a defaultdict. The function does some processing and returns a value, but you need to pass an argument for the function to work correctly. Here’s an example:

        >>>
        >>> deffactory(arg):... # Do some processing here...... result=arg.upper()... returnresult...>>> def_dict=defaultdict(lambda:factory('default value'))>>> def_dict['missing']'DEFAULT VALUE'

        In the above code, you create a function called factory(). The function takes an argument, does some processing, and returns the final result. Then, you create a defaultdict and use lambda to pass the string 'default value' to factory(). When you try to get access to a missing key, the following steps are run:

        1. The dictionary def_dict calls its .default_factory, which holds a reference to a lambda function.
        2. The lambda function gets called and returns the value that results from calling factory() with 'default value' as an argument.

        If you’re working with def_dict and suddenly need to change the argument to factory(), then you can do something like this:

        >>>
        >>> def_dict.default_factory=factory('another default value')>>> def_dict['another_missing']'ANOTHER DEFAULT VALUE'

        This time, factory() takes a new string argument ('another default value'). From now on, if you try to access or modify a missing key, then you’ll get a new default value, which is the string 'ANOTHER DEFAULT VALUE'.

        Finally, you can possibly face a situation where you need a default value that’s different from 0 or []. In this case, you can also use lambda to generate a different default value. For example, suppose you have a list of integer numbers, and you need to calculate the cumulative product of each number. Then, you can use a defaultdict along with lambda as follows:

        >>>
        >>> fromcollectionsimportdefaultdict>>> lst=[1,1,2,1,2,2,3,4,3,3,4,4]>>> def_dict=defaultdict(lambda:1)>>> fornumberinlst:... def_dict[number]*=number...>>> def_dictdefaultdict(<function <lambda> at 0x...70>, {1: 1, 2: 8, 3: 27, 4: 64})

        Here, you use lambda to supply a default value of 1. With this initial value, you can calculate the cumulative product of each number in lst. Notice that you can’t get the same result using int because the default value returned by int is always 0, which is not a good initial value for the multiplication operations you need to perform here.

        Using functools.partial()

        functools.partial(func, *args, **keywords) is a function that returns a partial object. When you call this object with the positional arguments (args) and keyword arguments (keywords), it behaves similar to when you call func(*args, **keywords). You can take advantage of this behavior of partial() and use it to pass arguments to .default_factory in a Python defaultdict. Here’s an example:

        >>>
        >>> deffactory(arg):... # Do some processing here...... result=arg.upper()... returnresult...>>> fromfunctoolsimportpartial>>> def_dict=defaultdict(partial(factory,'default value'))>>> def_dict['missing']'DEFAULT VALUE'>>> def_dict.default_factory=partial(factory,'another default value')>>> def_dict['another_missing']'ANOTHER DEFAULT VALUE'

        Here, you create a Python defaultdict and use partial() to supply an argument to .default_factory. Notice that you can also update .default_factory to use another argument for the callable factory(). This kind of behavior can add a lot of flexibility to your defaultdict objects.

        Conclusion

        The Python defaultdict type is a dictionary-like data structure provided by the Python standard library in a module called collections. The class inherits from dict, and its main added functionality is to supply default values for missing keys. In this tutorial, you’ve learned how to use the Python defaultdict type for handling the missing keys in a dictionary.

        You’re now able to:

        • Create and use a Python defaultdict to handle missing keys
        • Solve real-world problems related to grouping, counting, and accumulating operations
        • Know the implementation differences between defaultdict and dict
        • Decide when and why to use a Python defaultdict rather than a standard dict

        The Python defaultdict type is a convenient and efficient data structure that’s designed to help you out when you’re dealing with missing keys in a dictionary. Give it a try and make your code faster, more readable, and more Pythonic!


        [ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]

        Mike Driscoll: Python 101: Learning About Lists

        $
        0
        0

        Lists are a fundamental data type in the Python programming language. A list is a mutable sequence that is typically a collection of homogeneous items. Mutable means that you can change a list after its creation. You will frequently see lists that contain other lists. These are known as nested lists. You will also see lists that contain all manner of other data types, such as dictionaries, tuples or objects.

        Let’s find out how you can create a list!

        Creating Lists

        There are several ways to create a list. You may construct a list in any of the following ways:

        • Using a pair of square brackets with nothing inside creates an empty list: []
        • Using square brackets with comma-separated items: [1, 2, 3]
        • Using a list comprehension: [x for x in iterable]
        • Using the list() function: list(iterable)

        An iterable is a sequence, a container that supports iteration or an iterator object. Lists themselves are sequences as are strings.

        Let’s look at a few examples of creating a list so you can see it in action:

        >>> my_list = [1, 2, 3]
        >>> my_list
        [1, 2, 3]

        This first example is pretty straight-forward. Here you create a list with 3 numbers in it. Then you print it out to verify that it contains what you think it should.

        The next way to create a list is by using Python’s built-in list() function:

        >>> list_of_strings = list('abc')
        >>> list_of_strings
        ['a', 'b', 'c']

        In this case, you pass a string of three letters to the list() function. It automatically iterates over the characters in the string to create a list of three string, where each string is a single character.

        The last example to look at is how to create empty lists:

        >>> empty_list = []
        >>> empty_list
        []
        >>> another_empty_list = list()
        >>> another_empty_list
        []

        The quickest way to create an empty list is by using the square brackets without putting anything inside them. The second easiest way is to call list() without any arguments. The nice thing about using list() in general is that you can use it to cast a compatible data type to a list, as you did with the string, “abc”, in the example earlier.

        List Methods

        A Python list has several methods that you can call. Here is a listing of the methods you can use with a list:

        • append()
        • clear()
        • copy()
        • count()
        • extend()
        • index()
        • insert()
        • pop()
        • remove()
        • reverse()
        • sort()

        Most of these will be covered in the following sections. Let’s talk about the ones that aren’t covered in a specific section first.

        You can use count() to count the number of instances of the object that you passed in.

        Here is an example:

        >>> my_list = list('abcc')
        >>> my_list.count('a')
        1
        >>> my_list.count('c')
        2

        This is a simple way to count the number of occurrences of an item in a list.

        The index() method is useful for finding the first instance of an item in a list:

        >>> my_list = list('abcc')
        >>> my_list.index('c')
        2
        >>> my_list.index('a')
        0

        Python lists are zero-indexed, so “a” is in position 0, “b” is at position 1, etc.

        You can use the reverse() method to reverse a list in-place:

        >>> my_list = list('abcc')
        >>> my_list.reverse()
        >>> my_list
        ['c', 'c', 'b', 'a']

        Note that the reverse() method returns None. What that means is that if you try to assign the reversed list to a new variable, you may end up with something unexpected:

        >>> x = my_list.reverse()
        >>> print(x)
        None

        Here you end up with None instead of the reversed list. That is what in-place means. The original list is reversed, but the reverse() method itself doesn’t return anything.

        Now let’s find out what you can do with the other list methods!

        Adding to a List

        There are three list methods that you can use to add to a list. They are as follows:

        • append()
        • extend()
        • insert()

        The append() method will add an item to the end of a pre-existing list:

        >>> my_list = list('abcc')
        >>> my_list
        ['a', 'b', 'c', 'c']
        >>> my_list.append(1)
        >>> my_list
        ['a', 'b', 'c', 'c', 1]

        First you create a list that is made up of four one-character strings. Then you append an integer to the end of the list. Now the list should have 5 items in it with the 1 on the end.

        You can use Python’s built-in len() function to check the number of items in a list:

        >>> len(my_list)
        5

        So this tells you that you do in fact have five items in the list. But what if you wanted to add an element somewhere other than the end of the list?

        You can use insert() for that:

        >>> my_list.insert(0, 'first')
        >>> my_list
        ['first', 'a', 'b', 'c', 'c', 1]

        The insert() method takes two arguments:

        • The position at which to insert
        • The item to insert

        In the code above, you tell Python that you want to insert the string, “first”, into the 0 position, which is the first position in the list.

        There are two other ways to add items to a list. You can add an iterable to a list using extend():

        >>> my_list = [1, 2, 3]
        >>> other_list = [4, 5, 6]
        >>> my_list.extend(other_list)
        >>> my_list
        [1, 2, 3, 4, 5, 6]

        Here you create two lists. Then you use my_list‘s extend() method to add the items in other_list to my_list. extend() will iterate over the items in the passed in list and add each of them to the list.

        You can also combine lists using concatenation:

        >>> my_list = [1, 2, 3]
        >>> other_list = [4, 5, 6]
        >>> combined = my_list + other_list
        >>> combined
        [1, 2, 3, 4, 5, 6]

        In this case, you create two lists and then combine them using Python’s + operator.

        You can also use += with Python lists:

        >>> my_list = [1, 2, 3]
        >>> other_list = [4, 5, 6]
        >>> my_list += other_list
        >>> my_list
        [1, 2, 3, 4, 5, 6]

        This is a somewhat simpler way to combine the two lists.

        Now let’s learn how to access and change elements within a list.

        Accessing and Changing List Elements

        Lists are made to be worked with. You will need to learn how to access individual elements as well as how to change them.

        Let’s start by learning how to access an item:

        >>> my_list = [1, 2, 3]
        >>> my_list[0]
        1
        >>> my_list[2]
        3

        To access an item in a list, you need to use square braces and pass in the index of the item that you wish to access. In the example above, you access the first and third elements.

        Lists also support accessing items in reverse by using negative values:

        >>> my_list[-1]
        3

        This example demonstrates that when you pass in -1, you get the last item in the list returned. Try using some other values and see if you can get the first item using negative indexing.

        If you try to use an index that does not exist in the list, you will get an IndexError:

        >>> my_list[-5]
        Traceback (most recent call last):
        Python Shell, prompt 41, line 1
        builtins.IndexError: list index out of range

        Now let’s learn about removing items!

        Deleting From a List

        Deleting items from a list is pretty straight-forward. There are 4 primary methods of removing items from a list:

        • clear()
        • pop()
        • remove()
        • del

        You can use clear() to remove everything from the list. Let’s see how that works:

        >>> my_list = [1, 2, 3]
        >>> my_list.clear()
        >>> my_list
        []
        

        After calling clear(), the list is now empty. This can be useful when you have finished working on the items in the list and you need to start over from scratch. Of course, you could also do this instead of clear():

        >> my_list = []

        This will create a new empty list. If it is important for you to always use the same object, then using clear() would be better. If that does not matter, then setting it to an empty list will work well too.

        If you would rather remove individual items, then you should check out pop() or remove(). Let’s start with pop():

        >>> my_list = [1, 2, 3]
        >>> my_list.pop()
        3
        >>> my_list
        [1, 2]

        You can pass an index to pop() to remove an item and return it. Or you can call pop() without an argument like in the example above and it will default to removing the last item in the list and returning it. pop() is the most flexible way of removing items from a list.

        If the list is empty or you pass in an index that does not exist, pop() will throw an exception:

        >>> my_list.pop(10)
        Traceback (most recent call last):
          Python Shell, prompt 50, line 1
        builtins.IndexError: pop index out of range

        Now let’s take a look at how remove() works:

        >>> my_list = [1, 2, 3]
        >>> my_list.remove(2)
        >>> my_list
        [1, 3]

        remove() will delete the first instance of the passed in item. So in this case, you tell the list to remove the first occurrence of the number 2.

        If you tell remove() to delete an item that is not in the list, you will receive an exception:

        >>> my_list.remove(4)
        Traceback (most recent call last):
          Python Shell, prompt 51, line 1
        builtins.ValueError: list.remove(x): x not in list

        You can also use Python’s built-in del keyword to delete items from a list:

        >>> my_list.remove(4)
        Traceback (most recent call last):
          Python Shell, prompt 51, line 1
        builtins.ValueError: list.remove(x): x not in list

        You can also use Python’s built-in del keyword to delete items from a list:

        >>> my_list = [1, 2, 3]
        >>> del my_list[1]
        >>> my_list
        [1, 3]

        You will receive an error if you try to remove an index that does not exist:

        >>> my_list = [1, 2, 3]
        >>> del my_list[6]
        Traceback (most recent call last):
          Python Shell, prompt 296, line 1
        builtins.IndexError: list assignment index out of range

        Now let’s learn about sorting a list!

        Sorting a List

        Lists in Python can be sorted. You can use the built-in sort() method to sort a list in-place or you can use Python’s sorted() function.

        Let’s create a list and try sorting it:

        >>> my_list = [4, 10, 2, 1, 23, 9]
        >>> my_list.sort()
        >>> my_list
        [1, 2, 4, 9, 10, 23]

        Here you create a list with 6 integers in a pretty random order. To sort the list, you call its sort() method, which will sort it in-place. What that means is that sort() does not return anything.

        A common misconception with Python is that if you call sort(), you can assign the result to a variable, like this:

        >>> sorted_list = my_list.sort()
        >>> print(sorted_list)
        None

        However, when you do that, you will see that sort() doesn’t actually return a sorted list. It always returns None.

        Fortunately you can use Python’s built-in sorted() method for this too:

        >>> my_list = [4, 10, 2, 1, 23, 9]
        >>> sorted_list = sorted(my_list)
        >>> sorted_list
        [1, 2, 4, 9, 10, 23]

        If you use sorted(), it will return a new list, sorted ascending by default. The sorted() function will also allow you to sort by a specified key and you can tell it to sort ascending or descending by setting its reversed flag.

        Let’s sort this list in descending order instead:

        >>> my_list = [4, 10, 2, 1, 23, 9]
        >>> sorted_list = sorted(my_list, reverse=True)
        >>> sorted_list
        [23, 10, 9, 4, 2, 1]

        When you have a more complicated data structure, such as a nested list or a dictionary, you can use sorted() to sort in special ways, such as by key or by value.

        List Slicing

        Python lists support the idea of slicing. Slicing a list is done by using square brackets and entering a start and stop value. For example, if you had my_list[1:3], you would be saying that you want to create a new list with the element starting at index one through 3 but not including index 3.

        Here is an example:

        >>> my_list = [4, 10, 2, 1, 23, 9]
        >>> my_list[1:3]
        [10, 2]

        This slice returns index 1 (10) and index 2 (2) as a new list.

        You can also use negative values to slice:

        >>> my_list = [4, 10, 2, 1, 23, 9]
        >>> my_list[-2:]
        [23, 9]

        In this example, you didn’t specify an end value. That means you want to start at the second to last item in the list, 23, and take it to the end of the list.

        Let’s try another example where you specify only the end index:

        >>> my_list = [4, 10, 2, 1, 23, 9]
        >>> my_list[:3]
        [4, 10, 2]

        In this example, you want to grab all the values starting at index 0 up to but not including index 3.

        Copying a List

        Occasionally you will want to copy a list. One simple way to copy your list is to use the copy method:

        >>> my_list = [1, 2, 3]
        >>> new_list = my_list.copy()
        >>> new_list
        [1, 2, 3]

        This successfully creates a new list and assigns it to the variable, new_list.

        However note that when you do this, you are creating what is known as a “shallow copy”. What that means is that if you were to have objects in your list, they can be changed and it will affect both lists. For example, if you had a dictionary in your list and the dictionary was modified, both lists will change, which may not be what you want.

        You can also copy a list by using this funny syntax:

        >>> my_list = [1, 2, 3]
        >>> new_list = my_list[:]
        >>> new_list
        [1, 2, 3]

        This example is telling Python to create a slice from the 0 (first) element to the last, which in effect is the copy of the whole list.

        You could also use Python’s list() function to copy a list:

        >>> my_list = [1, 2, 3]
        >>> new_list = list(my_list)
        >>> new_list
        [1, 2, 3]

        No matter which method you choose though, whether it by [:], copy() or list(), all three will do a shallow copy. If you run into weird issues where changing one list affects the copied list, then you should use deepcopy method from the copy module instead.

        Wrapping Up

        In this article, you learned all about Python’s wonderful list data type. You will be using lists extensively when you are programming in Python. Here you learned how to create lists, edit them and remove items from them. You learned how to clear a list completely. You discovered how to sort a list as well as how to slice a list. Finally, you learned all about copying lists and the pitfalls that can happen when you do so.

        The post Python 101: Learning About Lists appeared first on The Mouse Vs. The Python.

        Mike Driscoll: Python 101: Learning About Lists

        $
        0
        0

        Lists are a fundamental data type in the Python programming language. A list is a mutable sequence that is typically a collection of homogeneous items. Mutable means that you can change a list after its creation. You will frequently see lists that contain other lists. These are known as nested lists. You will also see lists that contain all manner of other data types, such as dictionaries, tuples or objects.

        Let’s find out how you can create a list!

        Creating Lists

        There are several ways to create a list. You may construct a list in any of the following ways:

        • Using a pair of square brackets with nothing inside creates an empty list: []
        • Using square brackets with comma-separated items: [1, 2, 3]
        • Using a list comprehension: [x for x in iterable]
        • Using the list() function: list(iterable)

        An iterable is a sequence, a container that supports iteration or an iterator object. Lists themselves are sequences as are strings.

        Let’s look at a few examples of creating a list so you can see it in action:

        >>> my_list = [1, 2, 3]
        >>> my_list
        [1, 2, 3]

        This first example is pretty straight-forward. Here you create a list with 3 numbers in it. Then you print it out to verify that it contains what you think it should.

        The next way to create a list is by using Python’s built-in list() function:

        >>> list_of_strings = list('abc')
        >>> list_of_strings
        ['a', 'b', 'c']

        In this case, you pass a string of three letters to the list() function. It automatically iterates over the characters in the string to create a list of three string, where each string is a single character.

        The last example to look at is how to create empty lists:

        >>> empty_list = []
        >>> empty_list
        []
        >>> another_empty_list = list()
        >>> another_empty_list
        []

        The quickest way to create an empty list is by using the square brackets without putting anything inside them. The second easiest way is to call list() without any arguments. The nice thing about using list() in general is that you can use it to cast a compatible data type to a list, as you did with the string, “abc”, in the example earlier.

        List Methods

        A Python list has several methods that you can call. Here is a listing of the methods you can use with a list:

        • append()
        • clear()
        • copy()
        • count()
        • extend()
        • index()
        • insert()
        • pop()
        • remove()
        • reverse()
        • sort()

        Most of these will be covered in the following sections. Let’s talk about the ones that aren’t covered in a specific section first.

        You can use count() to count the number of instances of the object that you passed in.

        Here is an example:

        >>> my_list = list('abcc')
        >>> my_list.count('a')
        1
        >>> my_list.count('c')
        2

        This is a simple way to count the number of occurrences of an item in a list.

        The index() method is useful for finding the first instance of an item in a list:

        >>> my_list = list('abcc')
        >>> my_list.index('c')
        2
        >>> my_list.index('a')
        0

        Python lists are zero-indexed, so “a” is in position 0, “b” is at position 1, etc.

        You can use the reverse() method to reverse a list in-place:

        >>> my_list = list('abcc')
        >>> my_list.reverse()
        >>> my_list
        ['c', 'c', 'b', 'a']

        Note that the reverse() method returns None. What that means is that if you try to assign the reversed list to a new variable, you may end up with something unexpected:

        >>> x = my_list.reverse()
        >>> print(x)
        None

        Here you end up with None instead of the reversed list. That is what in-place means. The original list is reversed, but the reverse() method itself doesn’t return anything.

        Now let’s find out what you can do with the other list methods!

        Adding to a List

        There are three list methods that you can use to add to a list. They are as follows:

        • append()
        • extend()
        • insert()

        The append() method will add an item to the end of a pre-existing list:

        >>> my_list = list('abcc')
        >>> my_list
        ['a', 'b', 'c', 'c']
        >>> my_list.append(1)
        >>> my_list
        ['a', 'b', 'c', 'c', 1]

        First you create a list that is made up of four one-character strings. Then you append an integer to the end of the list. Now the list should have 5 items in it with the 1 on the end.

        You can use Python’s built-in len() function to check the number of items in a list:

        >>> len(my_list)
        5

        So this tells you that you do in fact have five items in the list. But what if you wanted to add an element somewhere other than the end of the list?

        You can use insert() for that:

        >>> my_list.insert(0, 'first')
        >>> my_list
        ['first', 'a', 'b', 'c', 'c', 1]

        The insert() method takes two arguments:

        • The position at which to insert
        • The item to insert

        In the code above, you tell Python that you want to insert the string, “first”, into the 0 position, which is the first position in the list.

        There are two other ways to add items to a list. You can add an iterable to a list using extend():

        >>> my_list = [1, 2, 3]
        >>> other_list = [4, 5, 6]
        >>> my_list.extend(other_list)
        >>> my_list
        [1, 2, 3, 4, 5, 6]

        Here you create two lists. Then you use my_list‘s extend() method to add the items in other_list to my_list. extend() will iterate over the items in the passed in list and add each of them to the list.

        You can also combine lists using concatenation:

        >>> my_list = [1, 2, 3]
        >>> other_list = [4, 5, 6]
        >>> combined = my_list + other_list
        >>> combined
        [1, 2, 3, 4, 5, 6]

        In this case, you create two lists and then combine them using Python’s + operator.

        You can also use += with Python lists:

        >>> my_list = [1, 2, 3]
        >>> other_list = [4, 5, 6]
        >>> my_list += other_list
        >>> my_list
        [1, 2, 3, 4, 5, 6]

        This is a somewhat simpler way to combine the two lists.

        Now let’s learn how to access and change elements within a list.

        Accessing and Changing List Elements

        Lists are made to be worked with. You will need to learn how to access individual elements as well as how to change them.

        Let’s start by learning how to access an item:

        >>> my_list = [1, 2, 3]
        >>> my_list[0]
        1
        >>> my_list[2]
        3

        To access an item in a list, you need to use square braces and pass in the index of the item that you wish to access. In the example above, you access the first and third elements.

        Lists also support accessing items in reverse by using negative values:

        >>> my_list[-1]
        3

        This example demonstrates that when you pass in -1, you get the last item in the list returned. Try using some other values and see if you can get the first item using negative indexing.

        If you try to use an index that does not exist in the list, you will get an IndexError:

        >>> my_list[-5]
        Traceback (most recent call last):
        Python Shell, prompt 41, line 1
        builtins.IndexError: list index out of range

        Now let’s learn about removing items!

        Deleting From a List

        Deleting items from a list is pretty straight-forward. There are 4 primary methods of removing items from a list:

        • clear()
        • pop()
        • remove()
        • del

        You can use clear() to remove everything from the list. Let’s see how that works:

        >>> my_list = [1, 2, 3]
        >>> my_list.clear()
        >>> my_list
        []
        

        After calling clear(), the list is now empty. This can be useful when you have finished working on the items in the list and you need to start over from scratch. Of course, you could also do this instead of clear():

        >> my_list = []

        This will create a new empty list. If it is important for you to always use the same object, then using clear() would be better. If that does not matter, then setting it to an empty list will work well too.

        If you would rather remove individual items, then you should check out pop() or remove(). Let’s start with pop():

        >>> my_list = [1, 2, 3]
        >>> my_list.pop()
        3
        >>> my_list
        [1, 2]

        You can pass an index to pop() to remove an item and return it. Or you can call pop() without an argument like in the example above and it will default to removing the last item in the list and returning it. pop() is the most flexible way of removing items from a list.

        If the list is empty or you pass in an index that does not exist, pop() will throw an exception:

        >>> my_list.pop(10)
        Traceback (most recent call last):
          Python Shell, prompt 50, line 1
        builtins.IndexError: pop index out of range

        Now let’s take a look at how remove() works:

        >>> my_list = [1, 2, 3]
        >>> my_list.remove(2)
        >>> my_list
        [1, 3]

        remove() will delete the first instance of the passed in item. So in this case, you tell the list to remove the first occurrence of the number 2.

        If you tell remove() to delete an item that is not in the list, you will receive an exception:

        >>> my_list.remove(4)
        Traceback (most recent call last):
          Python Shell, prompt 51, line 1
        builtins.ValueError: list.remove(x): x not in list

        You can also use Python’s built-in del keyword to delete items from a list:

        >>> my_list.remove(4)
        Traceback (most recent call last):
          Python Shell, prompt 51, line 1
        builtins.ValueError: list.remove(x): x not in list

        You can also use Python’s built-in del keyword to delete items from a list:

        >>> my_list = [1, 2, 3]
        >>> del my_list[1]
        >>> my_list
        [1, 3]

        You will receive an error if you try to remove an index that does not exist:

        >>> my_list = [1, 2, 3]
        >>> del my_list[6]
        Traceback (most recent call last):
          Python Shell, prompt 296, line 1
        builtins.IndexError: list assignment index out of range

        Now let’s learn about sorting a list!

        Sorting a List

        Lists in Python can be sorted. You can use the built-in sort() method to sort a list in-place or you can use Python’s sorted() function.

        Let’s create a list and try sorting it:

        >>> my_list = [4, 10, 2, 1, 23, 9]
        >>> my_list.sort()
        >>> my_list
        [1, 2, 4, 9, 10, 23]

        Here you create a list with 6 integers in a pretty random order. To sort the list, you call its sort() method, which will sort it in-place. What that means is that sort() does not return anything.

        A common misconception with Python is that if you call sort(), you can assign the result to a variable, like this:

        >>> sorted_list = my_list.sort()
        >>> print(sorted_list)
        None

        However, when you do that, you will see that sort() doesn’t actually return a sorted list. It always returns None.

        Fortunately you can use Python’s built-in sorted() method for this too:

        >>> my_list = [4, 10, 2, 1, 23, 9]
        >>> sorted_list = sorted(my_list)
        >>> sorted_list
        [1, 2, 4, 9, 10, 23]

        If you use sorted(), it will return a new list, sorted ascending by default. The sorted() function will also allow you to sort by a specified key and you can tell it to sort ascending or descending by setting its reversed flag.

        Let’s sort this list in descending order instead:

        >>> my_list = [4, 10, 2, 1, 23, 9]
        >>> sorted_list = sorted(my_list, reverse=True)
        >>> sorted_list
        [23, 10, 9, 4, 2, 1]

        When you have a more complicated data structure, such as a nested list or a dictionary, you can use sorted() to sort in special ways, such as by key or by value.

        List Slicing

        Python lists support the idea of slicing. Slicing a list is done by using square brackets and entering a start and stop value. For example, if you had my_list[1:3], you would be saying that you want to create a new list with the element starting at index one through 3 but not including index 3.

        Here is an example:

        >>> my_list = [4, 10, 2, 1, 23, 9]
        >>> my_list[1:3]
        [10, 2]

        This slice returns index 1 (10) and index 2 (2) as a new list.

        You can also use negative values to slice:

        >>> my_list = [4, 10, 2, 1, 23, 9]
        >>> my_list[-2:]
        [23, 9]

        In this example, you didn’t specify an end value. That means you want to start at the second to last item in the list, 23, and take it to the end of the list.

        Let’s try another example where you specify only the end index:

        >>> my_list = [4, 10, 2, 1, 23, 9]
        >>> my_list[:3]
        [4, 10, 2]

        In this example, you want to grab all the values starting at index 0 up to but not including index 3.

        Copying a List

        Occasionally you will want to copy a list. One simple way to copy your list is to use the copy method:

        >>> my_list = [1, 2, 3]
        >>> new_list = my_list.copy()
        >>> new_list
        [1, 2, 3]

        This successfully creates a new list and assigns it to the variable, new_list.

        However note that when you do this, you are creating what is known as a “shallow copy”. What that means is that if you were to have objects in your list, they can be changed and it will affect both lists. For example, if you had a dictionary in your list and the dictionary was modified, both lists will change, which may not be what you want.

        You can also copy a list by using this funny syntax:

        >>> my_list = [1, 2, 3]
        >>> new_list = my_list[:]
        >>> new_list
        [1, 2, 3]

        This example is telling Python to create a slice from the 0 (first) element to the last, which in effect is the copy of the whole list.

        You could also use Python’s list() function to copy a list:

        >>> my_list = [1, 2, 3]
        >>> new_list = list(my_list)
        >>> new_list
        [1, 2, 3]

        No matter which method you choose though, whether it by [:], copy() or list(), all three will do a shallow copy. If you run into weird issues where changing one list affects the copied list, then you should use deepcopy method from the copy module instead.

        Wrapping Up

        In this article, you learned all about Python’s wonderful list data type. You will be using lists extensively when you are programming in Python. Here you learned how to create lists, edit them and remove items from them. You learned how to clear a list completely. You discovered how to sort a list as well as how to slice a list. Finally, you learned all about copying lists and the pitfalls that can happen when you do so.

        The post Python 101: Learning About Lists appeared first on The Mouse Vs. The Python.

        Continuum Analytics Blog: Anaconda Individual Edition 2020.02: New Name, Exciting Features

        Kushal Das: More power to you my friend

        $
        0
        0

        With Chelsea and Micah

        Today marks 365 days of incarceration of Chelsea Manning, with around $256000 in fines. She has not been charged for any crime.

        At home, Py (daughter) wanted to know why her Wonder Woman is still in the dungeon? We had to explain Grand jury subpoena to her in simple terms and explain that her Wonder Woman aunty is resisting it, even though that means she is in a dungeon (where most good people go when they fight for truth against the big powers of the world). Py now wants to go to USA and meet Chelsea. The other day, Py also declared that after growing up she will fight for others and go to dungeon just like Chelsea.

        Chelsea spoke about her believes and principles again and again, and why did she feel that leaking the war crimes to the world was her duty. By the same principles, she is standing up to the secret hearings of grand juries now. Everyone knows that there is good reason to put her back into the prison system, but the government still did that.

        UN officials already accused the US government of using torture against Chelsea. The officials also mentioned to the US government:

        believe that subjecting Chelsea to more punishment will change her mind, they are gravely mistaken.

        After waking up today morning, I suddenly found she again tried to commit suicide and now recovering in the hospital. She had previously spent 7+years in prison including 11 months of solitary confinement, and these things in total causes a lot of mental health issues.

        I hope for her speedy recovery and also hope someone in the US judicial system will see the injustice to her and release her soon. Meanwhile, we all can send her letters (on white paper, handwritten or drawn) to the following address:

        Chelsea Elizabeth Manning
        A0181426
        William G. Truesdale Adult Detention Center
        2001 Mill Road
        Alexandria, VA 22314
        

        You can also read her statement released on Aaron Swartz Day 2019.


        Quansight Labs Blog: uarray: GSoC Participation

        $
        0
        0

        I'm pleased to announce that uarray is participating in GSoC '20 as a sub-organization under the umbrella of the Python Software Foundation. Our ideas page is up here, go take a look and see if you (or someone you know) is interested in participating, either as a student or as a mentor.

        Prasun Anand and Peter Bell and myself will be mentoring, and we plan to take a maximum of two students, unless more community mentors show up.

        There have been quitea fewpull requests already to qualify from prospective students, some even going as far as to begin the work described in the idea they plan to work on.

        We're quite excited by the number of students who have shown an interest in participating, and we look forward to seeing excellent applications! What's more exciting, though, are some of the first contributions from people not currently at Quansight, in the true spirit of open-source software!

        Django Weblog: New governance model for the Django project

        $
        0
        0

        For some time now, a proposal to change the governance of the Django open-source project has been under discussion and refinement. It was written up as a Django Enhancement Proposal (DEP), and numbered as DEP 10.

        Changing the governance of the Django project is not something to do lightly, and not something that could be done lightly. It required the agreement of the Django core team, the Django Technical Board, and the Board of Directors of the Django Software Foundation. All of those groups have now held their deliberations, and voted to accept DEP 10.

        In the coming weeks, implementation of DEP 10 will start in earnest, but today it's worth giving a quick summary of what's changing and why. For the full details you can also read the DEP (though keep in mind it's a governance document that tries to be as precise as possible and cover a lot of potential edge cases, and so is a bit long-winded and dry).

        History and rationale

        The Django open-source project was started by Adrian Holovaty and Jacob Kaplan-Moss, who also served as the first leaders of the project. They made the first few grants of commit access to other people back in the early days after Django was open-sourced, and the core team of committers had grown significantly by 2014, when Adrian and Jacob chose to step down from their leadership roles. At that time the basic structure, of a core team of committers who could add code to Django as they chose, was retained, and a new group -- a "Technical Board" of five committers, elected by the core committers -- was created to serve as an ultimate tie-breaking decision-maker.

        In practice, however, almost all code added to Django now is merged by the Django Fellows -- paid contractors of the Django Software Foundation, whose responsibilities include triaging, reviewing, and merging pull requests to Django -- or by a small number of active volunteer committers. And all releases of Django are now issued by the Fellows, on schedules decided well in advance. Which means most of the historical "core team" of committers now have very little direct involvement with Django despite holding significant theoretical power within the project. And instead of committers discussing and deciding amongst themselves, nearly all technical decisions in Django's development are made by consensus on public forums where anyone can participate.

        Additionally, the growth of that "core team" has slowed almost to a standstill; new committers are added only very rarely, and there's neither a clear path to "core" status nor any way for someone to tell whether they are, or could be, a good candidate for it. Discussions on project mailing lists and in-person at conferences have also indicated that many potential contributors measure themselves against an unrealistic idea of both their own capabilities, and of the prowess of the existing "core" developers, which has the effect of discouraging perfectly well-qualified people from attempting to get more seriously involved in contributing to Django.

        All of this is frustrating for everyone, and not good for Django's long-term health as a project. Replacing or reforming "Django core" and the project's governance has thus become a perennial topic of long discussions, especially among the current "core" team and groups like the DSF membership.

        What's changing

        As of the adoption of DEP 10, the structure of the Django open-source project is changing in several ways. The former "core team" is now dissolved, and the commit access of the former "core" members will be removed. A new role -- "Merger" -- is being created, and will have commit access, but only to merge pull requests from others: Mergers cannot decide to add things to Django on their own initiative, and hold no special decision-making privileges.

        Alongside this, a new role of "Releaser" is being created, and will have access to issue releases of Django and carry out the associated mechanics (like bumping version numbers in key files).

        Technical decisions are already, in practice, made by consensus in public venues where anyone can participate; this is now formalized as the primary and expected way Django will be developed, and there will not be any special class of "committers" or "core" individuals with special power to commit or block something solely on their own say-so.

        The Technical Board will be kept as a final decision-making authority for cases where this is needed -- which have historically come up only rarely -- and is also charged with canvassing for ideas and proposals for Django's future technical direction, and with setting the release schedule.

        However, membership on the Technical Board will no longer be restricted to committers, and the Technical Board will no longer be elected by committers, which is necessary because the "core" committers, as a group, cease to exist. Instead, anyone who demonstrates a history of technical contributions to Django is eligible to run for the Technical Board, and the Technical Board will be elected by the DSF's Individual members, all of whom have been granted that membership based on their involvement with and contributions to Django (and there are provisions for non-DSF-member voters in the rare case where someone who's been involved with Django does not hold DSF membership). This expands Technical Board elections from having around 50 potential voters (with the old model of only committers voting) to currently nearly 200, and quite likely more as the DSF's membership grows.

        Both the voter rolls, and the elections of the Technical Board, will be overseen by the Board of Directors of the DSF (with any DSF Board member who runs for the Technical Board having to abstain from involvement in election oversight), which will have the authority to investigate the qualifications and good faith of both candidates and voters.

        Finally, the term "Django Core Developer" is being repurposed as an honorary title, bestowed by the DSF on individuals who've had major, long-term impact on the history of Django, similar to the "Fellow of the Python Software Foundation" honor bestowed by the PSF for contributions to Python. This title will be automatically granted to anyone who held "core" status -- in any of several forms, because that term has been nebulous on occasion -- at any time prior to DEP 10's adoption.

        Effective immediately the Django Fellows, currently Carlton Gibson and Mariusz Felisiak, are the initial Mergers and Releasers, and the Django Technical Board will appoint additional people into those roles as needed to keep them properly staffed. The current Technical Board and the DSF Board also will work to hold the first election of a new Technical Board under DEP 10, which will be held once the necessary registration and voting infrastructure are in place.

        There will also be a flurry of updates to documentation and other parts of the Django project website to ensure the new process and structure are described as accurately as possible. Until then, please refer people to this blog post for its summary of what's happening, or to the text of DEP 10 for the full details.

        The future

        Later this year we'll be celebrating the 15th anniversary of the original open-sourcing of Django. In that time, there have been 278 releases of the framework, nearly 1,900 people have contributed to the primary repository, and the number of people who've learned and used Django is nearly impossible to measure; the main django-users mailing list has tens of thousands of members, and is certain to represent only a fraction of the global Django-using community.

        It's the hope of everyone who worked on this proposal that formally opening up Django's governance and decision-making will put the project on a healthier and more sustainable footing for the long term, and remove one of the barriers (the effective obsolescence of the "Django core" and stagnation of its membership) to welcoming new contributors to Django from all parts of its worldwide community.

        EuroPython: EuroPython 2020 and COVID-19

        $
        0
        0

        As you probably already know, the Coronavirus is spreading throughout Europe and we wanted to give you an update on our current plans around on the situation.

        We will update this blog post as new information becomes available.

        2020-03-12:

        The number of cases in Ireland is still low compared to other countries, but the Irish government is already starting to put limited bans on larger indoor events.

        Since EuroPython is planned for July 20-26, we are hopeful that the situation will have improved by then and continue the conference planning with the aim of having the conference on the planned date.

        We would still like to ask all attendees to take the necessary and recommended hygienic precautions when attending the event and pay close attention to your country’s travel guidelines. If you don’t feel well, please do not attend the conference - instead, please follow the COVID-19 advice of the Irish Health Service. We will refund your ticket.

        Should the conference need to be canceled as a result of the official ban still being in effect in July, we will refund all tickets - even after the official refund cut-off date (June 19th). We are in discussion with the venue to explore options in case the conference has to be canceled, which we will share with you soon as we have any update.

        Because the situation is very much in flux, we would recommend that you make booking arrangements with an option to cancel the booking closer to the event date.

        Resources:

        Thanks,

        EuroPython 2020 Team
        https://ep2020.europython.eu/
        https://www.europython-society.org/

        PyCon: March 12 Update on COVID-19

        $
        0
        0
        With a month until PyCon US 2020’s scheduled start, the Python Software Foundation Board and Staff are working through our options for PyCon US 2020, and will keep you updated as decisions are made.

        In the meantime, remember that PyCon US will refund any tickets with no questions asked. You do not need to commit to travel to PyCon US at this point in time if you do not want to.

        The Foundation is currently exploring options to re-schedule or cancel the conference. Any final decision to cancel or reschedule PyCon US will be made early enough to give you time to cancel or defer your travel plans.

        We continue to monitor advice from the Federal, Pennsylvania, Allegheny County, and Pittsburgh Governments, and our planning is taking this advice into account.


        We’d like to explain why this decision – and any announcement – is taking time.

        A decision to reschedule or cancel PyCon US needs to be made with the best interests of the international Python community in mind. First and foremost is the health and safety of everyone in the community, and the Foundation understands the risk that a large gathering like PyCon US poses to the community. It is front of mind in every discussion we are having at the moment.

        On the other hand, the Foundation has a mission to support the global Python community, and does so through grants, sponsorships, and funding core infrastructure that the community relies on.
        PyCon US is the majority source of the Foundation’s revenue.

        Since the last time PyCon US returned a loss, the Python Software Foundation has grown and managed a cash reserve to handle the (usually unlikely) case of PyCon US not proceeding due to unforeseen circumstances. Keeping this reserve healthy allows us to plan future PyCons with confidence, while still building our support for the community.

        Running a conference at PyCon US’s scale involves signing contracts with many vendors, and in most cases, cancelling contracts exposes the Foundation to penalties. If we were to cancel PyCon US now, beyond simply cancelling the event and forgoing sponsorship and ticket revenue, we may need to pay out substantial amounts of money in penalties.

        Those penalties would need to be paid out of our cash reserve, so the Foundation would, for the foreseeable future, need to work on rebuilding its cash reserve instead of running the programs the community has come to expect from us.

        During that period of rebuilding, another event like what we are facing this year would be a significant setback to the Foundation.

        One option that would reduce our exposure to penalties would be official government advice restricting conferences in Pittsburgh, preventing PyCon US from being held.

        Therefore, the Foundation is presently investigating options to reduce the long-term damage that rescheduling or cancelling PyCon US would cause to the community. We believe there are options available to us that will allow the Foundation to run as expected over the coming years.

        We appreciate the patience you’re showing as we work through this difficult situation.

        We will provide another update, on or before Friday March 20th.

        This post is authored by the PSF Board of Directors

        Will McGugan: Progress bars with Rich

        $
        0
        0

        I've added progress bar support to Rich.

        If you haven't seen my earlier posts on the subject, Rich is a terminal rendering framework for Python. It lets you render styled text and a whole bunch of other things (markdown, syntax, tables, tracebacks, etc.) to the terminal.

        This latest addition to the lib renders progress bars with additional information such as percentage completed, time remaining, data transfer speed etc. It's highly configurable, so you can customize it to show whatever information you like. And since it's implemented as a Rich renderable, you can easily add color and formatting. Here's what it looks like:

        © 2020 Will McGugan

        An example of Rich progress bars

        As you can see it supports multiple bars, which makes it useful for displaying progress of concurrent tasks. See downloader.py for an example which uses Rich to display progress of concurrent downloads.

        Pogress bars are in Rich 0.7.0, now on Pypi.

        This is the last major feature planned before a 1.0 release of Rich. Tweet @willmcgugan if you have any feedback or requests.

        Viewing all 22419 articles
        Browse latest View live


        <script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>