Raymond Hettinger - Beyond PEP 8 -- Best practices for beautiful intelligible code - PyCon 2015

By: PyCon 2015

2750   25   184736

Uploaded on 04/11/2015

"Speaker: Raymond Hettinger

Distillation of knowledge gained from a decade of Python consulting, Python training, code reviews, and serving as a core developer. Learn to avoid some of the hazards of the PEP 8 style guide and learn what really matters for creating beautiful intelligible code.

Slides can be found at: https://speakerdeck.com/pycon2015 and https://github.com/PyCon/2015-slides"

Comments (11):

By bbtony    2017-09-20

In every introductory python course tuples are presented as just immutable lists. However a "more accurate" way of describing tuples is if you think of them as records with no field names. When you see tuples as records then the fact that are inmutable make sense, since the order and quantity of the items matters (it remains constant). Records usually have field names and here is where namedtuples comes in handy. Also helps to clarify what the tuples wear (see https://youtu.be/wf-BqAjZb8M?t=44m45s), just 2 minutes clip. If you are thinking why don't define a class, I will tell you a couple of reasons:

1) You know before hand that the number of items won't be modified and the order matters since you are handling records. So it is a simple way of accomplishing that constraint.

2) Because they extend tuple they are inmutable too and therefore they don't store attributes per instance __dict__, field names are stored in the class so if you have tons of instances you save a lot of space.

Why creating a class if you just probably need a read-only interaction? But what about if you need some method? Then you can extend your namedtuple class and add the functionality you want. If for example you want to control the values of the fields when you are creating the namedtuple you can create your own namedtuple by overriding __new__. At that point it is worth it to take a look at https://pypi.python.org/pypi/recordclass.

Original Thread

By svennek    2017-09-20

Three... 2 is dying (and should be!)

As for resources, you can already program, so ... Browse the manual (it is quite good), look at some pythonic* style videos* , browse the giant standard library and do some stuff with it... (the last part is key)

= yes, that is a genuine keyword, that can be googled and youtubed.. * * = this is good https://www.youtube.com/watch?v=wf-BqAjZb8M

As for "2 works as good as 3", yes, if you only care about English text.

Bytes are what is on the disk, byte value 229 could be "å" (in latin1) , "ĺ" in latin2, or different things in other encodings... Only the lower 127 are "standard" (unless you are in EBCDIC on a mainframe where code 78 is "+" instead of "N")..

If you know the encoding of the bytes (i.e. what language/text type are they), you can "decode" the bytes to a string type, which is unicode glyphs (not utf8, which is also a byte encoding)... When you want to get back to bytes, you just encode it again....

I don't get it, why people find it so hard...

Original Thread

By gravypod    2017-09-20

> The first one is horrible and super un-pythonic (it even violates PEP8[1]).

I'm not really concerned with PEP. I'm concerned with if the idea being expressed is cleaner then the original. My first iteration was cleaner then the original comprehension (despite the comprehension being PEP8). It also let me see what I was really doing and I was able to turn my map and filter into a much nicer list comprehension.

Also, pointing out lambdas instead of defs is silly. It was done for an example. Most of the time you'll be operating on data structures with built in functions or supporting functions you will have written making it cleaner to use the map and filter paradigms.

    money = sum(user.get_payed_balance() for user in users if
                                           user.has_paid_bills() and 
                                           user.is_still_subscribed())
bs

    clients = sum(map(User.get_payed_balance,
                  filter(User.is_still_subscribed,
                      filter(User.has_paied_bills, users))))
I much prefer the filters to the list comprehension in this case. I'll think "User's money for user in users if user has paid their bill and subscribed". I'm going to think "Sum the get_payed_balance for every user who is_still_subscribed and who has_paid_bills" for the functional implementation. If I had complex tuple arraignments then (like the OP's post) then I agree LCs will be the better way forward. If you're dealing with objects or functional-fitting problems I prefer map and filter.

> But perhaps even more important, it doesn't even work since a map-function can only take one argument (not two).

The concept still stands. Just use `from itertools import starmap`. Starmap is like map that calls the * operator on arguments.

    >>> a = lambda a, b: 10
    >>> list(map(a, ((1, 2), (3, 4))))
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: <lambda>() missing 1 required positional argument: 'b'
    >>> list(starmap(a, ((1, 2), (3, 4))))
    [10, 10]
> Using functional programming paradigms like this often advised against in Python.

I'm not concerned with if it's "Advised against". I'm concerned with a) will someone be able to understand this better then the implementation that currently exists) and b) will I be able to come back in 10 years and tell what this is doing if need be.

You should check out this talk [1] before going around trying to use PEP8's inconsequential clauses to call something "horrible" code.

[1] - https://www.youtube.com/watch?v=wf-BqAjZb8M

Original Thread

By TremendousJudge    2017-10-14

Yes, just like that. Check out this fantastic talk on being pythonic: https://www.youtube.com/watch?v=wf-BqAjZb8M

Original Thread

By ossm1db    2017-10-20

