Raw strings to the rescue!

Whenever I teach Python courses, most of my students are using Windows. And thus, when it comes time to do an exercise, I inevitably end up with someone who does the following:

for one_line in open('c:\abc\def\ghi'):


The above code looks like it should work. But it almost certainly doesn’t. Why? Because backslashes (\) in Python strings are used to insert special characters. For example, \n inserts a newline, and \t inserts a tab. So when we create the above string, we think that we’re entering a simple path — but we’re actually entering a string containing ASCII 7, the alarm bell.

Experienced programmers are used to looking for \n and \t in their code.  But \a (alarm bell) and \v (vertical tab), for example, tend to surprise many of them. And if you aren’t an experienced programmer? Then you’re totally baffled why the pathname you’ve entered, and copied so precisely from Windows, results in a “file not found” error.

One way to solve this problem is by escaping the backslashes before the problematic characters.  If you want a literal “\n” in your text, then put “\\n” in your string.  By the same token, you can say “\\a” or “\\v”.  But let’s be honest; remembering which characters require a doubled backslash is a matter of time, experience, and discipline.

(And yes, you can use regular, Unix-style forward slashes on Windows.  But that is generally met by even more baffled looks than the notion of a “vertical tab.”)

You might as well double all of the backslashes — but doing that is really annoying.  Which is where “raw strings” come into play in Python.

A “raw string” is basically a “don’t do anything special with the contents” string — a what-you-see-is-what-you-get string. It’s actually not a different type of data, but rather a way to enter strings in which you want to escape all backslashes. Just preface the opening quote (or double quotes) with the “r” character, and your string will be defined with all backslashes escaped. For example, if you say:


then you’ll see




But if you say:


then you’ll see


I suggest using raw strings whenever working with pathnames on Windows; it allows you to avoid guessing which characters require escaping. I also use them whenever I’m writing regular expressions in Python, especially if I’m using \b (for word boundaries) or using backreferences to groups.

Raw strings are one of those super-simple ideas that can have big implications on the readability of your code, as well as your ability to avoid problems.  Avoid such problems; use raw strings for all of your Windows pathnames, and you’ll be able to devote your attention to fixing actual bugs in your code.

Announcing: Weekly Python Exercise

Weekly Python Exercise logoI have a great job.  Really, I’m quite fortunate: For many years, I’ve spent nearly every day helping engineers at some of the world’s largest and best companies (including Apple, Cisco, Ericsson, HP, PayPal, SanDisk, and VMWare) to become better Python developers.

My students are are experienced, intelligent engineers who are using Python in their work. Some of them are at the start of their Python journey, and others have been using the language for several years. But all of them feel that if they were just more fluent with Python, they could express themselves — and thus solve problems — more quickly and easily.

How do I help these engineers to become more fluent? The answer is simple: Practice. Lots and lots of practice.

Programming languages are like natural languages: When you’re fluent, the ideas flow out of you without having to think twice about vocabulary and syntax. When you’re speaking in your native language, you’re not thinking “third person, male, past tense.”  Rather, you just say what you’re thinking.  The same is true for programming languages; at a certain point, you don’t have to think about how to create a dispatch table with functions and a dictionary.  You just do it.

The only way to really learn a new natural language is through practice. You’ll make mistakes along the way, but those are an important part of the learning process. Over time, and with repeated practice, you’ll slowly but surely internalize the language’s structure. You’ll become fluent, able to express your ideas naturally and effortlessly.

Weekly Python Exercise is designed to help you gain that fluency, over time, through regular and repeated practice. Every Tuesday, I’ll send you a new Python exercise.  I want you to struggle with it, but not too much; my hope is that the exercises will never take more than 30 minutes to solve. As you work through the exercise, and then as you review the solution and explanation that I send each Friday, you’ll be growing and improving as a Python programmer. You’ll be gaining understanding and knowledge that will make you more efficient and confident.

Moreover, you’ll find yourself spending far less time on Stack Overflow. I’m a big fan of Stack Overflow, but going there too often interrupts your flow, impedes your productivity, and adds to your frustration.

  • If you use Python on a regular basis, but feel like you’re consulting Stack Overflow a bit too frequently, then these exercises are for you.
  • If you’re getting your work done in Python, but think that your code could look more “Pythonic,” then these exercises are for you.
  • If you want to feel more comfortable with the standard library and well-known packages on PyPI, then these exercises are for you.
  • If you want to explore more advanced aspects of Python, be they functional programming techniques, objects, generators, decorators, or async code, then these exercises are for you.

