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

TechBeamers Python: Python Map()

$
0
0

Python map() function applies another function on a given iterable (List/String/Dictionary, etc.) and returns map object. In simple words, it traverses the list, calls the function for each element, and returns the results. Python map object is also iterable holding the list of each iteration. We can also convert it to List or Dictionary or other types using their constructor functions. In this tutorial, you’ll learn how to use the map() function with different types of sequences. Also, you can refer to the examples that we’ve added to bring clarity. Python Map() Function Explained Python Map() Function The map() function

The post Python Map() appeared first on Learn Programming and Software Testing.


Stéphane Wirtel: PyCon Germany 2019

$
0
0
Speaker at PyCon.DE 2019 Voilà, during the last week, I received very good news, I will be a speaker at PyCon.DE 2019 in Berlin in October 2019. I will present my new talk What’s new in Python 3.8? So, good luck to the other speakers and I hope to see you there. Stéphane

Mike Driscoll: PyDev of the Week: Raphael Pierzina

$
0
0

This week we welcome Raphael Pierzina (@hackebrot) as our PyDev of the Week! Raphael is a core developer of pytest, a popular testing framework for Python. You can learn more about Raphael by visiting his blog or checking out his Github profile. Let’s take a few moments to get to know Raphael!

Can you tell us a little about yourself (hobbies, education, etc)

My background is in 3D visualization and animation. After graduating from university with a Bachelor of Arts in Design, I worked as a software developer for a visual effects company for a few years and built applications for digital artists.

Fast forward to today, after having worked at a few other software companies, I’m now at Mozilla where I work on Firefox Telemetry. I manage projects to reduce Telemetry related blind-spots in our Firefox browser products and support our Software Engineers and Data Engineers in increasing the automated test coverage for the Firefox Telemetry component and our Firefox Data Platform. I wrote about my first year at Mozilla on my blog earlier this year in February, if you’d like to find out more about my work.

For fun, I like to run fast, read books, and enjoy the outdoors. 🏔

 Raphael PierzinaRaphael Pierzina

Why did you start using Python?

Back when I worked in VFX, my team developed plugins for several 3D computer graphic applications in whatever scripting language these programs supported:

  • MaxScript in 3ds Max
  • MEL in Maya
  • TCL in Nuke
  • ZScript in ZBrush
  • C# in Unity

We often had to develop similar features for the different programs in the respective languages, which was not only tedious but also felt really unnecessary.

When I first learned about PyPI and the many awesome frameworks, libraries, and CLI apps that the Python community created and published under open-source licenses, I immediately fell in love with Python and started to look for ways to get involved and contribute back to Python projects that seemed welcoming to newcomers, like for example cookiecutter. 🍪

What other programming languages do you know and which is your favorite?

Aside from the scripting languages that I’ve mentioned earlier, I learned C++ and Java at university, but I wouldn’t say I know those as I haven’t used them in years. I’ve done a fair bit in Go for a previous job and for personal projects, but Python is definitely what I feel most proficient in. I recently started learning Rust and really like it so far.

While I don’t always enjoy coding in Python (I’ve worked on adding Python 3 support to way too many projects at this point and still support Python 2 in the majority of the projects that I maintain), Python is still my favorite programming language!

Through my involvement in several open-source Python projects, from attending and speaking at Python conferences and meetups, and interactions on Twitter, I have made a lot of friends in the Python community. If you see me at EuroPython or PyCon DE this year, please say hi!

What projects are you working on now?

I currently work on open-source projects at Mozilla as well as cookiecutter, pytest, and a number of smaller projects like cookiecutter-pytest-plugin, pytest-cookies, pytest-md, and labels.

My priorities have changed over the past year or two and I now focus on mentoring and teaching through speaking at conferences and meetups, writing on my blog and posting on my twitter.

Which Python libraries are your favorite (core or 3rd party)?

I’m a big fan of attrs, click, and pytest. 🚀

What lessons have you learned as a maintainer?

Setting expectations and being able to say “No” is really important. Allow yourself to take breaks or even walk away from your projects. Take care of yourself!

I gave a talk about the challenges of maintaining a popular open-source project at EuroPython in 2018. While this talk might not have quite as many views on YouTube as some of my other talks, it was very important to me to share what I’ve learned from maintaining cookiecutter for several years and I hope it helps folks who find themselves in a similar position.

Thanks for doing the interview, Raphael!

The post PyDev of the Week: Raphael Pierzina appeared first on The Mouse Vs. The Python.

codingdirectional: Change python string to lower or upper case

$
0
0

In this article, we will create a function which will take in a string and then change the word within that string to either all uppercases if most of the words within that string are uppercase or all lowercases if most of those words are either lowercase or the word counts for the uppercase word and lowercase word are equal.

def solve(s):
    list_string = list(s)
    upper = 0
    lower = 0
    for word in list_string:
        if word.isupper():
            upper += 1
        else:
            lower += 1
    if upper > lower :
        return s.upper()
    elif upper < lower:
        return s.lower()
    else:
        return s.lower()

Very simple solution, if you have better idea leave your comment below.

Talk Python to Me: #225 Can subinterpreters free us from Python's GIL?

$
0
0
Have you heard that Python is not good for writing concurrent asynchronous code? This is generally a misconception. But there is one class of parallel computing that Python is not good at: CPU bound work running the Python layer.

Erik Marsja: Repeated Measures ANOVA in R and Python using afex & pingouin

$
0
0

In this post we will learn how to carry out repeated measures Analysis of Variance (ANOVA) in R and Python. To be specific, we will use the R package afex and the Python package pingouin to carry out one-way and two-way ANOVA f or within subject’s design. The structure of the following data analysis tutorial is as follows; a brief introduction to (repeated measures) ANOVA, carrying out within-subjects ANOVA in R using afex and in Python using pingouin. In the end, there will be a comparison of the results and the pros and cons using R or Python for data analysis (i.e., ANOVA).

What is ANOVA?

Before we go into how to carry out repeated measures ANOVA in R and Python, we are briefly going to learn what an ANOVA is. An ANOVA test is a parametrical method to find out whether the results from collected data are significant. That is, this type of test will enable us to figure out whether we should to reject the null hypothesis or accept the alternate hypothesis. In a between ANOVA we’re testing groups to see if there’s a statistical difference between them. In this post we are going to learn to do repeated measures ANOVA, however, and using this method we compare means across one or more variables that are based on repeated observations. These repeated observations can either be time points or different conditions. In the repeated ANOVA examples below we use different conditions.

For more information about ANOVA:

Data

In this repeated measures ANOVA example, we will use fake data (can be downloaded here). This fake data is a sample of 60 adults responding as fast as they can to visual stimuli. This, the dependent variable (DV) is response time to the visual stimuli. While the subjects were categorizing visual stimuli, they were either exposed to background noise or quiet (independent variable, iv1).

In the first example, we are going to use these two conditions (iv1) when we carry out a one-way ANOVA for repeated measures. Furthermore, the visual stimuli could either be presented in the upper part, lower part, or in the middle part of the computer screen (independent variable, iv2).

The variables given in the data set:

  • Sub_id = Subject ID #
  • iv1 = Noise condition; quiet or noise
  • iv2 = Location condition; upper, lower, middle
  • DV = response time

Repeated Measures ANOVA in R

In this section we are going to learn how to do a repeated measures ANOVA in R using afex. More specifically, we are going to learn how carry out a one-way and two-way ANOVA using the aov_ez function. Note, working with aov_ez function we need to have our data in long format.

Installing afex

First, we are going to install the needed package: afex. In the code chunk, below , the package will only be installed if it’s not already installed.

list.of.packages <- c("afex", "emmeans")
new.packages <- list.of.packages[!(list.of.packages %in% installed.packages()[,"Package"])]
if(length(new.packages)) install.packages(new.packages)

One-Way Repeated Measures ANOVA in R.

In the first example, we are going to carry out a one-way repeated measures ANOVA in R using aov_ez. Here we want to know whether there is any difference in response time with background noise compared to without background noise. To test this, we need to conduct a within-subjects ANOVA.

In the first code chunk, below, we load the package, the data, and print the first 5 rows using head

require(afex)

df <- read.csv(file='./Python_ANOVA/rmAOV2way.csv',
     header=TRUE, sep=',')

head(df)

Example ANOVA for Within-Subjects Design:

aov <- aov_ez('Sub_id', 'rt',
              fun_aggregate = mean, df, within = 'iv1')
print(aov)

Two-Way Repeated Measures ANOVA in R

In the second example, we are going to conduct a two-way repeated measures ANOVA in R. Here we want to know whether there is any difference in response time during background noise compared to without background noise, and whether there is a difference depending on where the visual stimuli are presented (up, down, middle). Finally, we are interested if there is an interaction between the noise and location conditions.

aov <- aov_ez('Sub_id', 'rt', fun_aggregate = mean,
              df, within = c('iv1', 'iv2'))
print(aov)
  

Plotting an Interaction

The R package afex also have a function to plot an interaction. Now, before continuing with the Python ANOVA, we are going to use this function.

afex_plot(aov, x = "iv1", trace = "iv2",
         error = "within")
  

As can be seen, and confirmed by the ANOVA table above, we see that there is no interaction. If we had an interaction, we could follow this up with pairwise comparisons using the package emmeans.

Here’s a Jupyter Notebook containing the above code examples.

Repeated Measures ANOVA in Python

Now that we know how to conduct a within-subjects ANOVA in R we are going to carry out the same ANOVA in Python. In a previous post, we learned how to use the class AnovaRM from the Python package Statsmodels. In this post, however, we are going to use the package pingouin and the function anova_rm. Note, this function can handle both a wide and a long format data file.

One-Way Repeated Measures ANOVA in Python

In the first example, we are going to conduct a one-way ANOVA for repeated measures using Python. We start by imporring pandas as pd and pingoin as pg:

import pandas as pd
import pingouin as pg


df = pd.read_csv('./Python_ANOVA/rmAOV2way.csv')
df.head()
   

Learn more about how to work with Pandas dataframe and load data from different file types:

Now we can carry out our repeated measures ANOVA using Python:

aov = pg.rm_anova(dv='rt', within='iv1',
                   subject='Sub_id', data=df, detailed=True)
print(aov.round(2))

Two-Way Repeated Measures ANOVA in Python

In the second example, we are going to carry out a two-way ANOVA for repeated measures using Python.

 aov = pg.rm_anova(dv='rt',
                   within=['iv1', 'iv2'],
                   subject='Sub_id', data=df)
print(aov.round(2))
        

Interaction Plot in Python using Seaborn

For completeness, even though we didn’t have a significant interaction, we are going to create an interaction plot using Seaborn:

import seaborn as sns

ax = sns.pointplot(x="iv1", y="rt", hue="iv2",
                    data=df)
        

Learn more about data visualization in Python:

Pingouin also comes with a function to carry out pairwise comparison. If we had a significant interaction, we could use it. See this post for an example how to use this function.

Here’s a Jupyter Notebook containing the Python ANOVA examples above.

Conclusion: R vs Python

In this post, we have learned how to carry out one-way and two-way ANOVA for repeated measures using R and Python. We have used the r-package afex and the Python package pingouin. Both afex and pingouin are quite similar; they offer the Greenhouse-Geisser correction. In afex, however, you can c hoose to get either partial eta-squared or general eta-squared effect sizes. Furthermore, as can be seen in the ANOVA tables the results are basically the same.

In conclusion, the packages afex and pingouin offers an easy way to carry out ANOVA for within-subject designs in R and Python, respectively.

Resources

Here are some previous posts on how to carry out ANOVA in Python:

 

The post Repeated Measures ANOVA in R and Python using afex & pingouin appeared first on Erik Marsja.

Codementor: How I built a Python text app

$
0
0
This app helps in sending messages to phone numbers using a facility called Twilio.

Podcast.__init__: Learning To Program In Python With CodeGrades

$
0
0
With the increasing role of software in our world there has been an accompanying focus on teaching people to program. There are numerous approaches that have been attempted to achieve this goal with varying levels of success. Nicholas Tollervey has begun a new effort that blends the approach adopted by musicians and martial artists that uses a series of grades to provide recognition for the achievements of students. In this episode he explains how he has structured the study groups, syllabus, and evaluations to help learners build projects based on their interests and guide their own education while incorporating useful skills that are necessary for a career in software. If you are interested in learning to program, teach others, or act as a mentor then give this a listen and then get in touch with Nicholas to help make this endeavor a success.

Summary

With the increasing role of software in our world there has been an accompanying focus on teaching people to program. There are numerous approaches that have been attempted to achieve this goal with varying levels of success. Nicholas Tollervey has begun a new effort that blends the approach adopted by musicians and martial artists that uses a series of grades to provide recognition for the achievements of students. In this episode he explains how he has structured the study groups, syllabus, and evaluations to help learners build projects based on their interests and guide their own education while incorporating useful skills that are necessary for a career in software. If you are interested in learning to program, teach others, or act as a mentor then give this a listen and then get in touch with Nicholas to help make this endeavor a success.

Announcements

  • Hello and welcome to Podcast.__init__, the podcast about Python and the people who make it great.
  • When you’re ready to launch your next app or want to try a project you hear about on the show, you’ll need somewhere to deploy it, so take a look at our friends over at Linode. With 200 Gbit/s private networking, scalable shared block storage, node balancers, and a 40 Gbit/s public network, all controlled by a brand new API you’ve got everything you need to scale up. And for your tasks that need fast computation, such as training machine learning models, they just launched dedicated CPU instances. Go to pythonpodcast.com/linode to get a $20 credit and launch a new server in under a minute. And don’t forget to thank them for their continued support of this show!
  • You listen to this show to learn and stay up to date with the ways that Python is being used, including the latest in machine learning and data analysis. For even more opportunities to meet, listen, and learn from your peers you don’t want to miss out on this year’s conference season. We have partnered with organizations such as O’Reilly Media, Dataversity, Corinium Global Intelligence. Coming up this fall is the combined events of Graphorum and the Data Architecture Summit. The agendas have been announced and super early bird registration for up to $300 off is available until July 26th, with early bird pricing for up to $200 off through August 30th. Use the code BNLLC to get an additional 10% off any pass when you register. Go to pythonpodcast.com/conferences to learn more and take advantage of our partner discounts when you register.
  • Visit the site to subscribe to the show, sign up for the newsletter, and read the show notes. And if you have any questions, comments, or suggestions I would love to hear them. You can reach me on Twitter at @Podcast__init__ or email hosts@podcastinit.com)
  • To help other people find the show please leave a review on iTunes and tell your friends and co-workers
  • Join the community in the new Zulip chat workspace at pythonpodcast.com/chat
  • Your host as usual is Tobias Macey and today Nicholas Tollervey is back to talk about his work on CodeGrades, a new effort that he is building to blend his backgrounds in music, education, and software to help teach kids of all ages how to program.

Interview

  • Introductions
  • How did you get introduced to Python?
  • Can you start by describing what CodeGrades is and what motivated you to start this project?
    • How does it differ from other approaches to teaching software development that you have encountered?
    • Is there a particular age or level of background knowledge that you are targeting with the curriculum that you are developing?
  • What are the criteria that you are measuring against and how does that criteria change as you progress in grade levels?
  • For someone who completes the full set of levels, what level of capability would you expect them to have as a developer?
  • Given your affiliation with the Python community it is understandable that you would target that language initially. What would be involved in adapting the curriculum, mentorship, and assessments to other languages?
    • In what other ways can this idea and platform be adapted to accomodate other engineering skills? (e.g. system administration, statistics, graphic design, etc.)
  • What interesting/exciting/unexpected outcomes and lessons have you found while iterating on this idea?
  • For engineers who would like to be involved in the CodeGrades platform, how can they contribute?
  • What challenges do you anticipate as you continue to develop the curriculum and mentor networks?
  • How do you envision the future of CodeGrades taking ship in the medium to long term?

Keep In Touch

Picks

Links

The intro and outro music is from Requiem for a Fish The Freak Fandango Orchestra / CC BY-SA


Real Python: Your Guide to the Python Print Function

$
0
0

If you’re like most Python users, including me, then you probably started your Python journey by learning about print(). It helped you write your very own hello world one-liner. You can use it to display formatted messages onto the screen and perhaps find some bugs. But if you think that’s all there is to know about Python’s print() function, then you’re missing out on a lot!

