November 6, 2019 , bY reuven
Python

I’ve recently appeared on a whole bunch of podcasts about Python, freelancing, and even (believe it or not) learning Chinese! If you’re interested in any or all of these subjects, then you might want to catch my interviews:

  • Talk Python to Me: I spoke with Michael Kennedy (and Casey Kinsen) about freelancing in Python — and things to consider when you’re thinking of freelancing.
  • Programming Leadership: I spoke with Marcus Blankenship about why companies offer training to their employees, how they should look for training, and how best to take advantage of a course.
  • Profitable Python: I spoke with Ben McNeill about the world of Python training — how training works (for me, companies that invite me to train, and the people in my courses), how to build up an online business, and the difference between B2C vs. B2B. You can watch the video on YouTube, or listen to the audio version of the podcast!
  • Teaching Python: I spoke with Kelly Paredes and Sean Tibor about what it’s like to teach adults vs. children, and what tricks I use to help keep my students engaged. I learned quite a bit about how they teach Python to middle-school students!
  • You Can Learn Chinese: I’ve been studying Chinese for a few years, and spent some time chatting with Jared Turner about my experience, how I continue to improve, and how my Chinese studies have affected my work teaching Python. The entire episode is great, and my interview starts about halfway through.

In related news, you might know that I’ve been a co-panelist on the Freelancers Show podcast for the last few years. The entire panel (including me) recently left the show, and we’re currently discussing how/when/where we’ll restart.

I’ll be sure to post to my blog here when there are updates — but if you’re a freelancer of any level (new or experienced) who might be interested in sharing your stories with us, please contact me, so we can speak with you when we re-start in our new format.

November 4, 2019 , bY reuven
Python

Over the last year, I’ve taught in-person Python classes to companies in the US, Europe, Israel, India, and China. I’ve taught people from a variety of backgrounds, from absolute beginners to seasoned Pythonistas who want to improve their skills in new areas. And I’ve taught everything from intro Python to data science.

For all of the differences in background, jobs, courses, and education, I consistently got one request: Everyone wants to improve their skills, so that they can program in Python more fluently and easily — solving their current problems more easily, and taking on larger ones.

If this describes you — a competent and experienced Python developer who wants to know more, understand more, and do more with Python — then the new cohort of Weekly Python Exercise, starting tomorrow, is for you.

(Yes, it starts tomorrow. That means that tonight is the deadline to join. Really!)

Join the many developers from around the world who have improved their Python skills, one week at a time, with Weekly Python Exercise. Over the 15-week course, you’ll learn to work with iterators, generators, decorators, objects, and threads. You’ll improve your testing skills with “pytest”. You’ll communicate with other people in our cohort via our private forum. You’ll participate in my live office hours.

And best of all: Each week, you’ll get that much closer to Python fluency and mastery. This is great for your own personal satisfaction, of course, but will also help your career.

Also: The next advanced level cohort will start in March 2020.  So if you’re an experienced Python developer looking to improve your skills, this will be your last chance to do so for several months.  (A new basic-level cohort will be starting in January.)

If the price of WPE seems steep, maybe you qualify for one of my discounts — for pensioners/retirees, students, and anyone living outside of the world’s 30 richest countries. I want to help as many people as possible to improve their Python fluency, no matter where they live or where they are in life.

So join me tomorrow at Weekly Python Exercise, and start improving your Python tomorrow!

November 3, 2019 , bY reuven
Python

Let’s say you’re writing a Python program that asks the user to enter a number, so that you can double it:

>>> n = input("Enter a number: ")
Enter a number:

Just doubling what we get is a bad idea, though. If the user enters “123”, then we’ll get this:

>>> print(n*2)
123123

What’s going on? The “input” function always returns a string. The trailing newline character is removed, but we’re always going to get a string. If we multiply a Python string by 2, we get a new string back — a doubled version of what the user entered.

The obvious solution would be to use “int” to convert the string. For example, we could do this:

>>> print(int(n)*2)
246

But wait: What if the user enters extra whitespace on either side? That is, what if they do this:

>>> n = input("Enter a number: ")
Enter a number:         123        

You can see that there are extra space characters on either side of the ‘123’, and it becomes even clearer if we do this:

>>> print(f'"{n}"')
"       123       "
>>> print(len(n))
17

To avoid potential problems, you might want to use “str.strip”, a great method that (by default) removes all whitespace (i.e., space, tab, newline, carriage return, and vertical tab) from the edges of the string. In other words:

>>> print(int(n.strip())*2)
246

Sure enough, this will work, removing any whitespace characters from the ends of “n”. But guess what: It’s not necessary! That’s because Python’s “int” class automatically strips whitespace on any string it gets as input:

>>> int('5')
5
>>> int('   5    ')
5
>>> int('\n\n\t\t  5\t\t\v\v\t\t\n\r')
5

This is true, even though the str.isdigit/str.isnumeric/str.isdecimal methods will return “False” if you apply them to a string containing whitespace.

But be careful: If you apply “int” to the empty string, you’ll get a “TypeError” exception. And if you call “int” without any arguments, you’ll get the integer 0 back.

So save a few seconds when you convert strings to integers, and don’t bother stripping them first! You can rely on “int” to do it for you.

October 31, 2019 , bY reuven
Python

A new cohort of Weekly Python Exercise, my family of courses to improve your Python fluency, starts on November 5th.

This time, it’s an advanced-level cohort. We’ll explore topics such as iterators, generators, decorators, objects, and threads.

The course’s structure is simple:

  • Every Tuesday, you get a new question, along with “pytest” tests to check yourself
  • On the following Monday, you get the solution and explanation
  • In between, you can discuss your solutions (and problems) with others in your cohort, on our private forum
  • I also hold live video office hours, where you can ask me questions about the exercises

Questions or comments? Or perhaps you’re eligible for one of my discounts? Read more at http://WeeklyPythonExercise.com/, or send me e-mail at reuven@lerner.co.il.

But don’t delay, because November 5th is coming up soon. And why miss out on improving your Python knowledge and fluency?

October 28, 2019 , bY reuven
Python

My native language is English: I grew up speaking it at home and school, and it’s my preference when reading, writing, and speaking. I studied in US schools through 12 grade, and then got both a bachelor’s degree and a PhD at American universities.  I’ve been writing for years, including 20 years as a columnist at Linux Journal.

Am I fluent in English? Yes, I’d say so.  And yet, I’m always reading tidbits about the history of English, how to speak more clearly, and how sharpen the language I use when writing.

Why? Because fluency isn’t a video game, in which you get a flashing sign saying, “Achievement unlocked: You’re fluent!”  No matter how fluent you currently are, there are ideas, techniques, and practices that you can still learn. You can always become better. 

How do you improve your fluency? The best way, of course, is practice. No matter how fluent you already are, more practice is always good.  As the old saying goes, the best way to become a good writer is to write. And the best way to become a better speaker is to speak.  And so forth.

What’s true for English, and other languages, is true for programming languages, as well.  If you want to be a better Python programmer, then you should be writing Python code, making mistakes, and learning from those mistakes.  Better yet, you should be discussing your mistakes (and techniques) with others, so that you can compare ideas and techniques, and learn from your peers.

This is the thinking that has driven my work with Weekly Python Exercise. Each of the six WPE courses is designed to help you become a more fluent programmer.

A new advanced-level cohort is starting on November 5th. But tomorrow (Tuesday, October 29th) is the last day you can sign up for the early-bird price of $80.

Here’s what some people have said about previous cohorts of WPE, when asked what they thought:

  • I was a total python noob when I started.  I just wanted to learn the syntax, how to look at problems and find the solution. You provided both… your teaching is instrumental in drilling some concepts into our brains.
  • I learned a lot of features of the language and had a fun time doing it. I also got to apply what I learned when programming for work.
  • I expected to see Python in real world examples. I am not disappointed, because during WPE there were many these examples with wide varieties of programming blueprints.
  • The exercises are perfect for me because they are right in my “wheelhouse”. I have enough background knowledge that the context of the problems is relevant in my experience, yet I can’t just rattle off the solutions instantly.

If you use Python on a regular basis, but still feel that you can learn more about advanced techniques: Iterators, generators, decorators, comprehensions, inner functions, threading, and useful PyPI packages, then Weekly Python Exercise is for you.