Weekly Python Exercise is a subscription service: You can purchase it using PayPal or a credit card (with more options coming soon). You can pay each month, or at a reduced rate with an annual subscription. You can also buy a subscription for your team at work, ensuring that all of you will become more fluent and effective.

Along with your subscription, you’ll have free access to a private forum in which we’ll discuss the exercises (and answers). I’ve even set up a special forum area for people interested in pair programming with one another to find a solution.

I’m proud and excited to be launching Weekly Python Exercise.  But I’ll be doubly proud and excited to know that I’m helping developers around the world, not just those who participate in my courses, to become more fluent and effective Python developers.

Any questions?  Just e-mail me.  Otherwise, sign up, and start getting more fluent in Python!

Click here to subscribe to Weekly Python Exercise!

Boolean indexing in NumPy and Pandas: A free e-mail course for aspiring data scientists

NumPyFor nearly two years, I have been teaching my introductory course in data science and machine learning to companies around the world. On the one hand, participants are excited by data science, and all of the potential that it has to change our world. On the other hand, there is a lot to learn in order to be effective — a mix of theory and practice. While Python’s tools reduce the learning curve, you still end up having to learn about NumPy, Pandas, Matplotlib, scikit-learn, and a variety of other tools, such as the Jupyter notebook.

One of the things that most surprises and frustrates my students is the notion of “boolean indexing.” If you want to retrieve all of the odd elements from a NumPy array, you don’t use a “for” loop or even a list comprehension. Rather, you use a boolean index, as follows:


In order to cut down on the confusion, and help people to understand and use this powerful tool, I have created a free, 15-part e-mail course.  Each day, you’ll be introduced to another aspect of boolean indexing.  In every lesson, I give exercises, to help you practice what you’ve learned, and internalize the ideas.  By the end, you’ll know how to work with data in NumPy and Pandas (both series and data frames).

The course is 100% free, and a new lesson arrives in your e-mail inbox every day. So if you, or a colleague of yours, has been frustrated trying to understand how boolean indexing works, this is your chance!  The more fluently you can use these tools, the better you can be as a data scientist. Which, I would argue, is better for the world.

Sign up here: 

2+2 might be 4, but what is True+True?

In Python, we know that we can add two integers together:

>> 2 + 2

And of course, we can add two strings together:

>> 'a' + 'b'

We can even add two lists together:

>> [1,2,3] + [4,5,6]
[1, 2, 3, 4, 5, 6]

But what happens when you add two booleans together?

>> True + True

Huh?  What’s going on here?

This would seem to be the result of several different things going on.

First of all, booleans in Python are actually equal to 1 and 0. We know that in a boolean context (i.e., in an “if” statement or “while” loop), 1 is considered to be True, and 0 is considered to be False. But then again, 10, 100, and ‘abc’ are also considered to be True, while the empty string is considered to be False. All values are turned into booleans (using __nonzero__ in Python 2, and __bool__ in Python 3) when they’re in a place that requires a boolean value.

But whereas 10 and the empty string are turned into True and False (respectively) in a boolean context, 1 and 0 are special. True and False are really equal to 1 and 0, as we can see here:

>> True == 1
>>> True == 10
>>> False == 0
>>> False == ''

So, it would seem that while it’s preferable to use True and False, rather than 1 and 0, the difference is a semantic one, for programmers.  Behind the scenes, they’re really numbers.

But how can that be?  Why in the world would Python consider two objects of completely different types to have equal values?

The answer is that in Python, the “bool” type is actually a subclass of “int”, as we can see here:

>> bool.__bases__
(<class 'int'>,)

So while it’s still a bit weird for two values with different types to be considered equal, it’s not totally weird, given that booleans are basically a specialized form of integers.   And indeed, if we look at the documentation for booleans, we find that it implements very few methods of its own; most are inherited from int.  One of the many inherited operators is __eq__, the method that determines whether two objects are equal. Which means that when we’re comparing 1 and True, we’re really just comparing 1 (of type int) and 1 (of type bool, a subclass of int, which means that it behaves like an int).

This, then, explains what’s going on: When we say “True + True”, the int.__add__ operator is called. It gets two instances of bool, each with a value of 1, and which know how to behave as if they were regular ints. So we get 2 back.

Just for kicks, what happens if we say

True += 1

in Python 3, we get an error, saying that we can’t assign to a keyword. That’s because in Python 3, True and False are true keywords, rather than names defined in the “builtins” namespace. But in Python 2, they’re just built-in names. Which means that this is what happens in Python 2:

>>> True += 1
>>> True
>>> type(True)
<type 'int'>

