Everything I know about Python...

Learn to Write Pythonic Code!

Check out the book Writing Idiomatic Python!

Looking for Python Tutoring? Remote and local (NYC) slots still available! Email me at jeff@jeffknupp.com for more info.

A Common Misunderstanding About Python Generators

I received the following email a few days ago:


It seems that you know about iterators. Maybe you can explain some weird behavior. If you run the code below you will find that the function is treated differently just because it has a 'yield' in it somewhere, even if it's completely unreachable.

def func():
    print("> Why doesn't this line print?")
    exit() # Within this function, nothing should matter after this point.  The program should exit
    yield "> The exit line above will exit ONLY if you comment out this line."

x = func()

When I run the code, I get the following output from the print() call: <generator object func at 0x10e968a50>.

So what's going on here? Why doesn't that line in func() print? Even if yield is completely unreachable, it seems to affect the way the function executes.

Read on →

Counting Cards With Python

Having grown up about 20 minutes from Atlantic City, I'm no stranger to casinos. When I was younger (but over 21! cough) I learned to count cards, a tool used by Blackjack players to help them gain a statistical edge over the casino and thus, in a perfect world, win money over the long term. It appealed to me mainly for the allure of beating the casino at its own game (literally). While every other game in the casino has a negative expected value over the long term, the card counter really can beat the house (I'll outline card counting in more detail below).

Something just happened in New Jersey that rekindled my interest in counting: a casino offering Blackjack with live dealers online.

Read on →

Python is the fastest growing programming language due to a feature you've never heard of

According to a recent StackOverflow analysis Python is the fastest growing programming language of those already in wide use. What's more, the growth rate is accelerating, and has been consistently for the past few years. While the specific conclusions of the StackOverflow post should probably be taken with a grain of salt, there's no denying the fact that Python use has exploded over the past five years. That's great news for people who have long used and enjoyed the language, but it's still important to ask why Python usage has exploded. And the primary, if not sole facilitator of this growth is a feature of the language you've probably never even heard of.

Read on →

Improve Your Python: Python Classes and Object Oriented Programming

Note: Each day this week I'm going to republish one of my most popular posts. My hope is that people who missed them the first time might find them useful now. This post, on "classes" and Object Oriented Programming remains my most popular post of all time. I've gotten hundreds of emails about this post alone. Many have found it an accessible introduction to classes and OOP, both in Python and in general.

The class is a fundamental building block in Python. It is the underpinning for not only many popular programs and libraries, but the Python standard library as well. Understanding what classes are, when to use them, and how they can be useful is essential, and the goal of this article. In the process, we'll explore what the term Object-Oriented Programming means and how it ties together with Python classes.

Read on →

How Python Linters Will Save Your Large Python Project

A Python project I'm working on at Enigma is starting to grow rather large. I spent a good deal of effort yesterday getting a five line change added to our Makefile (which is run as part of our CI and CD pipeline on every pull request and merge). After the PR was merged, I gloated to others how awesome my team's project was. Here are the five lines:

    pylint --rcfile=.pylintrc api -f parseable -r n && \
    mypy --silent-imports api && \
    pycodestyle api --max-line-length=120 && \
    pydocstyle api

For completeness sake, here is the test target that actually gets run as part of CI tests:

test: install lint
    python3 setup.py test --addopts="--cov=api"
    coverage xml -i -o coverage/cobertura-coverage.xml --omit=$(VIRTUAL_ENV)/*,.eggs/*

(So, for those not versed in "Makefile-ese", the test target won't run successfully if the lint target doesn't do so first).

Why was I happy enough to be a jerk to other engineers and brag about those five lines? It all comes down to complexity.

Read on →

Web Analytics