Early-bird pricing ends on Tuesday evening. After that, you can still sign up, but you’ll pay the full price (i.e., $100).  Why delay?

Click here to learn more about Weekly Python Exercise, and become a better Python developer.

October 23, 2019 , bY reuven
Python

Most days, I’m on-site at companies around the world, teaching various Python courses. And by far, the most common question that I get from students is: Once the course is over, how can I keep improving my Python skills?

The answer is simple: Practice. Just as you have to practice using a language in order to become fluent, you must keep using and practicing Python to become more proficient and efficient.

Weekly Python Exercise is a family of 15-week courses, each of which gives you a chance to improve your Python skills. On November 5th, I’ll be opening a new advanced-level cohort, aimed at people with at least 6 months of day-to-day Python experience.

During the course, you’ll improve your understanding of iterators, generators, decorators, threads, functional programming, and even a bunch of useful packages from PyPI.

Here’s how WPE works:

  • Every Tuesday, you receive a problem/question, along with “pytest” tests that your code should pass.
  • On the following Monday, you receive the solution code, along with explanatory text.
  • In between (as well as before and after), you can participate in our private forum, sharing code and solutions, and asking me questions.
  • Every month or two, I hold live office hours, at which you can ask me questions in real time.

Sounds simple? It is — and it should only take you about an hour every week. But by getting regular practice, your coding skills will improve, and your Python fluency will improve, too. You’ll be able to do more in less time, and will think more “Pythonically” than before.

Moreover: Join before October 29th, and you can take advantage of the early-bird pricing of $80. After that, you’ll still be able to join … but you’ll have to pay more.

Questions? Want to see some sample exercises? Or maybe you qualify for one of my many discounts? It’s all explained at http://WeeklyPythonExercise.com/ . Or just send me e-mail at reuven@lerner.co.il, and I’ll be delighted to answer.

September 23, 2019 , bY reuven
Python

As you might know, I’m a panelist on the weekly “Freelancers Show” podcast, which talks about the business of freelancing.

The good news: The same company that’s behind the Freelancers Show, Devchat.tv, is putting together a weekly podcast about Python, and I’m going to be on that, too! We’ll have a combination of discussion, interviews with interesting people in the Python community, and (friendly) debates over the current and future state of the language.

The better news: We’re looking for cohosts to participate in our panel discussion on a regular basis, say 2-4 times per month.

We’re looking for a diverse set of hosts, representing the breadth and width (and height, I guess) of the Python community — including skill levels, technical backgrounds, workplaces, and interests. You’ll also need a decent podcasting microphone. We’ll record weekly, on a day to be determined, at about 20:00 UTC for about 60-90 minutes.

If you’re talkative, articulate in English, interested in Python, able to commit to recording several times per month, and are willing to tolerate my jokes, then please be in touch, via e-mail (reuven@lerner.co.il) or Twitter (@reuvenmlerner)! We’re hoping to start in the coming month or two.

I should note that this podcast is not meant to replace the existing, and amazing, podcasts that already exist in the Python community! I listen to them (and occasionally appear on them, too), and have a lot of respect for the hosts of (for example) Talk Python to Me, Python Bytes, Python Init, and Test & Code. I hope that what we create will be complementary to their shows, and grow the Python community to an even larger degree.

Sound interesting? Let me know!

September 16, 2019 , bY reuven
Python

If you have been using Python, but don’t quite understand how and when to write and use the language’s object-oriented facilities, then I have good news and bad news:

  • Good news: The new cohort of WPE: Beginner objects starts tomorrow, and includes 15 weekly exercises about classes, objects, instances, methods, attributes, and other Python object goodies.
  • Bad news: The new cohort of WPE: Beginner objects starts tomorrow, which means that you only have until TONIGHT to join the new cohort.
  • Even worse news: I’ll only be running this version of WPE in about a year, toward the end of 2020. So if you don’t join this cohort, then you’ll have to wait quite some time.

Here’s what people have previously said about Weekly Python Exercise:

  • “What differentiates Reuven’s course from regular online reading, YouTube videos, or other self study mechanisms are context and application.”
  • “It’s totally worth it and a fantastic way to keep my Python skills sharp and learn new things in the process.”
  • “Fully recommend the course to anyone wanting to not only begin with Python, but learn it contextually and apply the learning via best practices.”