Look at what we did: Not only did we add True + 1, but we then assigned this integer back to True! Which means that True is no longer an instance of “bool” in the “builtins” namespace, but rather an integer.

How did this happen? Because of Python’s scoping rules, known as “LEGB” for local-enclosing-globals-builtins.  When we assigned to True with +=, we didn’t change the value of True in builtins. Rather, we created a new global variable. The builtin value is still there, but because the global namespace gets priority, its value (2) masks the actual value (True, or 1) in the builtins namespace.

Indeed, look at this:

>>> True += 1
>>> True == __builtins__.True

How can we get out of this situation? By embracing nihilism, deleting truth (i.e., the True name we’ve defined in the global namespace).  Once we’ve done that, True in the builtins namespace will still exist:

>>> del(True)
>>> True

I’d like to think that none of us will ever be doing mathematical operations with booleans, or trying to assign to them. But understanding how these things work does provide a clearer picture of Python scoping rules, which govern how everything else in the language functions.

What other weird boolean/integer behavior have you noticed? I’m always curious to find, and then understand, these somewhat dark (and useless) aspects of Python!

Unfamiliar with Python scoping rules, or just want to brush up on them? Take my free, five-part “Python variable scoping” e-mail course: http://lerner.co.il/e-mail-courses/variable-scoping-in-python/

Python function brain transplants

What happens when we define a function in Python?

The “def” keyword does two things: It creates a function object, and then assigns a variable (our function name) to that function object.  So when I say:

def foo():
      return "I'm foo!"

Python creates a new function object.  Inside of that object, we can see the bytecodes, the arity (i.e., number of parameters), and a bunch of other stuff having to do with our function.

Most of those things are located inside of the function object’s __code__ attribute.  Indeed, looking through __code__ is a great way to learn how Python functions work.  The arity of our function “foo”, for example, is available via foo.__code__.co_argcount.  And the byte codes are in foo.__code__.co_code.

The individual attributes of the __code__ object are read-only.  But the __code__ attribute itself isn’t!  We can thus be a bit mischievous, and perform a brain transplant on our function:

def foo():
      return "I'm foo!"

def bar():
      return "I'm bar!"

foo.__code__ = bar.__code__

Now, when we run foo(), we’re actually running the code that was defined for “bar”, and we get:

"I'm in bar!"

This is not likely to be something you want to put in your actual programs, but it does demonstrate some of the power of the __code__ object, and how much it can tell us about our functions.  Indeed, I’ve found over the last few years that exploring the __code__ object can be quite interesting!

The five-minute guide to setting up a Jupyter notebook server

JupyterNearly every day, I teach a course in Python.  And nearly every day, I thus use the Jupyter notebook: I do my live-coding demos in it, answer students’ questions using it, and also send it to my students at the end of the day, so that they can review my code without having to type furiously or take pictures of my screen.

I also encourage my students to install the notebook — not just so that they can open the file I send them at the end of each day, but also so that they can learn to experiment, iterate, and play with their code using a modern interactive environment.

My two-day class in regular expressions uses Python, but as a means to an end: I teach the barest essentials of Python in an hour or so, just so that we can read from files and search inside of them using regular expressions.  For this class, it’s overkill to ask the participants to install Python, especially if they plan to use other languages in their work.

When I teach this class, then, I set up a server that is only used for my course. Students can all log into the Jupyter notebook, create and use their own notebook files, and avoid installing anything new on their own computers.

Moreover, this whole setup now takes me just a few minutes. And since the class lasts only two days, I’m paying a few dollars for the use of a server that doesn’t contain any valuable data on it. So if someone happens to break into the server or ruin it, or if one of my students happens to mess around with things, nothing from my own day-to-day work will be ruined or at risk.

How do I do this? It’s pretty simple, actually:

  • Create a new server.  I use Digital Ocean, because they’re cheap and easy to set up. When I teach a class in Israel or Europe, I use one of their European data centers (or should I say “centres”), because it’ll be a bit faster.  If a large number of students will participate, then I might get a server with a lot of RAM, but I normally get one of the most basic DO plans.  I normally set up an Ubuntu server, but you’re welcome ot use any version of Linux you want.
  • I log in as root, and add a bunch of packages, starting with “python-pip”.  (Note that this assumes you’re willing to use Python 2.  I don’t really care which version I use for this class; when Ubuntu switches to Python 3, I’ll gladly use that instead.) This ensures that the Python “pip” program is installed, allowing me to install Python packages:
apt-get install unzip emacs wget curl python-pip
  • I then use “pip” to install the “ipython[notebook]” package, which in turn downloads and installs everything else I’ll need:
pip install -U 'ipython[notebook]'   # yes, you need the quotes
  • Next, I create a “student” user.  It is under this user that I’ll run the notebook.
  • As the “student” user, I start the notebook with the “–generate-config” option. This creates a configuration directory (~/student/.jupyter) with a configuration file (jupyter_notebook_config.py) inside of it:
jupyter notebook --generate-config
  • Open the jupyter_notebook_config.py file, which is (as the suffix indicates) a Python file, defining a number of variables.  You’ll need to set a few of these in order for things to work; from my experience, changing four lines is sufficient:
    c.NotebookApp.open_browser = False    # no browser needed on a server
    c.NotebookApp.ip = ''          # listen on the network
    NotebookApp.password = u''            # don't require a password
    c.NotebookApp.token = ''              # don't require a security token


  • These final two instructions, to remove password protection and the security token, are debatable.  On the one hand, my server will exist for two days at most, and won’t have any important data on it.  On the other hand, you could argue that I’ve provided a new entry point for bad people in the world to attack the rest of the Internet.
  • Once that’s done, go back to the Unix shell, and launch the notebook using “nohup”, so that even if/when you log out, the server will still keep running:
    nohup jupyter notebook

    Once this is done, your server should be ready!  If you’re at the IP address, then you should at this point be able to point your browser to, and you’ll see the Jupyter notebook.  You can, of course, change the port that’s being used; I’ve found that when working from a cafe, non-standard ports can sometimes be blocked. Do remember that low-numbered ports, such as 80, can only be used by root, so you’ll need something higher, such as 8000 or 8080.

Also note that working this way means that all users have identical permissions. This means that in theory, one student can delete, change, or otherwise cause problems in another student’s notebook.  In practice, I’ve never found this to be a problem.

A bigger problem is that the notebook’s back end can sometimes fail. In such cases, you’ll need to ssh back into the server and restart the Jupyter notebook process. It’s frustrating, but relatively rare.  By using “nohup”, I’ve been able to avoid the server going down whenever my ssh connection died and/or I logged out.

I’ve definitely found that using the Jupyter notebook has improved my teaching.  Having my students use it in my courses has also improved their learning!   And as you can see, setting it up is a quick operation, requiring no more than a few minutes just before class starts.  Just don’t forget to shut down the server when you’re done, or you’ll end up paying for a server you don’t need.

Comprehensive documentation for setting up a Jupyter server, including security considerations, are at the (excellent) Jupyter documentation site.

Suggestions for how to improve these instructions are quite welcome, of course!

A short Python class puzzle

PuzzleHere’s a short Python puzzle that I use in many of my on-site courses, which I have found to be useful and instructive: Given the following short snippet of Python, which letters will be printed, and in which order?

class Person(object):
    def __init__(self, name):
        self.name = name

p1 = Person('name1')
p2 = Person('name2')

Think about this for a little bit before looking at the answer, or executing it on your computer.

Let’s start with the answer, then:


Let’s go through these one by one, to understand what’s happening.

The initial “A” is printed because… well, because it’s the first line of the program. And in a Python program, the lines are executed in order — starting with the first, then the second, and so forth, until we reach the end.  So it shouldn’t come as a surprise that the “A” line is printed first.

But what is surprising to many people — indeed, the majority of people who take my courses — is that we next see “B” printed out.  They are almost always convinced that the “B” won’t be printed when the class is defined, but rather when… well, they’re really sure when “B” will be printed.

Part of the problem is that Python’s keywords “class” and “def” look very similar. The former defines a new class, and the latter defines a new function. And both start with a keyword, and take a block of code.  They should work the same, right?

Except that “class” and “def” actually work quite differently: The “def” keyword creates a new function, that’s true.  However, the body of the function doesn’t get executed right away. Instead, the function body is byte compiled, and we end up with a function object.

This means that so long as the function body doesn’t contain any syntax errors (including indentation errors), the function object will be created. Indeed, the following function will produce an error when run, but won’t cause a problem when being defined:

def foo():    asdfafsafasfsafavasdvadsvas

This is not at all the case for the “class” keyword, which creates a new class. And if we think about it a bit, it stands to reason that “class” cannot work this way. Consider this: Immediately after I’ve defined a class, the methods that I’ve defined are already available. This means that the “def” keyword inside of the class must have executed. And if “def” executed inside of a class, then everything else executes inside of a class, also.