You may be able to refute their recommendations with this video where Raymond Hettinger sympathizes. https://www.youtube.com/watch?v=wf-BqAjZb8M

Original Thread

By anonymous    2017-09-20

No, its not a bad idea. But there has to be a better way!

Why not write the modal in a HTML file, say my_modal.html and then just include it in other templates like this:

<!-- another_template.html -->

{% include 'path/to/my_modal.html' %}

If you want to pass arguments inside my_modal.html do it like this:

<!-- another_template.html -->

{% include 'path/to/my_modal.html' with var1='abc' var2='cba' %}

Original Thread

By anonymous    2017-09-20

Don't parse integers from strings manually. Python is perfectly capable of doing that for you:

>>> s = "12345"
>>> i = int(s)
>>> print(i)
12345

That already cleans up a substantial part of your code:

string = string.lstrip()
n = int(string)

for i in range(n):
  string = string.lstrip()
  array[i] = int(string)

I don't see any logic that moves around the string, so I assume you have left those pieces out. You aren't explicit about what exactly it is that separates these integers either (your code says "anything that isn't a digit"), so I'll assume instead it's whitespace-delimited.

Python can split such strings for you through one of the methods in str: split.

>>> s = "1 2\n3\t4 5"  # Notice: all kinds of whitespace here.
>>> arr = s.split()  # By default, split will split on whitespace.
>>> print(arr)
['1', '2', '3', '4', '5']

Notice that the split leaves the values as strings. That means we aren't done yet, we also have to convert each individual element into an integer as I demonstrated before.

Here, I'll use a Python feature called list comprehensions:

>>> s = "1 2\n3\t4 5"
>>> arr = [int(n) for n in s.split()]
>>> print(arr)
[1, 2, 3, 4, 5]

This is what people are talking about when they mention the "expressiveness" of Python :) This turns all of the code you've written into a one-liner. However, this assumes your data is in a string already. It seems you're reading from a file, so there's a bit more work required to get it working properly...

arr = []  # Empty list. 
with open("path/to/file.txt") as f:
    for line in f:  # Will read all lines.
        arr += [int(x) for x in line.split()]
# Use arr...

...which assumes you have multiple ints in a line. If instead you have a single int on every line, your code becomes much simpler:

with open("path/to/file.txt") as f:
    arr = [int(line) for line in f]  # Will read all lines.
# Use arr...

However, this still isn't a complete solution to your original problem... But I hope it's educational regardless. FWIW, this is how I would solve your particular problem:

with open("path/to/file.txt") as f:
    ints_of_f = (int(line) for line in f)  # A *GENERATOR*, not a *LIST*.
    n = next(ints_of_f)
    arr = [next(ints_of_f) for _ in range(n)]  # _ is a throwaway variable.

Finally, here's a great talk on how to write "beautiful, expressive" Python code.

Original Thread

By anonymous    2018-02-26

Renaming the functions to something different than first and second number should fix it.

Here's a working example:

def menu():
    print('1) Add')
    print('2) Subtract')
    print('3) Multiply')
    print('4) Divide')


def get_menu_choice():
    menu_choice = int(input('Enter the number to choose among the menu '))
    return menu_choice


def enter_a():
    a_choice = input(
        'Enter a specific Arithmetic Operator that you wish to calculate with ')
    return a_choice


def while_r():
    keep_going = input('Do you want to keep going? Enter Y/N ')
    while keep_going == 'y' or keep_going == 'Y':
        assign()


def assign():
    menu()
    menu_choice = get_menu_choice()
    a_choice = enter_a()

    if menu_choice == 1:
        add()
    elif menu_choice == 2:
        subtract()
    elif menu_choice == 3:
        multiply()
    elif menu_choice == 4:
        divide()

    while_r()


def get_first_number():
    number = int(
        input('Enter two numbers that you wish to calculate, 1st Number: '))
    return number


def get_second_number():
    number = int(input('2nd Number: '))
    return number


def add():
    first_number = get_first_number()
    second_number = get_second_number()
    print(first_number + second_number)


def subtract():
    first_number = get_first_number()
    second_number = get_second_number()
    print(first_number - second_number)


def multiply():
    first_number = get_first_number()
    second_number = get_second_number()
    print(first_number * second_number)


def divide():
    first_number = get_first_number()
    second_number = get_second_number()
    print(first_number / second_number)

Consider using a python IDE that would help you detect similar issues and ensure that your code is formatted properly. Also if you're interested, lookup pep20 and pep8 to better understand python syntax best practices.

Original Thread

By anonymous    2018-02-26

Remember PEP8 is a style *guide* not a strict set of rules. That line is spot on 80 chars, and arguably is clearest left as a single line, not artificially split to meet PEP8. I'd recommend watching Raymond Hettinger's talk [Beyond PEP 8](https://www.youtube.com/watch?v=wf-BqAjZb8M) for some background as to why PEP8 shouldn't always be followed.

Original Thread

Popular Videos 403

Submit Your Video

If you have some great dev videos to share, please fill out this form.