Remember, if you’re dissatisfied, then I offer a 100%, no questions asked, refund. 

So, don’t wait: Read more about Weekly Python Exercise (at https://WeeklyPythonExercise.com/). Questions or comments? Just e-mail me at reuven@lerner.co.il, or contact me on Twitter as @reuvenmlerner. I’ll answer your query right away!

September 10, 2019 , bY reuven
Python

When it comes to variables, Python has a well-known search strategy, known by the acronym “LEGB.” Whenever you mention a variable — and by “variable,” I mean a name that could be referencing data, a function, or a class — Python tries to find it in four different places: The local (function) scope, the enclosing function’s scope, the global scope, and finally in the “builtins” namespace.

Variable scoping seems both boring and annoying, but it actually explains a lot about Python’s design. It’s really worth learning about, and won’t take much of your time. Indeed, I have a free e-mail course on the subject; you’re welcome to subscribe.

But what about attributes? How does Python search for those?

(Quick aside: If you’re wondering what “attributes” are, then consider that when you say “a.b” in Python, the “a” is a variable and the “b” is the attribute “b” on “a”, not a variable. As a general rule, anything with a dot before its name is an attribute. And yes, there are exceptions to this rule, but it’s a good generalization.)

From my experience, this question seems like an odd one to many Python developers, including those who have been using the language for a while. What does it mean to “search for attributes”? Aren’t attributes attached to an object, in a (sort of) private dictionary?

The answer, of course, is both “yes” and “no.” Attributes do belong to a single object. But in many cases, when Python cannot find an attribute on one object, it’ll look on another object to find it.

Indeed, this search for attributes sits at the heart of the Python language, and explains many of the things that we’ve come to expect, such as method calls.

I’ll start from the end: Just as the acronym LEGB (local, enclosing, global, builtins) makes it easy (or easier) for us to understand and follow Python variable lookups, I use the acronym ICPO (instance, class, parent, object) to understand where Python searches for attributes. Keeping this search path in mind will help you to both read and write Python more easily.

I’ll expand the acronym here, and then go through a bunch of examples, so that you can understand it better:

  • Instance: When we ask for a.b, Python first checks: Does the object “a” have an attribute “b”? If so, then “b” is retrieved from “a”, and the search ends.
  • Class: If Python doesn’t find “b” on object “a”, then it looks for type(a).b. That is, it looks for an attribute “b” on a’s class. If it finds the attribute here, then it returns the value, and the search ends.
  • Parents: If Python doesn’t find “b” on type(a), then it looks on the parents of type(a):
    • If the class inherits directly from “object”, then there aren’t really any parents from which to inherit, and this phase is skipped.
    • If the class inherits from one class, then we check there — and on its parents, and its parents, etc.
    • If the class inherits from multiple classes, then we follow the MRO (method resolution order) of the class.
  • Object: All classes in Python inherit, directly or indirectly, from “object”, the top of our class hierarchy. As a result, searching for an attribute, if not first found elsewhere always concludes on “object”. If we cannot find an attribute on “object”, and it wasn’t found elsewhere previously, then Python raises an AttributeError exception.

I is for “instance”

Let’s start with some simple code to understand what I mean by all of this:

class Foo():
    def __init__(self, x):
        self.x = x

f = Foo(10)
print(f.x)  

In the above code, we define a class, Foo, with a single method, __init__. (We’ll return to methods in a little bit.) When we create a new instance of Foo, aka “f”, we create a new attribute on “self”, the instance.

Take note of this: Whenever we add or update an attribute on “self”, we’re doing so on the instance. In this case, it’s an instance of Foo, not the Foo class. Just as there’s a difference between an auto factory and an individual car, so too is there is a difference between the class Foo and f — and in a method, “self” points to the individual instance.

Thus, when we ask (on the final line) to see the value of “f.x”, Python goes through its ICPO search path, first asking: Is “x” an attribute on the instance, which we call “f”? Happily, the answer is “yes,” the search ends, and we get our answer of 10 returned to us.

C is for “class”

The above is probably how most people think of attributes, and attribute lookups, in Python. But things are a bit more complex than that. Let’s make our class a tiny bit more interesting:

class Foo():
    def __init__(self, x):
        self.x = x

    def x2(self):
        return self.x * 2  

f = Foo(10)
print(f.x2())  

Once again, we’ve defined a class Foo. And once again, the __init__ method will define an attribute named “x” on our new instance.

But this time around, we’re not asking for “f.x”. Rather, we’re going to execute the method “f.x2”. So Python starts off asking if the object “f” has an attribute named “x2”.

Except that the answer is “no,” because methods are class attributes. “x2” doesn’t exist on “f”; “x2” was defined on the class “Foo”. And thus, when Python cannot find “x2” on “f”, it goes to the next stop on its search, namely on f’s class — Foo.

Does Foo have an attribute “x2”? It does, a method object. That object is returned, and then the parentheses tell Python to execute it. When the method is executed, it does Python’s magic switcheroo, turning “f.x2()” into “Foo.x2(f)”, thus passing an argument to the “self” parameter. And the method runs!

What happens if I define a new attribute on “f” whose value is “x2”? By the ICPO rule, that attribute would have priority, and would effectively make calling the method impossible via the instance.

NOTE: This is not something you would normally want to do.

Let’s throw caution and sanity to the wind, and try it:

class Foo():
    def __init__(self, x):
        self.x = x

    def x2(self):
        return self.x * 2  

f = Foo(10)
f.x2 = lambda: 'Not the x2 you expected'
print(f.x2())  

When we run the above code, Python first checks on “f”, to see if it has an attribute “x2”. And the answer is “yes.” It stops searching, and returns the function that we defined with “lambda”. The function is then executed via the parentheses, and returns a string value.

Note that this hijacked version of “x2” is only available on “f”. If we were to define another, separate instance of “Foo”, on which we didn’t define an “x2” attribute, the ICPO rule would fail to find “x2” on the instance, which means it would then search on Foo (i.e., the class). Sure enough, there’s an “x2” attribute on the class “Foo”, which would be returned.

P is for “parent”

What happens, though, if the attribute isn’t found either on the instance or on the class? Let’s look at an example:

class Foo():
    def __init__(self, x):
        self.x = x
    def x2(self):
        return self.x * 2

class Bar(Foo):
    pass

b = Bar(10)
print(b.x2())

When we create b, our new instance of Bar, Python looks for __init__ on it. But there is no attribute “__init__” defined on b. So it looks on b’s class, Bar. The attribute isn’t there, either. Python then falls back to its third ICPO possibility, the parent. Bar only inherits from a single class, Foo. Sure enough, Foo.__init__ does exist — so that method attribute is retrieved, and then executes.

In other words: The ICPO rule describes how inheritance functions in Python. If we don’t find a method in a class, we look in its parent class. But inheritance works on all attributes, not just methods; it’ll work for data, as well. That’s why, if you create a class attribute, it’s available via the instances:

class Foo():
    y = 100

    def __init__(self): 
        pass

f = Foo()
print(Foo.y)
print(f.y)

When we run the above code, we see “100” printed twice: The first time, because Python asks if “y” is an attribute on Foo, and the answer is “yes.”

Wait a second: Isn’t “Foo” a class? Why is it getting searched first?

Because in Python, classes are indeed special. But they’re also objects like everything else in the language. So yes, “f” is an instance of “Foo”. But “Foo” is an instance of “type”. If we ask for “Foo.y” and the attribute “y” doesn’t exist, then the ICPO rule tells Python to look at type(Foo), which is “type”. Fortunately, in this case, that doesn’t happen, and we get the value “100” back.

Then, we ask for “f.y”; this also returns “100” — because by the ICPO rule, Python looks on the instance “f”, fails to find attribute “y”, and then goes to the class “Foo”, where it finds the (class) attribute “y”.

As always with ICPO, the first match that Python finds wins. This means that if a subclass and a parent class both have a method of the same name, the subclass’s method will execute:

 class Foo():
     def __init__(self, x):
         self.x = x

     def x2(self): 
         return self.x * 2

 class Bar(Foo):
     def x2(self):
         return self.x * 22

 b = Bar(10)
 print(b.x2())  # prints 220

In the above example, we invoke “b.x2()”:

  • Python looks for “b.x2”, and doesn’t find it.
  • Python looks for “Bar.x2”, finds it, and executes it.
  • Python does not continue searching, and thus “Foo.x2” is not executed. Which is precisely what we want, but is (in my experience) surprising to many newcomers to Python.

Find, but what about multiple inheritance? In such a case, the “P” stands for parents (plural) and not parent (singular). Python will search through each parent class, one at a time, according to the MRO (method resolution order). For example:

class A():

    def __init__(self, x):
        self.x = x
    def x2(self):
        return self.x * 2

class B():

    def __init__(self, y):
        self.y = y
    def y2(self):
        return self.y * 2

class C(A, B):
      pass

In the above code, class C inherits from both A and B. If we ask for its MRO, we’ll find that it first looks on itself (as usual), then A, then B, and then (finally) object. This means that if we say:

c = C(10)
print(vars(c))

The above will show that c has a single attribute, “x”, whose value is 10. That’s because when we created “c”, Python looked for c.__init__. It kept following the ICPO rule until it found the first parent class, A, where __init__ was defined. That method ran, but B’s __init__ didn’t. This means that “c” doesn’t have the “y” attribute. And thus, if we write:

print(c.y2())

We’ll get an error — not an indication that the method is missing, because the “y2” method is indeed found, by searching “c”, then the class “C”, then its parent “A”, and then finally its parent “B”. And indeed, we find the “y2” method there!

So what’s the problem? The “y2” method expects the object (self, aka our instance “c”) to have an attribute “y”. But because only A.__init__ ran, and not B.__init__, there is no “y” attribute, and we get an error.

The error is obviously not something we want, but it is the natural result of the ICPO rule.

O is for “object”

The final location in which Python looks for an attribute is “object,” the top of our object hierarchy. In Python 2, you had to explicitly inherit from “object” to avoid having an old-style class, which worked just like modern classes… until it didn’t. Nowadays, we don’t have to worry about this; all classes automatically inherit from “object”, whether you state this expressly or not.

“object” doesn’t actually have a lot defined on it. There are some methods that are used as defaults, such as “__init__” (which does nothing, and fires if you don’t provide an “__init__” method on your class) and “__str__” (which ensures that all objects can be cast into strings). In many cases, you’ll want to implement — and thus override — these default methods, so that your objects can be initialized appropriately, as well as be cast as strings in the right way.

Why should I care?

You’ve read pretty far down in a long blog post — so I hope that you care! But if you got to this point and aren’t yet convinced of the importance of this rule, consider:

  • Every time you invoke a method, Python uses the ICPO rule to find it. In other words: Inheritance in Python is a directly outgrowth of the ICPO rule.
  • The fact that everything in Python, including classes, are objects, means that everything follows the same rules. The ICPO rule applies to your instances and classes, but also to built-in instances and classes. Python is nothing if not consistent, and your objects fit into this consistent hierarchy.
  • It’s common for people coming from other languages to talk about “instance variables” and “class variables.” Abandoning those terms in favor of “attributes,” along with the ICPO rule, will help you to understand how Python works, and why it is (or isn’t) finding the data you asked for.

At the end of the day, the entire object system in Python boils down to a few rules and systems. An important part of this system is the ICPO rule. Once you’ve internalized it, many things that previously seemed odd about Python will (I believe) be more straightforward and consistent.

So, let me know: Does this make things easier to understand? What does this not explain? Leave a comment here, and I’ll try to respond and/or update the article!

September 9, 2019 , bY reuven
Python

I’ve found that many Python developers are confused by object-oriented programming in the language:

  • Newcomers to programming are confused by object-oriented ideas and terminology, while
  • Veteran programmers are surprised and confused by how Python objects work

No matter which camp you’re in, I have good news for you: Weekly Python Exercise will be starting a new cohort on September 17th, and it’s all about object-oriented programming in Python. Join me as we learn by doing, solving problems with objects, instances, classes, attributes, class attributes, and inheritance.

By the end of the course, you’ll understand how objects work, and will know how to use them in your own projects.

Join me and other Python developers from around the world in this upcoming cohort. To sign up, see samples, or learn more, just go to https://WeeklyPythonExercise.com/ . See you on the 17th!