Now, under most normal circumstances, you’re not going to be invoking “print” from within your class definition. Rather, you’ll be using “def” to define methods, and assignment to create class attributes. But both “def” and assignment need to execute if they are to create those methods and attributes! Their execution cannot wait until after the class is already defined.

I should also add that in Python, a class definition operates like a module: What would looks like an assignment to a global variable inside of the class definition is actually the creation of an attribute on the class (module) itself. And of course, the fact that the body of a class definition executes line by line makes it possible to use decorators such as @staticmethod and @property.

In short, “def” inside of a class definition creates a new function object, and then creates a class-level attribute with the same name as your function.

So, when you define a class, Python executes each line, in sequence, at the time of definition.  That’s why “B” is printed next.

Why is “C” not printed next? Because the body of a function isn’t executed when the function is defined. So when we define our __init__  method, “print” doesn’t run right away.  It does, however, run one time for each of the two instances of “Person” we create at the end of the program, which is why “C” is printed twice.

However, before “C”  is printed, the class definition still needs to finish running.  So we first see “D” (inside of the class definition), and then “E” (just after the class is defined).

Over the years, I’ve found that understanding what goes on inside of a class definition helps to understand many of the fundamental principles of Python, and how the language is implemented. At the same time, I’ve found that even in my advanced Python classes, a large number of developers don’t answer this puzzle correctly, which means that even if you work with Python for a long time, you might not have grasped the difference between “class” and “def”.

Data science + machine learning + Python course in Shanghai

Reuven teaching in ChinaData science is changing our lives in dramatic ways, and just about every company out there wants to take advantage of the insights that we can gain from analyzing our data — and then making predictions based on that analysis.

Python is a leading language (and some would say the leading language) for data scientists. So it shouldn’t come as a surprise that in addition to teaching intro and advanced Python courses around the world, I’m increasingly also teaching courses in how to use Python for data science and machine learning.  (Within the next few weeks, I expect to release a free e-mail course on how to use Pandas, an amazing Python library for manipulating data.   I’ve already discussed it on my mailing list, with more discussion of the subject to come in the future.)

Next month (i.e., February 2017), I’ll be teaching a three-day course in the subject in Shanghai, China.  The course will be in English (since my Chinese is not nearly good enough for giving lectures at this point), and will involve a lot of hands-on exercises, as well as lecture and discussion.  And lots of bad jokes, of course.

Here’s the advertisement (in Chinese); if you’re interested in attending, contact me or the marketing folks at Trig, the company bringing me to China:


Can’t make it to Shanghai? That’s OK; maybe I can come to your city/country to teach!  Just contact me at reuven@lerner.co.il, and we can chat about it in greater depth.

Announcing: Trainer Weekly, practical advice for technical trainers

Do you offer technical training?  Or are you just interested in becoming a trainer?

I’ve been doing technical training for several years now, and it has become the main thing that I do.  I love it, and encourage everyone to look into it as a potential career (or part of a career).

I’ve created an online Facebook group for trainers. I’m doing coaching for trainers. And most recently, I started “Trainer Weekly,” a free newsletter for people offering training. Every Monday, you’ll get a new piece of advice about th business, pedagogy, or logistics of training. How do you price things?  How do companies think about training? What sorts of courses can and should you offer?  What kinds of exercises should you give in class?

If this sounds interesting to you, then sign up for Trainer Weekly, and expect to get a new message from me every Monday.  If you have specific questions about training, then just drop me a line; I’ve already addressed a few topics that were requested by readers, and hope to address many more.

Free download: Cheat sheet for Python data structures

Get the Python data manipulations cheat sheet

Just about every day of every week, I teach Python. I teach not only in Israel, but also in Europe, China, and the US.  While I do teach newcomers to programming, the overwhelming majority of my students are experienced developers in another language — most often C, C++, Java, or C#.

For many of these people, I find that it’s hard to keep track of which data structure does what — when do you use lists vs. dicts vs. tuples vs. sets.  Moreover, it’s hard for them to remember the most common methods and operators we use on these data structures.

Perhaps the most common question I get is, “How do I add a new element to a dictionary?”  They’re often looking for an “append” method, and are surprised to find that one doesn’t exist.

That, and other questions, led me to create this  “cheat sheet for Python data structures.”  It’s not meant to be all-encompassing, but rather to provide some insights and reminders into the most common tasks you’ll want to do with lists, tuples, dicts, and sets.

My students have found this to be helpful — and I hope that it’ll be useful to other Python developers out there, as well!  Feedback is, of course, warmly welcome.

Get the Python data manipulations cheat sheet