Keep reading to take full advantage of this seemingly boring and unappreciated little function. This tutorial will get you up to speed with using Python print() effectively. However, prepare for a deep dive as you go through the sections. You may be surprised how much print() has to offer!

By the end of this tutorial, you’ll know how to:

  • Avoid common mistakes with Python’s print()
  • Deal with newlines, character encodings, and buffering
  • Write text to files
  • Mock print() in unit tests
  • Build advanced user interfaces in the terminal

If you’re a complete beginner, then you’ll benefit most from reading the first part of this tutorial, which illustrates the essentials of printing in Python. Otherwise, feel free to skip that part and jump around as you see fit.

Note:print() was a major addition to Python 3, in which it replaced the old print statement available in Python 2.

There were a number of good reasons for that, as you’ll see shortly. Although this tutorial focuses on Python 3, it does show the old way of printing in Python for reference.

Free Bonus:Click here to get our free Python Cheat Sheet that shows you the basics of Python 3, like working with data types, dictionaries, lists, and Python functions.

Printing in a Nutshell

Let’s jump in by looking at a few real-life examples of printing in Python. By the end of this section, you’ll know every possible way of calling print(). Or, in programmer lingo, you’d say you’ll be familiar with the function signature.

Calling Print

The simplest example of using Python print() requires just a few keystrokes:

>>>
>>> print()

You don’t pass any arguments, but you still need to put empty parentheses at the end, which tell Python to actually execute the function rather than just refer to it by name.

This will produce an invisible newline character, which in turn will cause a blank line to appear on your screen. You can call print() multiple times like this to add vertical space. It’s just as if you were hitting Enter on your keyboard in a word processor.

A newline character is a special control character used to indicate the end of a line (EOL). It usually doesn’t have a visible representation on the screen, but some text editors can display such non-printable characters with little graphics.

The word “character” is somewhat of a misnomer in this case, because a newline is often more than one character long. For example, the Windows operating system, as well as the HTTP protocol, represent newlines with a pair of characters. Sometimes you need to take those differences into account to design truly portable programs.

To find out what constitutes a newline in your operating system, use Python’s built-in os module.

This will immediately tell you that Windows and DOS represent the newline as a sequence of \r followed by \n:

>>>
>>> importos>>> os.linesep'\r\n'

On Unix, Linux, and recent versions of macOS, it’s a single \n character:

>>>
>>> importos>>> os.linesep'\n'

The classic Mac OS X, however, sticks to its own “think different” philosophy by choosing yet another representation:

>>>
>>> importos>>> os.linesep'\r'

Notice how these characters appear in string literals. They use special syntax with a preceding backslash (\) to denote the start of an escape character sequence. Such sequences allow for representing control characters, which would be otherwise invisible on screen.

Most programming languages come with a predefined set of escape sequences for special characters such as these:

  • \\: backslash
  • \b: backspace
  • \t: tab
  • \r: carriage return (CR)
  • \n: newline, also known as line feed (LF)

The last two are reminiscent of mechanical typewriters, which required two separate commands to insert a newline. The first command would move the carriage back to the beginning of the current line, while the second one would advance the roll to the next line.

By comparing the corresponding ASCII character codes, you’ll see that putting a backslash in front of a character changes its meaning completely. However, not all characters allow for this–only the special ones.

To compare ASCII character codes, you may want to use the built-in ord() function:

>>>
>>> ord('r')114>>> ord('\r')13

Keep in mind that, in order to form a correct escape sequence, there must be no space between the backslash character and a letter!

As you just saw, calling print() without arguments results in a blank line, which is a line comprised solely of the newline character. Don’t confuse this with an empty line, which doesn’t contain any characters at all, not even the newline!

You can use Python’s string literals to visualize these two:

'\n'# Blank line''# Empty line

The first one is one character long, whereas the second one has no content.

Note: To remove the newline character from a string in Python, use its .rstrip() method, like this:

>>>
>>> 'A line of text.\n'.rstrip()'A line of text.'

This strips any trailing whitespace from the right edge of the string of characters.

In a more common scenario, you’d want to communicate some message to the end user. There are a few ways to achieve this.

First, you may pass a string literal directly to print():

>>>
>>> print('Please wait while the program is loading...')

This will print the message verbatim onto the screen.

String literals in Python can be enclosed either in single quotes (') or double quotes ("). According to the official PEP 8 style guide, you should just pick one and keep using it consistently. There’s no difference, unless you need to nest one in another.

For example, you can’t use double quotes for the literal and also include double quotes inside of it, because that’s ambiguous for the Python interpreter:

"My favorite book is "PythonTricks""# Wrong!

What you want to do is enclose the text, which contains double quotes, within single quotes:

'My favorite book is "Python Tricks"'

The same trick would work the other way around:

"My favorite book is 'Python Tricks'"

Alternatively, you could use escape character sequences mentioned earlier, to make Python treat those internal double quotes literally as part of the string literal:

"My favorite book is \"Python Tricks\""

Escaping is fine and dandy, but it can sometimes get in the way. Specifically, when you need your string to contain relatively many backslash characters in literal form.

One classic example is a file path on Windows:

'C:\Users\jdoe'# Wrong!'C:\\Users\\jdoe'

Notice how each backslash character needs to be escaped with yet another backslash.

This is even more prominent with regular expressions, which quickly get convoluted due to the heavy use of special characters:

'^\\w:\\\\(?:(?:(?:[^\\\\]+)?|(?:[^\\\\]+)\\\\[^\\\\]+)*)$'

Fortunately, you can turn off character escaping entirely with the help of raw-string literals. Simply prepend an r or R before the opening quote, and now you end up with this:

r'C:\Users\jdoe'r'^\w:\\(?:(?:(?:[^\\]+)?|(?:[^\\]+)\\[^\\]+)*)$'

That’s much better, isn’t it?

There are a few more prefixes that give special meaning to string literals in Python, but you won’t get into them here.

Lastly, you can define multi-line string literals by enclosing them between ''' or """, which are often used as docstrings.

Here’s an example:

"""This is an exampleof a multi-line stringin Python."""

To prevent an initial newline, simply put the text right after the opening """:

"""This is an exampleof a multi-line stringin Python."""

You can also use a backslash to get rid of the newline:

"""\This is an exampleof a multi-line stringin Python."""

To remove indentation from a multi-line string, you might take advantage of the built-in textwrap module:

>>>
>>> importtextwrap>>> paragraph='''...     This is an example...     of a multi-line string...     in Python....     '''...>>> print(paragraph)    This is an example    of a multi-line string    in Python.>>> print(textwrap.dedent(paragraph).strip())This is an exampleof a multi-line stringin Python.

This will take care of unindenting paragraphs for you. There are also a few other useful functions in textwrap for text alignment you’d find in a word processor.

Secondly, you could extract that message into its own variable with a meaningful name to enhance readability and promote code reuse:

>>>
>>> message='Please wait while the program is loading...'>>> print(message)

Lastly, you could pass an expression, like string concatenation, to be evaluated before printing the result:

>>>
>>> importos>>> print('Hello, '+os.getlogin()+'! How are you?')Hello, jdoe! How are you?

In fact, there are a dozen ways to format messages in Python. I highly encourage you to take a look at f-strings, introduced in Python 3.6, because they offer the most concise syntax of them all:

>>>
>>> importos>>> print(f'Hello, {os.getlogin()}! How are you?')

Moreover, f-strings will prevent you from making a common mistake, which is forgetting to type cast concatenated operands. Python is a strongly typed language, which means it won’t allow you to do this:

>>>
>>> 'My age is '+42Traceback (most recent call last):
  File "<input>", line 1, in <module>'My age is '+42TypeError: can only concatenate str (not "int") to str

That’s wrong because adding numbers to strings doesn’t make sense. You need to explicitly convert the number to string first, in order to join them together:

>>>
>>> 'My age is '+str(42)'My age is 42'

Unless you handle such errors yourself, the Python interpreter will let you know about a problem by showing a traceback.

Note:str() is a global built-in function that converts an object into its string representation.

You can call it directly on any object, for example, a number:

>>>
>>> str(3.14)'3.14'

Built-in data types have a predefined string representation out of the box, but later in this article, you’ll find out how to provide one for your custom classes.

As with any function, it doesn’t matter whether you pass a literal, a variable, or an expression. Unlike many other functions, however, print() will accept anything regardless of its type.

So far, you only looked at the string, but how about other data types? Let’s try literals of different built-in types and see what comes out:

>>>
>>> print(42)# <class 'int'>42>>> print(3.14)# <class 'float'>3.14>>> print(1+2j)# <class 'complex'>(1+2j)>>> print(True)# <class 'bool'>True>>> print([1,2,3])# <class 'list'>[1, 2, 3]>>> print((1,2,3))# <class 'tuple'>(1, 2, 3)>>> print({'red','green','blue'})# <class 'set'>{'red', 'green', 'blue'}>>> print({'name':'Alice','age':42})# <class 'dict'>{'name': 'Alice', 'age': 42}>>> print('hello')# <class 'str'>hello

Watch out for the None constant, though. Despite being used to indicate an absence of a value, it will show up as 'None' rather than an empty string:

>>>
>>> print(None)None

How does print() know how to work with all these different types? Well, the short answer is that it doesn’t. It implicitly calls str() behind the scenes to type cast any object into a string. Afterward, it treats strings in a uniform way.

Later in this tutorial, you’ll learn how to use this mechanism for printing custom data types such as your classes.

Okay, you’re now able to call print() with a single argument or without any arguments. You know how to print fixed or formatted messages onto the screen. The next subsection will expand on message formatting a little bit.

To achieve the same result in the previous language generation, you’d normally want to drop the parentheses enclosing the text:

# Python 2printprint'Please wait...'print'Hello, %s! How are you?'%os.getlogin()print'Hello, %s. Your age is %d.'%(name,age)

That’s because print wasn’t a function back then, as you’ll see in the next section. Note, however, that in some cases parentheses in Python are redundant. It wouldn’t harm to include them as they’d just get ignored. Does that mean you should be using the print statement as if it were a function? Absolutely not!

For example, parentheses enclosing a single expression or a literal are optional. Both instructions produce the same result in Python 2:

>>>
>>> # Python 2>>> print'Please wait...'Please wait...>>> print('Please wait...')Please wait...

Round brackets are actually part of the expression rather than the print statement. If your expression happens to contain only one item, then it’s as if you didn’t include the brackets at all.

On the other hand, putting parentheses around multiple items forms a tuple:

>>>
>>> # Python 2>>> print'My name is','John'My name is John>>> print('My name is','John')('My name is', 'John')

This is a known source of confusion. In fact, you’d also get a tuple by appending a trailing comma to the only item surrounded by parentheses:

>>>
>>> # Python 2>>> print('Please wait...')Please wait...>>> print('Please wait...',)# Notice the comma('Please wait...',)

The bottom line is that you shouldn’t call print with brackets in Python 2. Although, to be completely accurate, you can work around this with the help of a __future__ import, which you’ll read more about in the relevant section.

Separating Multiple Arguments

You saw print() called without any arguments to produce a blank line and then called with a single argument to display either a fixed or a formatted message.

However, it turns out that this function can accept any number of positional arguments, including zero, one, or more arguments. That’s very handy in a common case of message formatting, where you’d want to join a few elements together.

Arguments can be passed to a function in one of several ways. One way is by explicitly naming the arguments when you’re calling the function, like this:

>>>
>>> defdiv(a,b):... returna/b...>>> div(a=3,b=4)0.75

Since arguments can be uniquely identified by name, their order doesn’t matter. Swapping them out will still give the same result:

>>>
>>> div(b=4,a=3)0.75

Conversely, arguments passed without names are identified by their position. That’s why positional arguments need to follow strictly the order imposed by the function signature:

>>>
>>> div(3,4)0.75>>> div(4,3)1.3333333333333333

print() allows an arbitrary number of positional arguments thanks to the *args parameter.

Let’s have a look at this example:

>>>
>>> importos>>> print('My name is',os.getlogin(),'and I am',42)My name is jdoe and I am 42

print() concatenated all four arguments passed to it, and it inserted a single space between them so that you didn’t end up with a squashed message like 'My name isjdoeand I am42'.

Notice that it also took care of proper type casting by implicitly calling str() on each argument before joining them together. If you recall from the previous subsection, a naïve concatenation may easily result in an error due to incompatible types:

>>>
>>> print('My age is: '+42)Traceback (most recent call last):
  File "<input>", line 1, in <module>print('My age is: '+42)TypeError: can only concatenate str (not "int") to str

Apart from accepting a variable number of positional arguments, print() defines four named or keyword arguments, which are optional since they all have default values. You can view their brief documentation by calling help(print) from the interactive interpreter.

Let’s focus on sep just for now. It stands for separator and is assigned a single space (' ') by default. It determines the value to join elements with.

It has to be either a string or None, but the latter has the same effect as the default space:

>>>
>>> print('hello','world',sep=None)hello world>>> print('hello','world',sep=' ')hello world>>> print('hello','world')hello world

If you wanted to suppress the separator completely, you’d have to pass an empty string ('') instead:

>>>
>>> print('hello','world',sep='')helloworld

You may want print() to join its arguments as separate lines. In that case, simply pass the escaped newline character described earlier:

>>>
>>> print('hello','world',sep='\n')helloworld

A more useful example of the sep parameter would be printing something like file paths:

>>>
>>> print('home','user','documents',sep='/')home/user/documents

Remember that the separator comes between the elements, not around them, so you need to account for that in one way or another:

>>>
>>> print('/home','user','documents',sep='/')/home/user/documents>>> print('','home','user','documents',sep='/')/home/user/documents

Specifically, you can insert a slash character (/) into the first positional argument, or use an empty string as the first argument to enforce the leading slash.

Note: Be careful about joining elements of a list or tuple.

Doing it manually will result in a well-known TypeError if at least one of the elements isn’t a string:

>>>
>>> print(' '.join(['jdoe is',42,'years old']))Traceback (most recent call last):
  File "<input>", line 1, in <module>print(','.join(['jdoe is',42,'years old']))TypeError: sequence item 1: expected str instance, int found

It’s safer to just unpack the sequence with the star operator (*) and let print() handle type casting:

>>>
>>> print(*['jdoe is',42,'years old'])jdoe is 42 years old

Unpacking is effectively the same as calling print() with individual elements of the list.

One more interesting example could be exporting data to a comma-separated values (CSV) format:

>>>
>>> print(1,'Python Tricks','Dan Bader',sep=',')1,Python Tricks,Dan Bader

This wouldn’t handle edge cases such as escaping commas correctly, but for simple use cases, it should do. The line above would show up in your terminal window. In order to save it to a file, you’d have to redirect the output. Later in this section, you’ll see how to use print() to write text to files straight from Python.

Finally, the sep parameter isn’t constrained to a single character only. You can join elements with strings of any length:

>>>
>>> print('node','child','child',sep=' -> ')node -> child -> child

In the upcoming subsections, you’ll explore the remaining keyword arguments of the print() function.

To print multiple elements in Python 2, you must drop the parentheses around them, just like before:

>>>
>>> # Python 2>>> importos>>> print'My name is',os.getlogin(),'and I am',42My name is jdoe and I am 42

If you kept them, on the other hand, you’d be passing a single tuple element to the print statement:

>>>
>>> # Python 2>>> importos>>> print('My name is',os.getlogin(),'and I am',42)('My name is', 'jdoe', 'and I am', 42)

Moreover, there’s no way of altering the default separator of joined elements in Python 2, so one workaround is to use string interpolation like so:

>>>
>>> # Python 2>>> importos>>> print'My name is %s and I am %d'%(os.getlogin(),42)My name is jdoe and I am 42

That was the default way of formatting strings until the .format() method got backported from Python 3.

Preventing Line Breaks

Sometimes you don’t want to end your message with a trailing newline so that subsequent calls to print() will continue on the same line. Classic examples include updating the progress of a long-running operation or prompting the user for input. In the latter case, you want the user to type in the answer on the same line:

Are you sure you want to do this? [y/n] y

Many programming languages expose functions similar to print() through their standard libraries, but they let you decide whether to add a newline or not. For example, in Java and C#, you have two distinct functions, while other languages require you to explicitly append \n at the end of a string literal.

Here are a few examples of syntax in such languages:

LanguageExample
Perlprint "hello world\n"
Cprintf("hello world\n");
C++std::cout << "hello world"<< std::endl;

In contrast, Python’s print() function always adds \n without asking, because that’s what you want in most cases. To disable it, you can take advantage of yet another keyword argument, end, which dictates what to end the line with.

In terms of semantics, the end parameter is almost identical to the sep one that you saw earlier:

  • It must be a string or None.
  • It can be arbitrarily long.
  • It has a default value of '\n'.
  • If equal to None, it’ll have the same effect as the default value.
  • If equal to an empty string (''), it’ll suppress the newline.

Now you understand what’s happening under the hood when you’re calling print() without arguments. Since you don’t provide any positional arguments to the function, there’s nothing to be joined, and so the default separator isn’t used at all. However, the default value of end still applies, and a blank line shows up.

Note: You may be wondering why the end parameter has a fixed default value rather than whatever makes sense on your operating system.

Well, you don’t have to worry about newline representation across different operating systems when printing, because print() will handle the conversion automatically. Just remember to always use the \n escape sequence in string literals.

This is currently the most portable way of printing a newline character in Python:

>>>
>>> print('line1\nline2\nline3')line1line2line3

If you were to try to forcefully print a Windows-specific newline character on a Linux machine, for example, you’d end up with broken output:

>>>
>>> print('line1\r\nline2\r\nline3')line3

On the flip side, when you open a file for reading with open(), you don’t need to care about newline representation either. The function will translate any system-specific newline it encounters into a universal '\n'. At the same time, you have control over how the newlines should be treated both on input and output if you really need that.

To disable the newline, you must specify an empty string through the end keyword argument:

print('Checking file integrity...',end='')# (...)print('ok')

Even though these are two separate print() calls, which can execute a long time apart, you’ll eventually see only one line. First, it’ll look like this:

Checking file integrity...

However, after the second call to print(), the same line will appear on the screen as:

Checking file integrity...ok

As with sep, you can use end to join individual pieces into a big blob of text with a custom separator. Instead of joining multiple arguments, however, it’ll append text from each function call to the same line:

print('The first sentence',end='. ')print('The second sentence',end='. ')print('The last sentence.')

These three instructions will output a single line of text:

The first sentence. The second sentence. The last sentence.

You can mix the two keyword arguments:

print('Mercury','Venus','Earth',sep=', ',end=', ')print('Mars','Jupiter','Saturn',sep=', ',end=', ')print('Uranus','Neptune','Pluto',sep=', ')

Not only do you get a single line of text, but all items are separated with a comma:

Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto

There’s nothing to stop you from using the newline character with some extra padding around it:

print('Printing in a Nutshell',end='\n * ')print('Calling Print',end='\n * ')print('Separating Multiple Arguments',end='\n * ')print('Preventing Line Breaks')

It would print out the following piece of text:

Printing in a Nutshell
 * Calling Print
 * Separating Multiple Arguments
 * Preventing Line Breaks

As you can see, the end keyword argument will accept arbitrary strings.

Note: Looping over lines in a text file preserves their own newline characters, which combined with the print() function’s default behavior will result in a redundant newline character:

>>>
>>> withopen('file.txt')asfile_object:... forlineinfile_object:... print(line)...Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmodtempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo

There are two newlines after each line of text. You want to strip one of the them, as shown earlier in this article, before printing the line:

print(line.rstrip())

Alternatively, you can keep the newline in the content but suppress the one appended by print() automatically. You’d use the end keyword argument to do that:

>>>
>>> withopen('file.txt')asfile_object:... forlineinfile_object:... print(line,end='')...Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmodtempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo

By ending a line with an empty string, you effectively disable one of the newlines.

You’re getting more acquainted with printing in Python, but there’s still a lot of useful information ahead. In the upcoming subsection, you’ll learn how to intercept and redirect the print() function’s output.

Preventing a line break in Python 2 requires that you append a trailing comma to the expression:

print'hello world',

However, that’s not ideal because it also adds an unwanted space, which would translate to end=' ' instead of end='' in Python 3. You can test this with the following code snippet:

print'BEFORE'print'hello',print'AFTER'

Notice there’s a space between the words hello and AFTER:

BEFORE
hello AFTER

In order to get the expected result, you’d need to use one of the tricks explained later, which is either importing the print() function from __future__ or falling back to the sys module:

importsysprint'BEFORE'sys.stdout.write('hello')print'AFTER'

This will print the correct output without extra space:

BEFORE
helloAFTER

While using the sys module gives you control over what gets printed to the standard output, the code becomes a little bit more cluttered.

Printing to a File

Believe it or not, print() doesn’t know how to turn messages into text on your screen, and frankly it doesn’t need to. That’s a job for lower-level layers of code, which understand bytes and know how to push them around.

print() is an abstraction over these layers, providing a convenient interface that merely delegates the actual printing to a stream or file-like object. A stream can be any file on your disk, a network socket, or perhaps an in-memory buffer.

In addition to this, there are three standard streams provided by the operating system:

  1. stdin: standard input
  2. stdout: standard output
  3. stderr: standard error

Standard output is what you see in the terminal when you run various command-line programs including your own Python scripts:

$ cat hello.py 
print('This will appear on stdout')$ python hello.py
This will appear on stdout

Unless otherwise instructed, print() will default to writing to standard output. However, you can tell your operating system to temporarily swap out stdout for a file stream, so that any output ends up in that file rather than the screen:

$ python hello.py > file.txt
$ cat file.txt
This will appear on stdout

That’s called stream redirection.

The standard error is similar to stdout in that it also shows up on the screen. Nonetheless, it’s a separate stream, whose purpose is to log error messages for diagnostics. By redirecting one or both of them, you can keep things clean.

Note: To redirect stderr, you need to know about file descriptors, also known as file handles.

They’re arbitrary, albeit constant, numbers associated with standard streams. Below, you’ll find a summary of the file descriptors for a family of POSIX-compliant operating systems:

StreamFile Descriptor
stdin0
stdout1
stderr2

Knowing those descriptors allows you to redirect one or more streams at a time:

CommandDescription
./program > out.txtRedirect stdout
./program 2> err.txtRedirect stderr
./program > out.txt 2> err.txtRedirect stdout and stderr to separate files
./program &> out_err.txtRedirect stdout and stderr to the same file

Note that > is the same as 1>.

Some programs use different coloring to distinguish between messages printed to stdout and stderr:

The output of a program executed in PyCharmRun Tool Window in PyCharm

While both stdout and stderr are write-only, stdin is read-only. You can think of standard input as your keyboard, but just like with the other two, you can swap out stdin for a file to read data from.

In Python, you can access all standard streams through the built-in sys module:

>>>
>>> importsys>>> sys.stdin<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>>>> sys.stdin.fileno()0>>> sys.stdout<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>>>> sys.stdout.fileno()1>>> sys.stderr<_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>>>> sys.stderr.fileno()2

As you can see, these predefined values resemble file-like objects with mode and encoding attributes as well as .read() and .write() methods among many others.

By default, print() is bound to sys.stdout through its file argument, but you can change that. Use that keyword argument to indicate a file that was open in write or append mode, so that messages go straight to it:

withopen('file.txt',mode='w')asfile_object:print('hello world',file=file_object)

This will make your code immune to stream redirection at the operating system level, which might or might not be desired.

For more information on working with files in Python, you can check out Reading and Writing Files in Python (Guide).

Note: Don’t try using print() for writing binary data as it’s only well suited for text.

Just call the binary file’s .write() directly:

withopen('file.dat','wb')asfile_object:file_object.write(bytes(4))file_object.write(b'\xff')

If you wanted to write raw bytes on the standard output, then this will fail too because sys.stdout is a character stream:

>>>
>>> importsys>>> sys.stdout.write(bytes(4))Traceback (most recent call last):
  File "<stdin>", line 1, in <module>TypeError: write() argument must be str, not bytes

You must dig deeper to get a handle of the underlying byte stream instead:

>>>
>>> importsys>>> num_bytes_written=sys.stdout.buffer.write(b'\x41\x0a')A

This prints an uppercase letter A and a newline character, which correspond to decimal values of 65 and 10 in ASCII. However, they’re encoded using hexadecimal notation in the bytes literal.

Note that print() has no control over character encoding. It’s the stream’s responsibility to encode received Unicode strings into bytes correctly. In most cases, you won’t set the encoding yourself, because the default UTF-8 is what you want. If you really need to, perhaps for legacy systems, you can use the encoding argument of open():

withopen('file.txt',mode='w',encoding='iso-8859-1')asfile_object:print('über naïve café',file=file_object)

Instead of a real file existing somewhere in your file system, you can provide a fake one, which would reside in your computer’s memory. You’ll use this technique later for mocking print() in unit tests:

>>>
>>> importio>>> fake_file=io.StringIO()>>> print('hello world',file=fake_file)>>> fake_file.getvalue()'hello world\n'

If you got to this point, then you’re left with only one keyword argument in print(), which you’ll see in the next subsection. It’s probably the least used of them all. Nevertheless, there are times when it’s absolutely necessary.

There’s a special syntax in Python 2 for replacing the default sys.stdout with a custom file in the print statement:

withopen('file.txt',mode='w')asfile_object:print>>file_object,'hello world'

Because strings and bytes are represented with the same str type in Python 2, the print statement can handle binary data just fine:

withopen('file.dat',mode='wb')asfile_object:print>>file_object,'\x41\x0a'

Although, there’s a problem with character encoding. The open() function in Python 2 lacks the encoding parameter, which would often result in the dreadful UnicodeEncodeError:

>>>
>>> withopen('file.txt',mode='w')asfile_object:... unicode_text=u'\xfcber na\xefve caf\xe9'... print>>file_object,unicode_text... Traceback (most recent call last):
  File "<stdin>", line 3, in <module>UnicodeEncodeError: 'ascii' codec can't encode character u'\xfc'...

Notice how non-Latin characters must be escaped in both Unicode and string literals to avoid a syntax error. Take a look at this example:

unicode_literal=u'\xfcber na\xefve caf\xe9'string_literal='\xc3\xbcber na\xc3\xafve caf\xc3\xa9'

Alternatively, you could specify source code encoding according to PEP 263 at the top of the file, but that wasn’t the best practice due to portability issues:

#!/usr/bin/env python2# -*- coding: utf-8 -*-unescaped_unicode_literal=u'über naïve café'unescaped_string_literal='über naïve café'

Your best bet is to encode the Unicode string just before printing it. You can do this manually:

withopen('file.txt',mode='w')asfile_object:unicode_text=u'\xfcber na\xefve caf\xe9'encoded_text=unicode_text.encode('utf-8')print>>file_object,encoded_text

However, a more convenient option is to use the built-in codecs module:

importcodecswithcodecs.open('file.txt','w',encoding='utf-8')asfile_object:unicode_text=u'\xfcber na\xefve caf\xe9'print>>file_object,unicode_text

It’ll take care of making appropriate conversions when you need to read or write files.

Buffering Print Calls

In the previous subsection, you learned that print() delegates printing to a file-like object such as sys.stdout. Some streams, however, buffer certain I/O operations to enhance performance, which can get in the way. Let’s take a look at an example.

Imagine you were writing a countdown timer, which should append the remaining time to the same line every second:

3...2...1...Go!

Your first attempt may look something like this:

importtimenum_seconds=3forcountdowninreversed(range(num_seconds+1)):ifcountdown>0:print(countdown,end='...')time.sleep(1)else:print('Go!')

As long as the countdown variable is greater than zero, the code keeps appending text without a trailing newline and then goes to sleep for one second. Finally, when the countdown is finished, it prints Go! and terminates the line.

Unexpectedly, instead of counting down every second, the program idles wastefully for three seconds, and then suddenly prints the entire line at once:

Terminal with buffered output

That’s because the operating system buffers subsequent writes to the standard output in this case. You need to know that there are three kinds of streams with respect to buffering:

  1. Unbuffered
  2. Line-buffered
  3. Block-buffered

Unbuffered is self-explanatory, that is, no buffering is taking place, and all writes have immediate effect. A line-buffered stream waits before firing any I/O calls until a line break appears somewhere in the buffer, whereas a block-buffered one simply allows the buffer to fill up to a certain size regardless of its content. Standard output is both line-buffered and block-buffered, depending on which event comes first.

Buffering helps to reduce the number of expensive I/O calls. Think about sending messages over a high-latency network, for example. When you connect to a remote server to execute commands over the SSH protocol, each of your keystrokes may actually produce an individual data packet, which is orders of magnitude bigger than its payload. What an overhead! It would make sense to wait until at least a few characters are typed and then send them together. That’s where buffering steps in.

On the other hand, buffering can sometimes have undesired effects as you just saw with the countdown example. To fix it, you can simply tell print() to forcefully flush the stream without waiting for a newline character in the buffer using its flush flag:

print(countdown,end='...',flush=True)

That’s all. Your countdown should work as expected now, but don’t take my word for it. Go ahead and test it to see the difference.

Congratulations! At this point, you’ve seen examples of calling print() that cover all of its parameters. You know their purpose and when to use them. Understanding the signature is only the beginning, however. In the upcoming sections, you’ll see why.

There isn’t an easy way to flush the stream in Python 2, because the print statement doesn’t allow for it by itself. You need to get a handle of its lower-level layer, which is the standard output, and call it directly:

importtimeimportsysnum_seconds=3forcountdowninreversed(range(num_seconds+1)):ifcountdown>0:sys.stdout.write('%s...'%countdown)sys.stdout.flush()time.sleep(1)else:print'Go!'

Alternatively, you could disable buffering of the standard streams either by providing the -u flag to the Python interpreter or by setting up the PYTHONUNBUFFERED environment variable:

$ python2 -u countdown.py
$PYTHONUNBUFFERED=1 python2 countdown.py

Note that print() was backported to Python 2 and made available through the __future__ module. Unfortunately, it doesn’t come with the flush parameter:

>>>
>>> from__future__importprint_function>>> help(print)Help on built-in function print in module __builtin__:print(...)    print(value, ..., sep=' ', end='\n', file=sys.stdout)

What you’re seeing here is a docstring of the print() function. You can display docstrings of various objects in Python using the built-in help() function.

Printing Custom Data Types

Up until now, you only dealt with built-in data types such as strings and numbers, but you’ll often want to print your own abstract data types. Let’s have a look at different ways of defining them.

For simple objects without any logic, whose purpose is to carry data, you’ll typically take advantage of namedtuple, which is available in the standard library. Named tuples have a neat textual representation out of the box:

>>>
>>> fromcollectionsimportnamedtuple>>> Person=namedtuple('Person','name age')>>> jdoe=Person('John Doe',42)>>> print(jdoe)Person(name='John Doe', age=42)

That’s great as long as holding data is enough, but in order to add behaviors to the Person type, you’ll eventually need to define a class. Take a look at this example:

classPerson:def__init__(self,name,age):self.name,self.age=name,age

If you now create an instance of the Person class and try to print it, you’ll get this bizarre output, which is quite different from the equivalent namedtuple:

>>>
>>> jdoe=Person('John Doe',42)>>> print(jdoe)<__main__.Person object at 0x7fcac3fed1d0>

It’s the default representation of objects, which comprises their address in memory, the corresponding class name and a module in which they were defined. You’ll fix that in a bit, but just for the record, as a quick workaround you could combine namedtuple and a custom class through inheritance:

fromcollectionsimportnamedtupleclassPerson(namedtuple('Person','name age')):pass

Your Person class has just become a specialized kind of namedtuple with two attributes, which you can customize.

Note: In Python 3, the pass statement can be replaced with the ellipsis (...) literal to indicate a placeholder:

defdelta(a,b,c):...

This prevents the interpreter from raising IndentationError due to missing indented block of code.

That’s better than a plain namedtuple, because not only do you get printing right for free, but you can also add custom methods and properties to the class. However, it solves one problem while introducing another. Remember that tuples, including named tuples, are immutable in Python, so they can’t change their values once created.

It’s true that designing immutable data types is desirable, but in many cases, you’ll want them to allow for change, so you’re back with regular classes again.

Note: Following other languages and frameworks, Python 3.7 introduced data classes, which you can think of as mutable tuples. This way, you get the best of both worlds:

>>>
>>> fromdataclassesimportdataclass>>> @dataclass... classPerson:... name:str... age:int... ... defcelebrate_birthday(self):... self.age+=1... >>> jdoe=Person('John Doe',42)>>> jdoe.celebrate_birthday()>>> print(jdoe)Person(name='John Doe', age=43)

The syntax for variable annotations, which is required to specify class fields with their corresponding types, was defined in Python 3.6.

From earlier subsections, you already know that print() implicitly calls the built-in str() function to convert its positional arguments into strings. Indeed, calling str() manually against an instance of the regular Person class yields the same result as printing it:

>>>
>>> jdoe=Person('John Doe',42)>>> str(jdoe)'<__main__.Person object at 0x7fcac3fed1d0>'

str(), in turn, looks for one of two magic methods within the class body, which you typically implement. If it doesn’t find one, then it falls back to the ugly default representation. Those magic methods are, in order of search:

  1. def __str__(self)
  2. def __repr__(self)

The first one is recommended to return a short, human-readable text, which includes information from the most relevant attributes. After all, you don’t want to expose sensitive data, such as user passwords, when printing objects.

However, the other one should provide complete information about an object, to allow for restoring its state from a string. Ideally, it should return valid Python code, so that you can pass it directly to eval():

>>>
>>> repr(jdoe)"Person(name='John Doe', age=42)">>> type(eval(repr(jdoe)))<class '__main__.Person'>

Notice the use of another built-in function, repr(), which always tries to call .__repr__() in an object, but falls back to the default representation if it doesn’t find that method.

Note: Even though print() itself uses str() for type casting, some compound data types delegate that call to repr() on their members. This happens to lists and tuples, for example.

Consider this class with both magic methods, which return alternative string representations of the same object:

classUser:def__init__(self,login,password):self.login=loginself.password=passworddef__str__(self):returnself.logindef__repr__(self):returnf"User('{self.login}', '{self.password}')"

If you print a single object of the User class, then you won’t see the password, because print(user) will call str(user), which eventually will invoke user.__str__():

>>>
>>> user=User('jdoe','s3cret')>>> print(user)jdoe

However, if you put the same user variable inside a list by wrapping it in square brackets, then the password will become clearly visible:

>>>
>>> print([user])[User('jdoe', 's3cret')]

That’s because sequences, such as lists and tuples, implement their .__str__() method so that all of their elements are first converted with repr().

Python gives you a lot of freedom when it comes to defining your own data types if none of the built-in ones meet your needs. Some of them, such as named tuples and data classes, offer string representations that look good without requiring any work on your part. Still, for the most flexibility, you’ll have to define a class and override its magic methods described above.

The semantics of .__str__() and .__repr__() didn’t change since Python 2, but you must remember that strings were nothing more than glorified byte arrays back then. To convert your objects into proper Unicode, which was a separate data type, you’d have to provide yet another magic method: .__unicode__().

Here’s an example of the same User class in Python 2:

classUser(object):def__init__(self,login,password):self.login=loginself.password=passworddef__unicode__(self):returnself.logindef__str__(self):returnunicode(self).encode('utf-8')def__repr__(self):user=u"User('%s', '%s')"%(self.login,self.password)returnuser.encode('unicode_escape')

As you can see, this implementation delegates some work to avoid duplication by calling the built-in unicode() function on itself.

Both .__str__() and .__repr__() methods must return strings, so they encode Unicode characters into specific byte representations called character sets. UTF-8 is the most widespread and safest encoding, while unicode_escape is a special constant to express funky characters, such as é, as escape sequences in plain ASCII, such as \xe9.

The print statement is looking for the magic .__str__() method in the class, so the chosen charset must correspond to the one used by the terminal. For example, default encoding in DOS and Windows is CP 852 rather than UTF-8, so running this can result in a UnicodeEncodeError or even garbled output:

>>>
>>> user=User(u'\u043d\u0438\u043a\u0438\u0442\u0430',u's3cret')>>> printuserđŻđŞđ║đŞĐéđ░

However, if you ran the same code on a system with UTF-8 encoding, then you’d get the proper spelling of a popular Russian name:

>>>
>>> user=User(u'\u043d\u0438\u043a\u0438\u0442\u0430',u's3cret')>>> printuserникита

It’s recommended to convert strings to Unicode as early as possible, for example, when you’re reading data from a file, and use it consistently everywhere in your code. At the same time, you should encode Unicode back to the chosen character set right before presenting it to the user.

It seems as if you have more control over string representation of objects in Python 2 because there’s no magic .__unicode__() method in Python 3 anymore. You may be asking yourself if it’s possible to convert an object to its byte string representation rather than a Unicode string in Python 3. It’s possible, with a special .__bytes__() method that does just that:

>>>
>>> classUser(object):... def__init__(self,login,password):... self.login=login... self.password=password... ... def__bytes__(self):# Python 3... returnself.login.encode('utf-8')...>>> user=User(u'\u043d\u0438\u043a\u0438\u0442\u0430',u's3cret')>>> bytes(user)b'\xd0\xbd\xd0\xb8\xd0\xba\xd0\xb8\xd1\x82\xd0\xb0'

Using the built-in bytes() function on an instance delegates the call to its __bytes__() method defined in the corresponding class.

Understanding Python Print

You know how to use print() quite well at this point, but knowing what it is will allow you to use it even more effectively and consciously. After reading this section, you’ll understand how printing in Python has improved over the years.

You’ve seen that print() is a function in Python 3. More specifically, it’s a built-in function, which means that you don’t need to import it from anywhere:

>>>
>>> print<built-in function print>

It’s always available in the global namespace so that you can call it directly, but you can also access it through a module from the standard library:

>>>
>>> importbuiltins>>> builtins.print<built-in function print>

This way, you can avoid name collisions with custom functions. Let’s say you wanted to redefineprint() so that it doesn’t append a trailing newline. At the same time, you wanted to rename the original function to something like println():

>>>
>>> importbuiltins>>> println=builtins.print>>> defprint(*args,**kwargs):... builtins.print(*args,**kwargs,end='')...>>> println('hello')hello>>> print('hello\n')hello

Now you have two separate printing functions just like in the Java programming language. You’ll define custom print() functions in the mocking section later as well. Also, note that you wouldn’t be able to overwrite print() in the first place if it wasn’t a function.

On the other hand, print() isn’t a function in the mathematical sense, because it doesn’t return any meaningful value other than the implicit None:

>>>
>>> value=print('hello world')hello world>>> print(value)None

Such functions are, in fact, procedures or subroutines that you call to achieve some kind of side-effect, which ultimately is a change of a global state. In the case of print(), that side-effect is showing a message on the standard output or writing to a file.

Because print() is a function, it has a well-defined signature with known attributes. You can quickly find its documentation using the editor of your choice, without having to remember some weird syntax for performing a certain task.

Besides, functions are easier to extend. Adding a new feature to a function is as easy as adding another keyword argument, whereas changing the language to support that new feature is much more cumbersome. Think of stream redirection or buffer flushing, for example.

Another benefit of print() being a function is composability. Functions are so-called first-class objects or first-class citizens in Python, which is a fancy way of saying they’re values just like strings or numbers. This way, you can assign a function to a variable, pass it to another function, or even return one from another. print() isn’t different in this regard. For instance, you can take advantage of it for dependency injection:

defdownload(url,log=print):log(f'Downloading {url}')# ...defcustom_print(*args):pass# Do not print anythingdownload('/js/app.js',log=custom_print)

Here, the log parameter lets you inject a callback function, which defaults to print() but can be any callable. In this example, printing is completely disabled by substituting print() with a dummy function that does nothing.

Note: A dependency is any piece of code required by another bit of code.

Dependency injection is a technique used in code design to make it more testable, reusable, and open for extension. You can achieve it by referring to dependencies indirectly through abstract interfaces and by providing them in a push rather than pull fashion.

There’s a funny explanation of dependency injection circulating on the Internet:

Dependency injection for five-year-olds

When you go and get things out of the refrigerator for yourself, you can cause problems. You might leave the door open, you might get something Mommy or Daddy doesn’t want you to have. You might even be looking for something we don’t even have or which has expired.

What you should be doing is stating a need, “I need something to drink with lunch,” and then we will make sure you have something when you sit down to eat.

John Munsch, 28 October 2009. (Source)

Composition allows you to combine a few functions into a new one of the same kind. Let’s see this in action by specifying a custom error() function that prints to the standard error stream and prefixes all messages with a given log level:

>>>
>>> fromfunctoolsimportpartial>>> importsys>>> redirect=lambdafunction,stream:partial(function,file=stream)>>> prefix=lambdafunction,prefix:partial(function,prefix)>>> error=prefix(redirect(print,sys.stderr),'[ERROR]')>>> error('Something went wrong')[ERROR] Something went wrong

This custom function uses partial functions to achieve the desired effect. It’s an advanced concept borrowed from the functional programming paradigm, so you don’t need to go too deep into that topic for now. However, if you’re interested in this topic, I recommend taking a look at the functools module.

Unlike statements, functions are values. That means you can mix them with expressions, in particular, lambda expressions. Instead of defining a full-blown function to replace print() with, you can make an anonymous lambda expression that calls it:

>>>
>>> download('/js/app.js',lambdamsg:print('[INFO]',msg))[INFO] Downloading /js/app.js

However, because a lambda expression is defined in place, there’s no way of referring to it elsewhere in the code.

Note: In Python, you can’t put statements, such as assignments, conditional statements, loops, and so on, in an anonymous lambda function. It has to be a single expression!

Another kind of expression is a ternary conditional expression:

>>>
>>> user='jdoe'>>> print('Hi!')ifuserisNoneelseprint(f'Hi, {user}.')Hi, jdoe.

Python has both conditional statements and conditional expressions. The latter is evaluated to a single value that can be assigned to a variable or passed to a function. In the example above, you’re interested in the side-effect rather than the value, which evaluates to None, so you simply ignore it.

As you can see, functions allow for an elegant and extensible solution, which is consistent with the rest of the language. In the next subsection, you’ll discover how not having print() as a function caused a lot of headaches.

A statement is an instruction that may evoke a side-effect when executed but never evaluates to a value. In other words, you wouldn’t be able to print a statement or assign it to a variable like this:

result=print'hello world'

That’s a syntax error in Python 2.

Here are a few more examples of statements in Python:

  • assignment:=
  • conditional:if
  • loop:while
  • assertion: assert

Note: Python 3.8 brings a controversial walrus operator (:=), which is an assignment expression. With it, you can evaluate an expression and assign the result to a variable at the same time, even within another expression!

Take a look at this example, which calls an expensive function once and then reuses the result for further computation:

# Python 3.8+values=[y:=f(x),y**2,y**3]

This is useful for simplifying the code without losing its efficiency. Typically, performant code tends to be more verbose:

y=f(x)values=[y,y**2,y**3]

The controversy behind this new piece of syntax caused a lot of argument. An abundance of negative comments and heated debates eventually led Guido van Rossum to step down from the Benevolent Dictator For Life or BDFL position.

Statements are usually comprised of reserved keywords such as if, for, or print that have fixed meaning in the language. You can’t use them to name your variables or other symbols. That’s why redefining or mocking the print statement isn’t possible in Python 2. You’re stuck with what you get.

Furthermore, you can’t print from anonymous functions, because statements aren’t accepted in lambda expressions:

>>>
>>> lambda:print'hello world'
  File "<stdin>", line 1lambda:print'hello world'^SyntaxError: invalid syntax

The syntax of the print statement is ambiguous. Sometimes you can add parentheses around the message, and they’re completely optional:

>>>
>>> print'Please wait...'Please wait...>>> print('Please wait...')Please wait...

At other times they change how the message is printed:

>>>
>>> print'My name is','John'My name is John>>> print('My name is','John')('My name is', 'John')

String concatenation can raise a TypeError due to incompatible types, which you have to handle manually, for example:

>>>
>>> values=['jdoe','is',42,'years old']>>> print' '.join(map(str,values))jdoe is 42 years old

Compare this with similar code in Python 3, which leverages sequence unpacking:

>>>
>>> values=['jdoe','is',42,'years old']>>> print(*values)# Python 3jdoe is 42 years old

There aren’t any keyword arguments for common tasks such as flushing the buffer or stream redirection. You need to remember the quirky syntax instead. Even the built-in help() function isn’t that helpful with regards to the print statement:

>>>
>>> help(print)
  File "<stdin>", line 1help(print)^SyntaxError: invalid syntax

Trailing newline removal doesn’t work quite right, because it adds an unwanted space. You can’t compose multiple print statements together, and, on top of that, you have to be extra diligent about character encoding.

The list of problems goes on and on. If you’re curious, you can jump back to the previous section and look for more detailed explanations of the syntax in Python 2.

However, you can mitigate some of those problems with a much simpler approach. It turns out the print() function was backported to ease the migration to Python 3. You can import it from a special __future__ module, which exposes a selection of language features released in later Python versions.

Note: You may import future functions as well as baked-in language constructs such as the with statement.

To find out exactly what features are available to you, inspect the module:

>>>
>>> import__future__>>> __future__.all_feature_names['nested_scopes', 'generators', 'division', 'absolute_import', 'with_statement', 'print_function', 'unicode_literals']

You could also call dir(__future__), but that would show a lot of uninteresting internal details of the module.

To enable the print() function in Python 2, you need to add this import statement at the beginning of your source code:

from__future__importprint_function

From now on the print statement is no longer available, but you have the print() function at your disposal. Note that it isn’t the same function like the one in Python 3, because it’s missing the flush keyword argument, but the rest of the arguments are the same.

Other than that, it doesn’t spare you from managing character encodings properly.

Here’s an example of calling the print() function in Python 2:

>>>
>>> from__future__importprint_function>>> importsys>>> print('I am a function in Python',sys.version_info.major)I am a function in Python 2

You now have an idea of how printing in Python evolved and, most importantly, understand why these backward-incompatible changes were necessary. Knowing this will surely help you become a better Python programmer.

Printing With Style

If you thought that printing was only about lighting pixels up on the screen, then technically you’d be right. However, there are ways to make it look cool. In this section, you’ll find out how to format complex data structures, add colors and other decorations, build interfaces, use animation, and even play sounds with text!

Pretty-Printing Nested Data Structures

Computer languages allow you to represent data as well as executable code in a structured way. Unlike Python, however, most languages give you a lot of freedom in using whitespace and formatting. This can be useful, for example in compression, but it sometimes leads to less readable code.

Pretty-printing is about making a piece of data or code look more appealing to the human eye so that it can be understood more easily. This is done by indenting certain lines, inserting newlines, reordering elements, and so forth.

Python comes with the pprint module in its standard library, which will help you in pretty-printing large data structures that don’t fit on a single line. Because it prints in a more human-friendly way, many popular REPL tools, including JupyterLab and IPython, use it by default in place of the regular print() function.

Note: To toggle pretty printing in IPython, issue the following command:

>>>
In [1]: %pprintPretty printing has been turned OFFIn [2]: %pprintPretty printing has been turned ON

This is an example of Magic in IPython. There are a lot of built-in commands that start with a percent sign (%), but you can find more on PyPI, or even create your own.

If you don’t care about not having access to the original print() function, then you can replace it with pprint() in your code using import renaming:

>>>
>>> frompprintimportpprintasprint>>> print<function pprint at 0x7f7a775a3510>

Personally, I like to have both functions at my fingertips, so I’d rather use something like pp as a short alias:

frompprintimportpprintaspp

At first glance, there’s hardly any difference between the two functions, and in some cases there’s virtually none:

>>>
>>> print(42)42>>> pp(42)42>>> print('hello')hello>>> pp('hello')'hello'  # Did you spot the difference?

That’s because pprint() calls repr() instead of the usual str() for type casting, so that you may evaluate its output as Python code if you want to. The differences become apparent as you start feeding it more complex data structures:

>>>
>>> data={'powers':[x**10forxinrange(10)]}>>> pp(data){'powers': [0,            1,            1024,            59049,            1048576,            9765625,            60466176,            282475249,            1073741824,            3486784401]}

The function applies reasonable formatting to improve readability, but you can customize it even further with a couple of parameters. For example, you may limit a deeply nested hierarchy by showing an ellipsis below a given level:

>>>
>>> cities={'USA':{'Texas':{'Dallas':['Irving']}}}>>> pp(cities,depth=3){'USA': {'Texas': {'Dallas': [...]}}}

The ordinary print() also uses ellipses but for displaying recursive data structures, which form a cycle, to avoid stack overflow error:

>>>
>>> items=[1,2,3]>>> items.append(items)>>> print(items)[1, 2, 3, [...]]

However, pprint() is more explicit about it by including the unique identity of a self-referencing object:

>>>
>>> pp(items)[1, 2, 3, <Recursion on list with id=140635757287688>]>>> id(items)140635757287688

The last element in the list is the same object as the entire list.

Note: Recursive or very large data sets can be dealt with using the reprlib module as well:

>>>
>>> importreprlib>>> reprlib.repr([x**10forxinrange(10)])'[0, 1, 1024, 59049, 1048576, 9765625, ...]'

This module supports most of the built-in types and is used by the Python debugger.

pprint() automatically sorts dictionary keys for you before printing, which allows for consistent comparison. When you’re comparing strings, you often don’t care about a particular order of serialized attributes. Anyways, it’s always best to compare actual dictionaries before serialization.

Dictionaries often represent JSON data, which is widely used on the Internet. To correctly serialize a dictionary into a valid JSON-formatted string, you can take advantage of the json module. It too has pretty-printing capabilities:

>>>
>>> importjson>>> data={'username':'jdoe','password':'s3cret'}>>> ugly=json.dumps(data)>>> pretty=json.dumps(data,indent=4,sort_keys=True)>>> print(ugly){"username": "jdoe", "password": "s3cret"}>>> print(pretty){"password": "s3cret","username": "jdoe"}

Notice, however, that you need to handle printing yourself, because it’s not something you’d typically want to do. Similarly, the pprint module has an additional pformat() function that returns a string, in case you had to do something other than printing it.

Surprisingly, the signature of pprint() is nothing like the print() function’s one. You can’t even pass more than one positional argument, which shows how much it focuses on printing data structures.

Adding Colors With ANSI Escape Sequences

As personal computers got more sophisticated, they had better graphics and could display more colors. However, different vendors had their own idea about the API design for controlling it. That changed a few decades ago when people at the American National Standards Institute decided to unify it by defining ANSI escape codes.

Most of today’s terminal emulators support this standard to some degree. Until recently, the Windows operating system was a notable exception. Therefore, if you want the best portability, use the colorama library in Python. It translates ANSI codes to their appropriate counterparts in Windows while keeping them intact in other operating systems.

To check if your terminal understands a subset of the ANSI escape sequences, for example, related to colors, you can try using the following command:

$ tput colors

My default terminal on Linux says it can display 256 distinct colors, while xterm gives me only 8. The command would return a negative number if colors were unsupported.

ANSI escape sequences are like a markup language for the terminal. In HTML you work with tags, such as <b> or <i>, to change how elements look in the document. These tags are mixed with your content, but they’re not visible themselves. Similarly, escape codes won’t show up in the terminal as long as it recognizes them. Otherwise, they’ll appear in the literal form as if you were viewing the source of a website.

As its name implies, a sequence must begin with the non-printable Esc character, whose ASCII value is 27, sometimes denoted as 0x1b in hexadecimal or 033 in octal. You may use Python number literals to quickly verify it’s indeed the same number:

>>>
>>> 27==0x1b==0o33True

Additionally, you can obtain it with the \e escape sequence in the shell:

$echo -e "\e"

The most common ANSI escape sequences take the following form:

ElementDescriptionExample
Escnon-printable escape character\033
[opening square bracket[
numeric codeone or more numbers separated with ;0
character codeuppercase or lowercase letterm

The numeric code can be one or more numbers separated with a semicolon, while the character code is just one letter. Their specific meaning is defined by the ANSI standard. For example, to reset all formatting, you would type one of the following commands, which use the code zero and the letter m:

$echo -e "\e[0m"$echo -e "\x1b[0m"$echo -e "\033[0m"

At the other end of the spectrum, you have compound code values. To set foreground and background with RGB channels, given that your terminal supports 24-bit depth, you could provide multiple numbers:

$echo -e "\e[38;2;0;0;0m\e[48;2;255;255;255mBlack on white\e[0m"

It’s not just text color that you can set with the ANSI escape codes. You can, for example, clear and scroll the terminal window, change its background, move the cursor around, make the text blink or decorate it with an underline.

In Python, you’d probably write a helper function to allow for wrapping arbitrary codes into a sequence:

>>>
>>> defesc(code):... returnf'\033[{code}m'...>>> print(esc('31;1;4')+'really'+esc(0)+' important')

This would make the word really appear in red, bold, and underlined font:

Text formatted with ANSI escape codes

However, there are higher-level abstractions over ANSI escape codes, such as the mentioned colorama library, as well as tools for building user interfaces in the console.

Building Console User Interfaces

While playing with ANSI escape codes is undeniably a ton of fun, in the real world you’d rather have more abstract building blocks to put together a user interface. There are a few libraries that provide such a high level of control over the terminal, but curses seems to be the most popular choice.

Note: To use the curses library in Windows, you need to install a third-party package:

C:\> pip install windows-curses

That’s because curses isn’t available in the standard library of the Python distribution for Windows.

Primarily, it allows you to think in terms of independent graphical widgets instead of a blob of text. Besides, you get a lot of freedom in expressing your inner artist, because it’s really like painting a blank canvas. The library hides the complexities of having to deal with different terminals. Other than that, it has great support for keyboard events, which might be useful for writing video games.

How about making a retro snake game? Let’s create a Python snake simulator:

The retro snake game built with curses library

First, you need to import the curses module. Since it modifies the state of a running terminal, it’s important to handle errors and gracefully restore the previous state. You can do this manually, but the library comes with a convenient wrapper for your main function:

importcursesdefmain(screen):passif__name__=='__main__':curses.wrapper(main)

Note, the function must accept a reference to the screen object, also known as stdscr, that you’ll use later for additional setup.

If you run this program now, you won’t see any effects, because it terminates immediately. However, you can add a small delay to have a sneak peek:

importtime,cursesdefmain(screen):time.sleep(1)if__name__=='__main__':curses.wrapper(main)

This time the screen went completely blank for a second, but the cursor was still blinking. To hide it, just call one of the configuration functions defined in the module:

importtime,cursesdefmain(screen):curses.curs_set(0)# Hide the cursortime.sleep(1)if__name__=='__main__':curses.wrapper(main)

Let’s define the snake as a list of points in screen coordinates:

snake=[(0,i)foriinreversed(range(20))]

The head of the snake is always the first element in the list, whereas the tail is the last one. The initial shape of the snake is horizontal, starting from the top-left corner of the screen and facing to the right. While its y-coordinate stays at zero, its x-coordinate decreases from head to tail.

To draw the snake, you’ll start with the head and then follow with the remaining segments. Each segment carries (y, x) coordinates, so you can unpack them:

# Draw the snakescreen.addstr(*snake[0],'@')forsegmentinsnake[1:]:screen.addstr(*segment,'*')

Again, if you run this code now, it won’t display anything, because you must explicitly refresh the screen afterward:

importtime,cursesdefmain(screen):curses.curs_set(0)# Hide the cursorsnake=[(0,i)foriinreversed(range(20))]# Draw the snakescreen.addstr(*snake[0],'@')forsegmentinsnake[1:]:screen.addstr(*segment,'*')screen.refresh()time.sleep(1)if__name__=='__main__':curses.wrapper(main)

You want to move the snake in one of four directions, which can be defined as vectors. Eventually, the direction will change in response to an arrow keystroke, so you may hook it up to the library’s key codes:

directions={curses.KEY_UP:(-1,0),curses.KEY_DOWN:(1,0),curses.KEY_LEFT:(0,-1),curses.KEY_RIGHT:(0,1),}direction=directions[curses.KEY_RIGHT]

How does a snake move? It turns out that only its head really moves to a new location, while all other segments shift towards it. In each step, almost all segments remain the same, except for the head and the tail. Assuming the snake isn’t growing, you can remove the tail and insert a new head at the beginning of the list:

# Move the snakesnake.pop()snake.insert(0,tuple(map(sum,zip(snake[0],direction))))

To get the new coordinates of the head, you need to add the direction vector to it. However, adding tuples in Python results in a bigger tuple instead of the algebraic sum of the corresponding vector components. One way to fix this is by using the built-in zip(), sum(), and map() functions.

The direction will change on a keystroke, so you need to call .getch() to obtain the pressed key code. However, if the pressed key doesn’t correspond to the arrow keys defined earlier as dictionary keys, the direction won’t change:

# Change direction on arrow keystrokedirection=directions.get(screen.getch(),direction)

By default, however, .getch() is a blocking call that would prevent the snake from moving unless there was a keystroke. Therefore, you need to make the call non-blocking by adding yet another configuration:

defmain(screen):curses.curs_set(0)# Hide the cursorscreen.nodelay(True)# Don't block I/O calls

You’re almost done, but there’s just one last thing left. If you now loop this code, the snake will appear to be growing instead of moving. That’s because you have to erase the screen explicitly before each iteration.

Finally, this is all you need to play the snake game in Python:

importtime,cursesdefmain(screen):curses.curs_set(0)# Hide the cursorscreen.nodelay(True)# Don't block I/O callsdirections={curses.KEY_UP:(-1,0),curses.KEY_DOWN:(1,0),curses.KEY_LEFT:(0,-1),curses.KEY_RIGHT:(0,1),}direction=directions[curses.KEY_RIGHT]snake=[(0,i)foriinreversed(range(20))]whileTrue:screen.erase()# Draw the snakescreen.addstr(*snake[0],'@')forsegmentinsnake[1:]:screen.addstr(*segment,'*')# Move the snakesnake.pop()snake.insert(0,tuple(map(sum,zip(snake[0],direction))))# Change direction on arrow keystrokedirection=directions.get(screen.getch(),direction)screen.refresh()time.sleep(0.1)if__name__=='__main__':curses.wrapper(main)

This is merely scratching the surface of the possibilities that the curses module opens up. You may use it for game development like this or more business-oriented applications.

Living It Up With Cool Animations

Not only can animations make the user interface more appealing to the eye, but they also improve the overall user experience. When you provide early feedback to the user, for example, they’ll know if your program’s still working or if it’s time to kill it.

To animate text in the terminal, you have to be able to freely move the cursor around. You can do this with one of the tools mentioned previously, that is ANSI escape codes or the curses library. However, I’d like to show you an even simpler way.

If the animation can be constrained to a single line of text, then you might be interested in two special escape character sequences:

  • Carriage return:\r
  • Backspace:\b

The first one moves the cursor to the beginning of the line, whereas the second one moves it only one character to the left. They both work in a non-destructive way without overwriting text that’s already been written.

Let’s take a look at a few examples.

You’ll often want to display some kind of a spinning wheel to indicate a work in progress without knowing exactly how much time’s left to finish:

Indefinite animation in the terminal

Many command line tools use this trick while downloading data over the network. You can make a really simple stop motion animation from a sequence of characters that will cycle in a round-robin fashion:

fromitertoolsimportcyclefromtimeimportsleepforframeincycle(r'-\|/-\|/'):print('\r',frame,sep='',end='',flush=True)sleep(0.2)

The loop gets the next character to print, then moves the cursor to the beginning of the line, and overwrites whatever there was before without adding a newline. You don’t want extra space between positional arguments, so separator argument must be blank. Also, notice the use of Python’s raw strings due to backslash characters present in the literal.

When you know the remaining time or task completion percentage, then you’re able to show an animated progress bar:

Progress bar animation in the terminal

First, you need to calculate how many hashtags to display and how many blank spaces to insert. Next, you erase the line and build the bar from scratch:

fromtimeimportsleepdefprogress(percent=0,width=30):left=width*percent//100right=width-leftprint('\r[','#'*left,' '*right,']',f' {percent:.0f}%',sep='',end='',flush=True)foriinrange(101):progress(i)sleep(0.1)

As before, each request for update repaints the entire line.

Note: There’s a feature-rich progressbar2 library, along with a few other similar tools, that can show progress in a much more comprehensive way.

Making Sounds With Print

If you’re old enough to remember computers with a PC speaker, then you must also remember their distinctive beep sound, often used to indicate hardware problems. They could barely make any more noises than that, yet video games seemed so much better with it.

Today you can still take advantage of this small loudspeaker, but chances are your laptop didn’t come with one. In such a case, you can enable terminal bell emulation in your shell, so that a system warning sound is played instead.

Go ahead and type this command to see if your terminal can play a sound:

$echo -e "\a"

This would normally print text, but the -e flag enables the interpretation of backslash escapes. As you can see, there’s a dedicated escape sequence \a, which stands for “alert”, that outputs a special bell character. Some terminals make a sound whenever they see it.

Similarly, you can print this character in Python. Perhaps in a loop to form some kind of melody. While it’s only a single note, you can still vary the length of pauses between consecutive instances. That seems like a perfect toy for Morse code playback!

The rules are the following:

  • Letters are encoded with a sequence of dot (·) and dash (–) symbols.
  • A dot is one unit of time.
  • A dash is three units of time.
  • Individual symbols in a letter are spaced one unit of time apart.
  • Symbols of two adjacent letters are spaced three units of time apart.
  • Symbols of two adjacent words are spaced seven units of time apart.

According to those rules, you could be “printing” an SOS signal indefinitely in the following way:

whileTrue:dot()symbol_space()dot()symbol_space()dot()letter_space()dash()symbol_space()dash()symbol_space()dash()letter_space()dot()symbol_space()dot()symbol_space()dot()word_space()

In Python, you can implement it in merely ten lines of code:

fromtimeimportsleepspeed=0.1defsignal(duration,symbol):sleep(duration)print(symbol,end='',flush=True)dot=lambda:signal(speed,\a')dash=lambda:signal(3*speed,'−\a')symbol_space=lambda:signal(speed,'')letter_space=lambda:signal(3*speed,'')word_space=lambda:signal(7*speed,' ')

Maybe you could even take it one step further and make a command line tool for translating text into Morse code? Either way, I hope you’re having fun with this!

Mocking Python Print in Unit Tests

Nowadays, it’s expected that you ship code that meets high quality standards. If you aspire to become a professional, you must learn how to test your code.

Software testing is especially important in dynamically typed languages, such as Python, which don’t have a compiler to warn you about obvious mistakes. Defects can make their way to the production environment and remain dormant for a long time, until that one day when a branch of code finally gets executed.

Sure, you have linters, type checkers, and other tools for static code analysis to assist you. But they won’t tell you whether your program does what it’s supposed to do on the business level.

So, should you be testing print()? No. After all, it’s a built-in function that must have already gone through a comprehensive suite of tests. What you want to test, though, is whether your code is calling print() at the right time with the expected parameters. That’s known as a behavior.

You can test behaviors by mocking real objects or functions. In this case, you want to mock print() to record and verify its invocations.

Note: You might have heard the terms: dummy, fake, stub, spy, or mock used interchangeably. Some people make a distinction between them, while others don’t.

Martin Fowler explains their differences in a short glossary and collectively calls them test doubles.

Mocking in Python can be done twofold. First, you can take the traditional path of statically-typed languages by employing dependency injection. This may sometimes require you to change the code under test, which isn’t always possible if the code is defined in an external library:

defdownload(url,log=print):log(f'Downloading {url}')# ...

This is the same example I used in an earlier section to talk about function composition. It basically allows for substituting print() with a custom function of the same interface. To check if it prints the right message, you have to intercept it by injecting a mocked function:

>>>
>>> defmock_print(message):... mock_print.last_message=message...>>> download('resource',mock_print)>>> assert'Downloading resource'==mock_print.last_message

Calling this mock makes it save the last message in an attribute, which you can inspect later, for example in an assert statement.

In a slightly alternative solution, instead of replacing the entire print() function with a custom wrapper, you could redirect the standard output to an in-memory file-like stream of characters:

>>>
>>> defdownload(url,stream=None):... print(f'Downloading {url}',file=stream)... # ......>>> importio>>> memory_buffer=io.StringIO()>>> download('app.js',memory_buffer)>>> download('style.css',memory_buffer)>>> memory_buffer.getvalue()'Downloading app.js\nDownloading style.css\n'

This time the function explicitly calls print(), but it exposes its file parameter to the outside world.

However, a more Pythonic way of mocking objects takes advantage of the built-in mock module, which uses a technique called monkey patching. This derogatory name stems from it being a “dirty hack” that you can easily shoot yourself in the foot with. It’s less elegant than dependency injection but definitely quick and convenient.

Note: The mock module got absorbed by the standard library in Python 3, but before that, it was a third-party package. You had to install it separately:

$ pip2 install mock

Other than that, you referred to it as mock, whereas in Python 3 it’s part of the unit testing module, so you must import from unittest.mock.

What monkey patching does is alter implementation dynamically at runtime. Such a change is visible globally, so it may have unwanted consequences. In practice, however, patching only affects the code for the duration of test execution.

To mock print() in a test case, you’ll typically use the @patchdecorator and specify a target for patching by referring to it with a fully qualified name, that is including the module name:

fromunittest.mockimportpatch@patch('builtins.print')deftest_print(mock_print):print('not a real print')mock_print.assert_called_with('not a real print')

This will automatically create the mock for you and inject it to the test function. However, you need to declare that your test function accepts a mock now. The underlying mock object has lots of useful methods and attributes for verifying behavior.

Did you notice anything peculiar about that code snippet?

Despite injecting a mock to the function, you’re not calling it directly, although you could. That injected mock is only used to make assertions afterward and maybe to prepare the context before running the test.

In real life, mocking helps to isolate the code under test by removing dependencies such as a database connection. You rarely call mocks in a test, because that doesn’t make much sense. Rather, it’s other pieces of code that call your mock indirectly without knowing it.

Here’s what that means:

fromunittest.mockimportpatchdefgreet(name):print(f'Hello, {name}!')@patch('builtins.print')deftest_greet(mock_print):greet('John')mock_print.assert_called_with('Hello, John!')

The code under test is a function that prints a greeting. Even though it’s a fairly simple function, you can’t test it easily because it doesn’t return a value. It has a side-effect.

To eliminate that side-effect, you need to mock the dependency out. Patching lets you avoid making changes to the original function, which can remain agnostic about print(). It thinks it’s calling print(), but in reality, it’s calling a mock you’re in total control of.

There are many reasons for testing software. One of them is looking for bugs. When you write tests, you often want to get rid of the print() function, for example, by mocking it away. Paradoxically, however, that same function can help you find bugs during a related process of debugging you’ll read about in the next section.

You can’t monkey patch the print statement in Python 2, nor can you inject it as a dependency. However, you have a few other options:

  • Use stream redirection.
  • Patch the standard output defined in the sys module.
  • Import print() from the __future__ module.

Let’s examine them one by one.

Stream redirection is almost identical to the example you saw earlier:

>>>
>>> defdownload(url,stream=None):... print>>stream,'Downloading %s'%url... # ......>>> fromStringIOimportStringIO>>> memory_buffer=StringIO()>>> download('app.js',memory_buffer)>>> download('style.css',memory_buffer)>>> memory_buffer.getvalue()'Downloading app.js\nDownloading style.css\n'

There are only two differences. First, the syntax for stream redirection uses chevron (>>) instead of the file argument. The other difference is where StringIO is defined. You can import it from a similarly named StringIO module, or cStringIO for a faster implementation.

Patching the standard output from the sys module is exactly what it sounds like, but you need to be aware of a few gotchas:

frommockimportpatch,calldefgreet(name):print'Hello, %s!'%name@patch('sys.stdout')deftest_greet(mock_stdout):greet('John')mock_stdout.write.assert_has_calls([call('Hello, John!'),call('\n')])

First of all, remember to install the mock module as it wasn’t available in the standard library in Python 2.

Secondly, the print statement calls the underlying .write() method on the mocked object instead of calling the object itself. That’s why you’ll run assertions against mock_stdout.write.

Finally, a single print statement doesn’t always correspond to a single call to sys.stdout.write(). In fact, you’ll see the newline character written separately.

The last option you have is importing print() from future and patching it:

from__future__importprint_functionfrommockimportpatchdefgreet(name):print('Hello, %s!'%name)@patch('__builtin__.print')deftest_greet(mock_print):greet('John')mock_print.assert_called_with('Hello, John!')

Again, it’s nearly identical to Python 3, but the print() function is defined in the __builtin__ module rather than builtins.

In this section, you’ll take a look at the available tools for debugging in Python, starting from a humble print() function, through the logging module, to a fully fledged debugger. After reading it, you’ll be able to make an educated decision about which of them is the most suitable in a given situation.

Note: Debugging is the process of looking for the root causes of bugs or defects in software after they’ve been discovered, as well as taking steps to fix them.

The term bug has an amusing story about the origin of its name.

Tracing

Also known as print debugging or caveman debugging, it’s the most basic form of debugging. While a little bit old-fashioned, it’s still powerful and has its uses.

The idea is to follow the path of program execution until it stops abruptly, or gives incorrect results, to identify the exact instruction with a problem. You do that by inserting print statements with words that stand out in carefully chosen places.

Take a look at this example, which manifests a rounding error:

>>>
>>> defaverage(numbers):... print('debug1:',numbers)... iflen(numbers)>0:... print('debug2:',sum(numbers))... returnsum(numbers)/len(numbers)...>>> 0.1==average(3*[0.1])debug1: [0.1, 0.1, 0.1]debug2: 0.30000000000000004False

As you can see, the function doesn’t return the expected value of 0.1, but now you know it’s because the sum is a little off. Tracing the state of variables at different steps of the algorithm can give you a hint where the issue is.

In this case, the problem lies in how floating point numbers are represented in computer memory. Remember that numbers are stored in binary form. Decimal value of 0.1 turns out to have an infinite binary representation, which gets rounded.

For more information on rounding numbers in Python, you can check out How to Round Numbers in Python.

This method is simple and intuitive and will work in pretty much every programming language out there. Not to mention, it’s a great exercise in the learning process.

On the other hand, once you master more advanced techniques, it’s hard to go back, because they allow you to find bugs much quicker. Tracing is a laborious manual process, which can let even more errors slip through. The build and deploy cycle takes time. Afterward, you need to remember to meticulously remove all the print() calls you made without accidentally touching the genuine ones.

Besides, it requires you to make changes in the code, which isn’t always possible. Maybe you’re debugging an application running in a remote web server or want to diagnose a problem in a post-mortem fashion. Sometimes you simply don’t have access to the standard output.

That’s precisely where logging shines.

Logging

Let’s pretend for a minute that you’re running an e-commerce website. One day, an angry customer makes a phone call complaining about a failed transaction and saying he lost his money. He claims to have tried purchasing a few items, but in the end, there was some cryptic error that prevented him from finishing that order. Yet, when he checked his bank account, the money was gone.

You apologize sincerely and make a refund, but also don’t want this to happen again in the future. How do you debug that? If only you had some trace of what happened, ideally in the form of a chronological list of events with their context.

Whenever you find yourself doing print debugging, consider turning it into permanent log messages. This may help in situations like this, when you need to analyze a problem after it happened, in an environment that you don’t have access to.

There are sophisticated tools for log aggregation and searching, but at the most basic level, you can think of logs as text files. Each line conveys detailed information about an event in your system. Usually, it won’t contain personally identifying information, though, in some cases, it may be mandated by law.

Here’s a breakdown of a typical log record:

[2019-06-14 15:18:34,517][DEBUG][root][MainThread] Customer(id=123) logged out

As you can see, it has a structured form. Apart from a descriptive message, there are a few customizable fields, which provide the context of an event. Here, you have the exact date and time, the log level, the logger name, and the thread name.

Log levels allow you to filter messages quickly to reduce noise. If you’re looking for an error, you don’t want to see all the warnings or debug messages, for example. It’s trivial to disable or enable messages at certain log levels through the configuration, without even touching the code.

With logging, you can keep your debug messages separate from the standard output. All the log messages go to the standard error stream by default, which can conveniently show up in different colors. However, you can redirect log messages to separate files, even for individual modules!

Quite commonly, misconfigured logging can lead to running out of space on the server’s disk. To prevent that, you may set up log rotation, which will keep the log files for a specified duration, such as one week, or once they hit a certain size. Nevertheless, it’s always a good practice to archive older logs. Some regulations enforce that customer data be kept for as long as five years!

Compared to other programming languages, logging in Python is simpler, because the logging module is bundled with the standard library. You just import and configure it in as little as two lines of code:

importlogginglogging.basicConfig(level=logging.DEBUG)

You can call functions defined at the module level, which are hooked to the root logger, but more the common practice is to obtain a dedicated logger for each of your source files:

logging.debug('hello')# Module-level functionlogger=logging.getLogger(__name__)logger.debug('hello')# Logger's method

The advantage of using custom loggers is more fine-grain control. They’re usually named after the module they were defined in through the __name__ variable.

Note: There’s a somewhat related warnings module in Python, which can also log messages to the standard error stream. However, it has a narrower spectrum of applications, mostly in library code, whereas client applications should use the logging module.

That said, you can make them work together by calling logging.captureWarnings(True).

One last reason to switch from the print() function to logging is thread safety. In the upcoming section, you’ll see that the former doesn’t play well with multiple threads of execution.

Debugging

The truth is that neither tracing nor logging can be considered real debugging. To do actual debugging, you need a debugger tool, which allows you to do the following:

  • Step through the code interactively.
  • Set breakpoints, including conditional breakpoints.
  • Introspect variables in memory.
  • Evaluate custom expressions at runtime.

A crude debugger that runs in the terminal, unsurprisingly named pdb for “The Python Debugger,” is distributed as part of the standard library. This makes it always available, so it may be your only choice for performing remote debugging. Perhaps that’s a good reason to get familiar with it.

However, it doesn’t come with a graphical interface, so using pdb may be a bit tricky. If you can’t edit the code, you have to run it as a module and pass your script’s location:

$ python -m pdb my_script.py

Otherwise, you can set up a breakpoint directly in the code, which will pause the execution of your script and drop you into the debugger. The old way of doing this required two steps:

>>>
>>> importpdb>>> pdb.set_trace()--Return--> <stdin>(1)<module>()->None(Pdb)

This shows up an interactive prompt, which might look intimidating at first. However, you can still type native Python at this point to examine or modify the state of local variables. Apart from that, there’s really only a handful of debugger-specific commands that you want to use for stepping through the code.

Note: It’s customary to put the two instructions for spinning up a debugger on a single line. This requires the use of a semicolon, which is rarely found in Python programs:

importpdb;pdb.set_trace()

While certainly not Pythonic, it stands out as a reminder to remove it after you’re done with debugging.

Since Python 3.7, you can also call the built-in breakpoint() function, which does the same thing, but in a more compact way and with some additional bells and whistles:

defaverage(numbers):iflen(numbers)>0:breakpoint()# Python 3.7+returnsum(numbers)/len(numbers)

You’re probably going to use a visual debugger integrated with a code editor for the most part. PyCharm has an excellent debugger, which boasts high performance, but you’ll find plenty of alternative IDEs with debuggers, both paid and free of charge.

Debugging isn’t the proverbial silver bullet. Sometimes logging or tracing will be a better solution. For example, defects that are hard to reproduce, such as race conditions, often result from temporal coupling. When you stop at a breakpoint, that little pause in program execution may mask the problem. It’s kind of like the Heisenberg principle: you can’t measure and observe a bug at the same time.

These methods aren’t mutually exclusive. They complement each other.

Thread-Safe Printing

I briefly touched upon the thread safety issue before, recommending logging over the print() function. If you’re still reading this, then you must be comfortable with the concept of threads.

Thread safety means that a piece of code can be safely shared between multiple threads of execution. The simplest strategy for ensuring thread-safety is by sharing immutable objects only. If threads can’t modify an object’s state, then there’s no risk of breaking its consistency.

Another method takes advantage of local memory, which makes each thread receive its own copy of the same object. That way, other threads can’t see the changes made to it in the current thread.

But that doesn’t solve the problem, does it? You often want your threads to cooperate by being able to mutate a shared resource. The most common way of synchronizing concurrent access to such a resource is by locking it. This gives exclusive write access to one or sometimes a few threads at a time.

However, locking is expensive and reduces concurrent throughput, so other means for controlling access have been invented, such as atomic variables or the compare-and-swap algorithm.

Printing isn’t thread-safe in Python. The print() function holds a reference to the standard output, which is a shared global variable. In theory, because there’s no locking, a context switch could happen during a call to sys.stdout.write(), intertwining bits of text from multiple print() calls.

Note: A context switch means that one thread halts its execution, either voluntarily or not, so that another one can take over. This might happen at any moment, even in the middle of a function call.

In practice, however, that doesn’t happen. No matter how hard you try, writing to the standard output seems to be atomic. The only problem that you may sometimes observe is with messed up line breaks:

[Thread-3 A][Thread-2 A][Thread-1 A]

[Thread-3 B][Thread-1 B]


[Thread-1 C][Thread-3 C]

[Thread-2 B]
[Thread-2 C]

To simulate this, you can increase the likelihood of a context switch by making the underlying .write() method go to sleep for a random amount of time. How? By mocking it, which you already know about from an earlier section:

importsysfromtimeimportsleepfromrandomimportrandomfromthreadingimportcurrent_thread,Threadfromunittest.mockimportpatchwrite=sys.stdout.writedefslow_write(text):sleep(random())write(text)deftask():thread_name=current_thread().nameforletterin'ABC':print(f'[{thread_name}{letter}]')withpatch('sys.stdout')asmock_stdout:mock_stdout.write=slow_writefor_inrange(3):Thread(target=task).start()

First, you need to store the original .write() method in a variable, which you’ll delegate to later. Then you provide your fake implementation, which will take up to one second to execute. Each thread will make a few print() calls with its name and a letter: A, B, and C.

If you read the mocking section before, then you may already have an idea of why printing misbehaves like that. Nonetheless, to make it crystal clear, you can capture values fed into your slow_write() function. You’ll notice that you get a slightly different sequence each time:

['[Thread-3 A]','[Thread-2 A]','[Thread-1 A]','\n','\n','[Thread-3 B]',(...)]

Even though sys.stdout.write() itself is an atomic operation, a single call to the print() function can yield more than one write. For example, line breaks are written separately from the rest of the text, and context switching takes place between those writes.

Note: The atomic nature of the standard output in Python is a byproduct of the Global Interpreter Lock, which applies locking around bytecode instructions. Be aware, however, that many interpreter flavors don’t have the GIL, where multi-threaded printing requires explicit locking.

You can make the newline character become an integral part of the message by handling it manually:

print(f'[{thread_name}{letter}]\n',end='')

This will fix the output:

[Thread-2 A]
[Thread-1 A]
[Thread-3 A]
[Thread-1 B]
[Thread-3 B]
[Thread-2 B]
[Thread-1 C]
[Thread-2 C]
[Thread-3 C]

Notice, however, that the print() function still keeps making a separate call for the empty suffix, which translates to useless sys.stdout.write('') instruction:

['[Thread-2 A]\n','[Thread-1 A]\n','[Thread-3 A]\n','','','','[Thread-1 B]\n',(...)]

A truly thread-safe version of the print() function could look like this:

importthreadinglock=threading.Lock()defthread_safe_print(*args,**kwargs):withlock:print(*args,**kwargs)

You can put that function in a module and import it elsewhere:

fromthread_safe_printimportthread_safe_printdeftask():thread_name=current_thread().nameforletterin'ABC':thread_safe_print(f'[{thread_name}{letter}]')

Now, despite making two writes per each print() request, only one thread is allowed to interact with the stream, while the rest must wait:

[# Lock acquired by Thread-3 '[Thread-3 A]','\n',# Lock released by Thread-3# Lock acquired by Thread-1'[Thread-1 B]','\n',# Lock released by Thread-1(...)]

I added comments to indicate how the lock is limiting access to the shared resource.

Note: Even in single-threaded code, you might get caught up in a similar situation. Specifically, when you’re printing to the standard output and the standard error streams at the same time. Unless you redirect one or both of them to separate files, they’ll both share a single terminal window.

Conversely, the logging module is thread-safe by design, which is reflected by its ability to display thread names in the formatted message:

>>>
>>> importlogging>>> logging.basicConfig(format='%(threadName)s%(message)s')>>> logging.error('hello')MainThread hello

It’s another reason why you might not want to use the print() function all the time.

Python Print Counterparts

By now, you know a lot of what there is to know about print()! The subject, however, wouldn’t be complete without talking about its counterparts a little bit. While print() is about the output, there are functions and libraries for the input.

Built-In

Python comes with a built-in function for accepting input from the user, predictably called input(). It accepts data from the standard input stream, which is usually the keyboard:

>>>
>>> name=input('Enter your name: ')Enter your name: jdoe>>> print(name)jdoe

The function always returns a string, so you might need to parse it accordingly:

try:age=int(input('How old are you? '))exceptValueError:pass

The prompt parameter is completely optional, so nothing will show if you skip it, but the function will still work:

>>>
>>> x=input()hello world>>> print(x)hello world

Nevertheless, throwing in a descriptive call to action makes the user experience so much better.

Note: To read from the standard input in Python 2, you have to call raw_input() instead, which is yet another built-in. Unfortunately, there’s also a misleadingly named input() function, which does a slightly different thing.

In fact, it also takes the input from the standard stream, but then it tries to evaluate it as if it was Python code. Because that’s a potential security vulnerability, this function was completely removed from Python 3, while raw_input() got renamed to input().

Here’s a quick comparison of the available functions and what they do:

Python 2Python 3
raw_input()input()
input()eval(input())

As you can tell, it’s still possible to simulate the old behavior in Python 3.

Asking the user for a password with input() is a bad idea because it’ll show up in plaintext as they’re typing it. In this case, you should be using the getpass() function instead, which masks typed characters. This function is defined in a module under the same name, which is also available in the standard library:

>>>
>>> fromgetpassimportgetpass>>> password=getpass()Password: >>> print(password)s3cret

The getpass module has another function for getting the user’s name from an environment variable:

>>>
>>> fromgetpassimportgetuser>>> getuser()'jdoe'

Python’s built-in functions for handling the standard input are quite limited. At the same time, there are plenty of third-party packages, which offer much more sophisticated tools.

Third-Party

There are external Python packages out there that allow for building complex graphical interfaces specifically to collect data from the user. Some of their features include:

  • Advanced formatting and styling
  • Automated parsing, validation, and sanitization of user data
  • A declarative style of defining layouts
  • Interactive autocompletion
  • Mouse support
  • Predefined widgets such as checklists or menus
  • Searchable history of typed commands
  • Syntax highlighting

Demonstrating such tools is outside of the scope of this article, but you may want to try them out. I personally got to know about some of those through the Python Bytes Podcast. Here they are:

Nonetheless, it’s worth mentioning a command line tool called rlwrap that adds powerful line editing capabilities to your Python scripts for free. You don’t have to do anything for it to work!

Let’s assume you wrote a command-line interface that understands three instructions, including one for adding numbers:

print('Type "help", "exit", "add a [b [c ...]]"')whileTrue:command,*arguments=input('~ ').split(' ')iflen(command)>0:ifcommand.lower()=='exit':breakelifcommand.lower()=='help':print('This is help.')elifcommand.lower()=='add':print(sum(map(int,arguments)))else:print('Unknown command')

At first glance, it seems like a typical prompt when you run it:

$ python calculator.py
Type "help", "exit", "add a [b [c ...]]"~ add 1 2 3 410~ aad 2 3Unknown command~ exit$

But as soon as you make a mistake and want to fix it, you’ll see that none of the function keys work as expected. Hitting the Left arrow, for example, results in this instead of moving the cursor back:

$ python calculator.py
Type "help", "exit", "add a [b [c ...]]"~ aad^[[D

Now, you can wrap the same script with the rlwrap command. Not only will you get the arrow keys working, but you’ll also be able to search through the persistent history of your custom commands, use autocompletion, and edit the line with shortcuts:

$ rlwrap python calculator.py
Type "help", "exit", "add a [b [c ...]]"(reverse-i-search)`a': add 1 2 3 4

Isn’t that great?

Conclusion

You’re now armed with a body of knowledge about the print() function in Python, as well as many surrounding topics. You have a deep understanding of what it is and how it works, involving all of its key elements. Numerous examples gave you insight into its evolution from Python 2.

Apart from that, you learned how to:

  • Avoid common mistakes with print() in Python
  • Deal with newlines, character encodings and buffering
  • Write text to files
  • Mock the print() function in unit tests
  • Build advanced user interfaces in the terminal

Now that you know all this, you can make interactive programs that communicate with users or produce data in popular file formats. You’re able to quickly diagnose problems in your code and protect yourself from them. Last but not least, you know how to implement the classic snake game.

If you’re still thirsty for more information, have questions, or simply would like to share your thoughts, then feel free to reach out in the comments section below.


[ 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 ]

Curtis Miller: Learn Python Statistics and Machine Learning with My New Book: Training Systems using Python Statistical Modeling

$
0
0
Packt Publishing has turned another one of my video courses, Training Your Systems with Python Statistical Modeling, into a book! This book is now available for purchase. It is a tutorial book for Python statistics and machine learning.

CodeGrades: CodeGrades on Podcast.__init__

$
0
0

CodeGrades was recently on the Podcast.__init__ show where we had lots of fun exploring the links between music and coding education as a way to explain the concepts behind CodeGrades.

Podcast.__init__

The host, Tobias, asked plenty of interesting questions, giving us a chance to explain and unpack the high-level aspects of the project, tell the story so far and describe the various upcoming milestones. We were also able to touch upon related projects such as the Mu beginner’s code editor and PyperCard GUI framework, also aimed at beginner developers.

We were very pleased with Tobias’s positive reaction to CodeGrades.

Codementor: Top 9 Django Concepts - Part 1: 4 Mins

$
0
0
The 1st part of a 3 part series on 9 concepts of Django to help any aspiring Django developer to accelerate their learnings

Stack Abuse: Using Django Signals to Simplify and Decouple Code

$
0
0

Introduction

Systems are getting more complex as time goes by and this warrants the need to decouple systems more. A decoupled system is easier to build, extend, and maintain in the long run since not only does decoupling reduce the complexity of the system, each part of the system can be managed individually. Fault tolerance has also enhanced since, in a decoupled system, a failing component does not drag down the entire system with it.

Django is a powerful open-source web framework that can be used to build large and complex systems, as well as small ones. It follows the model-template-view architectural pattern and it is true to its goal of helping developers achieve the delivery of complex data-driven web-based applications.

Django enables us to decouple system functionality by building separate apps within a project. For instance, we can have a shopping system and have separate apps that handle accounts, emailing of receipts, and notifications, among other things.

In such a system, several apps may be need to perform an action when certain events take place. One event can occur when a customer places an order. For exmaple, we will need to notify the user via email and also send the order to the supplier or vendor, at the same time we can be able to receive and process payments. All these events happen at the same time and since our application is decoupled, we need to keep every component in sync, but how do we achieve this?

Django Signals come in handy in such a situation, all that needs to happen is a signal is sent when a user places an order, and every related or affected component listens out for it and performs its operations. Let us explore more about signals in this post.

Signals at a Glance

Django Signals are an implementation of the Observer Pattern. In such a design pattern, a subscription mechanism is implemented where multiple objects are subscribed to, or "observing", a particular object and any events that may happen to it. A good analogy is how all subscribers to a YouTube channel get a notification when a content creator uploads new content.

Through a "signal dispatcher", Django is able to distribute signals in a decoupled setup to registered "receivers" in the various system components. Signals are registered and triggered whenever certain events occur, and any listeners to that event will get notified that event has occurred, alongside receiving some contextual data within the payload that may be relevant to the functionality of the receiver. A receiver can be any Python function or method. More on this later on.

Aside from the signals dispatcher, Django also ships with some useful signals that we can listen on. They include:

  • post_save, which is sent out whenever a new Django model has been created and saved. For instance, when a user signs up or uploads a new post,
  • pre_delete, which is sent out just before a Django model is deleted. A good scenario would be when a user is deleting a message or their account,
  • request_finished, which is fired whenever Django completes serving an HTTP request. This can range from opening the website or accessing a particular resource.

Another advantage of Django is that it is a highly customizable framework. In our case, we can create our custom signals and use the built-in system to dispatch and receive them in our decoupled system. In the demo section, we will subscribe to some of Django's built-in signals, and also create some custom ones of our own.

When to Use Signals

We have already identified what Django Signals are and how they work, but as is with any other framework feature, it is not meant to be used at every turn. There are particular scenarios where it is highly recommended that we use Django signals, and they include:

  • When we have many separate pieces of code interested in the same events, a signal would help distribute the event notification as opposed to us invoking all of the different pieces of code at the same point, which can get untidy and introduce bugs
  • We can also use Django signals to handle interactions between components in a decoupled system as an alternative to interaction through RESTful communication mechanisms
  • Signals are also useful when extending third-party libraries where we want to avoid modifying them, but need to add extra functionality

Advantages of Signals

Django Signals simplify the implementation of our decoupled systems in various ways. They help us implement reusable applications and instead of reimplementing functionality severally, or modifying other parts of the system, we can just respond to signals without affecting other code. This way, components of a system can be modified, added, or removed without touching the existing codebase.

Signals also provide a simplified mechanism for keeping different components of a decoupled system in sync and up to date with each other.

Demo Project

In our demo project, we will build a simple jobs board where users will access the site, view available jobs and pick a job posting to subscribe to. The users will subscribe just by submitting their email address and will be notified of any changes to the job. For instance, if the requirements change, the job opening is closed, or if the job posting is taken down. All of these changes will be performed by an admin who will have a dashboard to create, update, and even take down job postings.

In the spirit of decoupling our application, we will build the main Jobs Board application and a separate Notifications application that will be tasked with notifying users whenever required. We will then use signals to invoke functionality in the Notifications app from the main Jobs Board app.

Another testament of Django's expansive feature-set is the built-in administration dashboard that our administrators will use to manage jobs. Our work on that front is greatly reduced and we can prototype our application faster.

Project Setup

It is good practice to build Python projects in a virtual environment so that we work in an isolated environment that does not affect the system's Python setup, so we'll use Pipenv.

Let us first set up our environment:

# Set up the environment
$ pipenv install --three

# Activate the virtual environment
$ pipenv shell

# Install Django
$ pipenv install django

Django comes with some commands that help us perform various tasks such as creating a project, creating apps, migrating data, and testing code, among others. To create our project:

# Create the project
$ django-admin startproject jobs_board && cd jobs_board

# Create the decoupled applications
$ django-admin startapp jobs_board_main
$ django-admin startapp jobs_board_notifications

The commands above will create a Django project with two applications within it, which are decoupled from each other but can still work together. To confirm that our setup was successful, let us migrate the default migrations that come with Django and set up our database and tables:

$ python manage.py migrate
$ python manage.py runserver

When we access the local running instance of our Django project, we should see the following:

django set up

This means we have set up our Django project successfully and can now start implementing our logic.

Implementation

Django is based on a model-view-template architecture pattern, and this pattern will also guide our implementation. We will create models to define our data, then implement views to handle data access and manipulation, and finally templates to render our data to the end-user on the browser.

To have our applications integrated into the main Django application, we have to add them to the jobs_board/settings.py under INSTALLED_APPS, as follows:

INSTALLED_APPS = [
    # Existing apps remain...

    # jobs_board apps
    'jobs_board_main',
    'jobs_board_notifications',
]

Part 1: The Main Jobs Board App

This is where the bulk of our system's functionality will reside and it will be the interaction point with our users. It will contain our models, views and templates and some bespoke signals that we will use to interact with the Notifications app.

Let us start by creating our models in jobs_board_main/models.py:

# jobs_board_main/models.py

class Job(models.Model):
    company = models.CharField(max_length=255, blank=False)
    company_email = models.CharField(max_length=255, blank=False)
    title = models.CharField(max_length=255, blank=False)
    details = models.CharField(max_length=255, blank=True)
    status = models.BooleanField(default=True)
    date_created = models.DateTimeField(auto_now_add=True)
    date_modified = models.DateTimeField(auto_now=True)

class Subscriber(models.Model):
    email = models.CharField(max_length=255, blank=False, unique=True)
    date_created = models.DateTimeField(auto_now_add=True)
    date_modified = models.DateTimeField(auto_now=True)

class Subscription(models.Model):
    email = models.CharField(max_length=255, blank=False, unique=True)
    user = models.ForeignKey(Subscriber, related_name="subscriptions", on_delete=models.CASCADE)
    job = models.ForeignKey(Job, related_name="jobs", on_delete=models.CASCADE)
    date_created = models.DateTimeField(auto_now_add=True)
    date_modified = models.DateTimeField(auto_now=True)

We create a model to define our Job posting, which will only have a company name and the job details alongside the status of the job opening. We will also have a model to store our subscribers by only taking their email addresses. The Subscribers and the Jobs come together through the Subscription model where we will store details on subscriptions to Job postings.

With our models in place, we need to make migrations and migrate them to have the tables created in the database:

$ python manage.py makemigrations
$ python manage.py migrate

Next we move on to the view section of our application. Let's create a view to display all job postings, and another to display individual job postings where users can subscribe to them by submitting their emails.

We will start by creating the view that will handle the displaying of all our jobs:

# jobs_board_main/views.py

from .models import Job

def get_jobs(request):
    # get all jobs from the DB
    jobs = Job.objects.all()
    return render(request, 'jobs.html', {'jobs': jobs})

For this project we will use function-based views, the alternative being class-based views, but that is not part of this discussion. We query the database for all the jobs and respond to the request by specifying the template that will render the jobs and also including the jobs in the response.

Django ships with the Jinja templating engine which we will use to create the HTML files that will be rendered to the end-user. In our jobs_board_main application, we will create a templates folder that will host all the HTML files that we will render to the end-users.

The template to render all the jobs will display all jobs with links to individual job postings, as follows:

<!-- jobs_board_main/templates/jobs.html -->
<!DOCTYPE html>
<html>
  <head>
    <title>Jobs Board Homepage</title>
  </head>
  <body>
    <h2> Welcome to the Jobs board </h2>

    {% for job in jobs %}
      <div>
        <a href="/jobs/{{ job.id }}">{{ job.title }} at {{ job.company }}</a>
        <p>
          {{ job.details }}
        </p>
      </div>
    {% endfor %}

  </body>
</html>

We have created the Job model, the get_jobs view to get and display all the views, and the template to render the jobs listing. To bring all this work together, we have to create an endpoint from which the jobs will be accessible, and we do so by creating a urls.py file in our jobs_board_main_application:

# jobs_board_main/urls.py

from django.urls import path
from .views import get_jobs

urlpatterns = [
    # All jobs
    path('jobs/', get_jobs, name="jobs_view"),
]

In this file, we import our view, create a path and attach our view to it. We will now register our applications URLs in the main urls.py file in the jobs_board project folder:

# jobs_board/urls.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('jobs_board_main.urls')), # <--- Add this line
]

Our project is ready to be tested now. This is what we get when we run the application and navigate to localhost:8000/jobs:

jobs board landing 1

We currently have no jobs in place. Django ships with an administration application that we can use to perform our data entry. First, we start by creating a superuser:

create superuser

With the superuser created, we need to register our models in the admin.py file in our jobs_board_main application:

# jobs_board_main/admin.py
from django.contrib import admin
from .models import Job

# Register your models here.
admin.site.register(Job)

We restart our application and navigate to localhost:8000/admin and log in with the credentials we just set up. This is the result:

jobs board admin 1

When we click on the plus sign on the "Jobs" row, we get a form where we fill in details about our job posting:

jobs data entry

When we save the job and navigate back to the jobs endpoint, we are greeted by the job posting that we have just created:

jobs board landing 2

We will now create the views, templates, and URLs to display a single job and also allow users to subscribe by submitting their email.

Our jobs_board_main/views.py will be extended as follows:

# jobs_board_main/views.py
# previous code remains
def get_job(request, id):
    job = Job.objects.get(pk=id)
    return render(request, 'job.html', {'job': job})

def subscribe(request, id):
    job = Job.objects.get(pk=id)
    sub = Subscriber(email=request.POST['email'])
    sub.save()

    subscription = Subscription(user=sub, job=job)
    subscription.save()

    payload = {
      'job': job,
      'email': request.POST['email']
    }
    return render(request, 'subscribed.html', {'payload': payload})

We will also need to create the template for a single view of a job posting in templates/job.html, which includes the form that will take in a user's email and subscribe them to the job posting:

<!-- jobs_board_main/templates/job.html -->
<html>
  <head>
    <title>Jobs Board - {{ job.title }}</title>
  </head>
  <body>
      <div>
        <h3>{{ job.title }} at {{ job.company }}</h3>
        <p>
          {{ job.details }}
        </p>
        <br>
        <p>Subscribe to this job posting by submitting your email</p>
        <form action="/jobs/{{ job.id }}/subscribe" method="POST">
          {% csrf_token %}
          <input type="email" name="email" id="email" placeholder="Enter your email"/>
          <input type="submit" value="Subscribe">
        </form>
        <hr>
      </div>
  </body>
</html>

Once a user subscribes to a job, we will need to redirect them to a confirmation page whose subscribed.html template will be as follows:

<!-- jobs_board_main/templates/subscribed.html -->
<!DOCTYPE html>
<html>
  <head>
    <title>Jobs Board - Subscribed</title>
  </head>
  <body>
      <div>
        <h3>Subscription confirmed!</h3>
        <p>
          Dear {{ payload.email }}, thank you for subscribing to {{ payload.job.title }}
        </p>
      </div>
  </body>
</html>

Finally, our new functionality will need to exposed via endpoints which we will append to our existing jobs_board_main/urls.py as follows:

# jobs_board_main/urls.py
from .views import get_jobs, get_job, subscribe

urlpatterns = [
    # All jobs
    path('jobs/', get_jobs, name="jobs_view"),
    path('jobs/<int:id>', get_job, name="job_view"),
    path('jobs/<int:id>/subscribe', subscribe, name="subscribe_view"),
]

We can now test our main Jobs Board application by viewing the job posts listings, clicking on one, and submitting an email address that will receive updates.

Now that we have a working application, it is time to bring in Django Signals and notify users/subscribers when certain events take place. Job postings are tied to a certain company whose email we record, we want to notify them when a new user subscribes to their job posting. We also want to notify subscribed users when a job posting is taken down.

To notify users when a job posting is taken down or deleted, we will utilize Django's built-in post_delete signal. We will also create our signal called new_subscriber that we will use to notify companies when users subscribe to their job posting.

We create our custom signals by creating a signals.py file in our jobs_board_main application:

# jobs_board_main/signals.py
from django.dispatch import Signal

new_subscriber = Signal(providing_args=["job", "subscriber"])

That's it! Our custom signal is ready to be invoked after a user has successfully subscribed to a job posting as follows in our jobs_board_main/views.py file:

# jobs_board_main/views.py

# Existing imports and code are maintained and truncated for brevity
from .signals import new_subscriber

def subscribe(request, id):
    job = Job.objects.get(pk=id)
    subscriber = Subscriber(email=request.POST['email'])
    subscriber.save()

    subscription = Subscription(user=subscriber, job=job, email=subscriber.email)
    subscription.save()

    # Add this line that sends our custom signal
    new_subscriber.send(sender=subscription, job=job, subscriber=subscriber)

    payload = {
      'job': job,
      'email': request.POST['email']
    }
    return render(request, 'subscribed.html', {'payload': payload})

We don't have to worry about the pre_delete signal as Django will send that for us automatically just before a job posting is deleted. The reason we are using pre_delete and not post_delete signal is because, when a Job is deleted, all linked subscriptions are also deleted in the process and we need that data before they are also deleted.

Let us now consume the signals that we have just sent in a separate jobs_board_notifications app.

Part 2: The Jobs Board Notifications App

We already created the jobs_board_notifications application and connected it to our Django project. In this section, we will consume the signals sent from our main application and send out the notifications. Django has built-in functionality to send out emails, but for development purposes, we will print the messages to the console instead.

Our jobs_board_notifications application does not need user interaction, therefore, we do not need to create any views or templates for that purpose. The only goal is for our jobs_board_notifications is to receive signals and send out notifications. We will implement this functionality in our models.py since it gets imported early when the application is starting.

Let us receive our signals in our jobs_board_notifications/models.py:

# jobs_board_notifications/models.py.
from django.db.models.signals import pre_delete
from django.dispatch import receiver

from jobs_board_main.signals import new_subscriber
from jobs_board_main.models import Job, Subscriber, Subscription

@receiver(new_subscriber, sender=Subscription)
def handle_new_subscription(sender, **kwargs):
    subscriber = kwargs['subscriber']
    job = kwargs['job']

    message = """User {} has just subscribed to the Job {}.
    """.format(subscriber.email, job.title)

    print(message)

@receiver(pre_delete, sender=Job)
def handle_deleted_job_posting(**kwargs):
    job = kwargs['instance']

    # Find the subscribers list
    subscribers = Subscription.objects.filter(job=job)

    for subscriber in subscribers:
        message = """Dear {}, the job posting {} by {} has been taken down.
        """.format(subscriber.email, job.title, job.company)

        print(message)

In our jobs_board_notifications, we import our custom signal, the pre_save signal, and our models. Using the @receiverdecorator, we capture the signals and the contextual data passed with them as keyword arguments.

Upon receiving the contextual data, we use it to dispatch the "emails" (recall that we're just printing to the console for the sake of simplicity) to subscribers and companies when a user subscribes and a job posting is deleted by responding to the signals we sent out.

Testing

Once we have created a job in our admin dashboard, it is available for users to subscribe. When users subscribe, the following email is sent out from the jobs_board_notifications application to the company that owns the posting:

job subscribe message

This is proof that our new_subscriber signal was sent out from the jobs_board_main application and received by the jobs_board_notifications application.

When a job posting is deleted, all users who subscribed to the job posting get notified via email, as follows:

job deleted email

Django's pre_delete signal came in handy and our handler sent out notifications to the subscribed users that the particular job posting has been taken down.

Summary

In this article we have built a Django project with two applications which communicate through Django Signals in response to certain events. Our two applications are decoupled and the complexity in communication between our applications has been greatly reduced. When a user subscribes to a job posting, we notify the company. In turn, when a job posting has been deleted, we notify all subscribed customers that the job posting has been taken down.

However, there are some things we should have in mind when utilizing Django Signals. When signals are not well documented, new maintainers may have a hard time identifying the root cause of certain issues or unexpected behavior. Therefore, when signals are used in an application, it is a good idea to document the signals used, where they are received, and the reason behind them. This will help anyone maintaining the code to understand application behavior and solve issues faster and better. Also, it is helpful to note that signals are sent out synchronously. They are not executed in the background or by any asynchronous jobs.

With all this information about Django's Signals and the demo project, we should be able to harness the power of Signals in our Django web projects.

The source code for this project is available here on Github.

Real Python: Traditional Face Detection With Python

$
0
0

Computer vision is an exciting and growing field. There are tons of interesting problems to solve! One of them is face detection: the ability of a computer to recognize that a photograph contains a human face, and tell you where it is located. In this course, you’ll learn about face detection with Python.

To detect any object in an image, it is necessary to understand how images are represented inside a computer, and how that object differs visually from any other object.

Once that is done, the process of scanning an image and looking for those visual cues needs to be automated and optimized. All these steps come together to form a fast and reliable computer vision algorithm.

In this course, you’ll learn:

  • What face detection is
  • How computers understand features in images
  • How to quickly analyze many different features to reach a decision
  • How to use a minimal Python solution for detecting human faces in images

[ 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 ]

Continuum Analytics Blog: What’s in a Name? Clarifying the Anaconda Metapackage

$
0
0

The name “Anaconda” is overloaded in many ways. There’s our company, Anaconda, Inc., the Anaconda Distribution, the anaconda metapackage, Anaconda Enterprise, and several other, sometimes completely unrelated projects (like Red Hat’s Anaconda). Here we hope…

The post What’s in a Name? Clarifying the Anaconda Metapackage appeared first on Anaconda.


Continuum Analytics Blog: Getting Started with Machine Learning in the Enterprise

Bhavin Gandhi: Organizing PythonPune Meetups

$
0
0
One thing I like most about meetups is, you get to meet new people. Talking with people, sharing what they are doing helps a lot to gain more knowledge. It is also a good platform to make connections with people having similar area of interests. I have been attending PythonPune meetup since last 2 years. In this blog post, I will be sharing some history about this group and how I got involved in organizing meetups.

Continuum Analytics Blog: Getting Started with Machine Learning in the Enterprise

Mike Driscoll: An Intro to Flake8

$
0
0

Python has several linters that you can use to help you find errors in your code or warnings about style. For example, one of the most thorough linters is Pylint.

Flake8 is described as a tool for style guide enforcement. It is also a wrapper around PyFlakes, pycodestyle and Ned Batchelder’s McCabe script. You can use Flake8 as a way to lint your code and enforce PEP8 compliance.


Installation

Installing Flake8 is pretty easy when you use pip. If you’d like to install flake8 to your default Python location, you can do so with the following command:

python -m pip install flake8

Now that Flake8 is installed, let’s learn how to use it!


Getting Started

The next step is to use Flake8 on your code base. Let’s write up a small piece of code to run Flake8 against.

Put the following code into a file named hello.py:

from tkinter import* 
class Hello:
    def__init__(self, parent):
        self.master = parent
        parent.title("Hello Tkinter") 
        self.label = Label(parent, text="Hello there")self.label.pack() 
        self.close_button = Button(parent, text="Close",
                                   command=parent.quit)self.close_button.pack() 
    def greet(self):
        print("Greetings!") 
root = Tk()
my_gui = Hello(root)
root.mainloop()

Here you write a small GUI application using Python’s tkinter library. A lot of tkinter code on the internet uses the from tkinter import * pattern, which is something that you should normally avoid. The reason being that you don’t know everything you are importing and you could accidentally overwrite an import with your own variable name.

Let’s run Flake8 against this code example.

Open up your terminal and run the following command:

flake8 hello.py

You should see the following output:


tkkkk.py:1:1: F403 'from tkinter import *' used; unable to detect undefined names
tkkkk.py:3:1: E302 expected 2 blank lines, found 1
tkkkk.py:8:22: F405 'Label' may be undefined, or defined from star imports: tkinter
tkkkk.py:11:29: F405 'Button' may be undefined, or defined from star imports: tkinter
tkkkk.py:18:1: E305 expected 2 blank lines after class or function definition, found 1
tkkkk.py:18:8: F405 'Tk' may be undefined, or defined from star imports: tkinter
tkkkk.py:20:16: W292 no newline at end of file

The items that start with “F” are PyFlake error codes and point out potential errors in your code. The other errors are from pycodestyle. You should check out those two links to see the full error code listings and what they mean.

You can also run Flake8 against a directory of files rather than one file at a time.

If you want to limit what types of errors you want to catch, you can do something like the following:

flake8 --select E123 my_project_dir

This will only show the E123 error for any files that have them in the specified directory and ignore all other types of errors.

For a full listing of the command line arguments you can use with Flake8, check out their documentation.

Finally, Flake8 allows you to change its configuration. For example, your company might only adhere to parts of PEP8, so you don’t want Flake8 to flag things that your company doesn’t care about. Flake8 also supports using plugins.


Wrapping Up

Flake8 might be just the tool for you to use to help keep your code clean and free of errors. If you use a continuous integration system, like TravisCI or Jenkins, you can combine Flake8 with Black to automatically format your code and flag errors.

This is definitely a tool worth checking out and it’s a lot less noisy than PyLint. Give it a try and see what you think!


Related Reading

The post An Intro to Flake8 appeared first on The Mouse Vs. The Python.

PyCoder’s Weekly: Issue #381 (Aug. 13, 2019)

$
0
0

#381 – AUGUST 13, 2019
View in Browser »

The PyCoder’s Weekly Logo


Traditional Face Detection With Python

In this course on face detection with Python, you’ll learn about a historically important algorithm for object detection that can be successfully applied to finding the location of a human face within an image.
REAL PYTHONvideo

Three Techniques for Inverting Control, in Python

Inversion of Control, in which code delegates control using plugins, is a powerful way of modularising software. It may sound complicated, but it can be achieved in Python with very little work. This article examines three different techniques for handling IOC in Python.
DAVID SEDDON

Save 40% on Your Order at manning.com

alt

Take the time to learn something new! Manning Publications are offering 40% off everything at manning.com, including everything Pythonic. Just enter the code pycoders40 at the cart before you checkout to save →
MANNING PUBLICATIONSsponsor

NumPy 1.17.0 Drops Python 2 Support

“The 1.17.0 release contains a number of new features that should substantially improve its performance and usefulness. The Python versions supported are 3.5-3.7, note that Python 2.7 has been dropped.”
MAIL-ARCHIVE.COM

print() Function Deep Dive (17,000 Words Guide)

Learn all there is to know about the print() function in Python and discover some of its lesser-known features. Avoid common mistakes, take your “hello world” to the next level, and know when to use a better alternative.
REAL PYTHON

An Overview of the Python Tooling Landscape

An opinionated guide to tooling in Python covering pyenv, poetry, black, flake8, isort, pre-commit, pytest, coverage, tox, Azure Pipelines, sphinx, and readthedocs.
ADITHYA BALAJI

Discussions

Python Jobs

Senior Python Developer (Austin, TX)

InQuest

Backend and DataScience Engineers (London, Relocation & Visa Possible)

Citymapper Ltd

Software Engineering Lead (Houston, TX)

SimpleLegal

Software Engineer (Multiple US Locations)

Invitae

Python Software Engineer (Munich, Germany)

Stylight GmbH

Senior Software Developer (Edmonton, AB)

Levven Electronics Ltd.

Lead Data Scientist (Buffalo, NY)

Utilant LLC

Python Developer (Remote)

418 Media

More Python Jobs >>>

Articles & Tutorials

Inheritance and Composition: A Python OOP Guide

In this step-by-step tutorial, you’ll learn about inheritance and composition in Python. You’ll improve your object oriented programming skills by understanding how to use inheritance and composition and how to leverage them in their design.
REAL PYTHON

An Intro to Flake8

Flake8 is a style guide enforcement tool for Python that you can use in place of PyLint to help you find errors in your code and more closely follow PEP8. This article shows you how to get up and running with Flake8.
MIKE DRISCOLL

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

Organizing PythonPune Meetups

PythonPune is a meetup group in Pune India. This blog post is about how the author got involved in organizing the meetup and what the process looks like.
BHAVIN GANDHI

Keras for Beginners: Implementing a Convolutional Neural Network

A beginner-friendly guide on using Keras to implement a simple Convolutional Neural Network (CNN) in Python.
VICTOR ZHOU

What Every Developer Should Learn Early On

“These are a few of the things I wish they were teaching at university instead of pure theory.”
RYLAND GOLDSTEIN

Making an Interactive Projected Surface With Python + OpenCV

“Computer vision + music = life-sized rhythm games”
TSUKURU.CLUB

Projects & Code

austin: Frame Stack Sampler for CPython

“The most interesting use of Austin is probably in conjunction with FlameGraph to profile Python applications while they are running, without the need of instrumentation. This means that Austin can be used on production code with little or even no impact on performance.”
GITHUB.COM/P403N1X87

LibCST: Concrete Syntax Tree Parser and Serializer Library

Parses Python 3.7 source code as a CST tree that keeps all formatting details (comments, whitespaces, parentheses, etc). It’s useful for building automated refactoring (codemod) applications and linters.
GITHUB.COM/INSTAGRAM

Events

PyBay

August 15 to August 19, 2019
PYBAY.COM

PyCon Korea 2019

August 15 to August 19, 2019
PYCON.KR

Kiwi PyCon X

August 23 to August 26, 2019
PYTHON.NZ

IndyPy Web Conf 2019

August 23 to August 24, 2019
INDYPY.ORG


Happy Pythoning!
This was PyCoder’s Weekly Issue #381.
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 ]

Viewing all 22875 articles
Browse latest View live


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