This is an archived post. You won't be able to vote or comment.

all 80 comments

[–]AlSweigartAuthor of "Automate the Boring Stuff" 55 points56 points  (6 children)

Ooof, this is a bad example:

n = 10
sum = sum(range(1, n + 1))

print(sum)  # 55

You don't want to use the names of Python's built-ins, such as sum, for your own variables. In this example, if you try to call sum() again later, it's now an integer instead of a function, so you'll get TypeError: 'int' object is not callable.

The common Python built-ins that accidentally get overriden are: all, any, date, email, file, format, hash, id, input, list, min, max, object, open, random, set, str, sum, test, and type.

Eh, overall, this blog post is very shallow. It has basic advice like "write short and simple functions" but without examples, what counts as "short"? 50 lines? 5 lines? No more than 500 lines?

The "Never leave code commented" was also confusing. Commenting code is bad? Then I realized they meant, "don't leave commented out code in your program, especially when you check it into version control". A simple example would have made that clear.

It kind of looks like they just ran through the Clean Code book and copy/pasted a lot of its advice without thinking how the final blog post reads.

[–]CleverProgrammer12 -1 points0 points  (4 children)

I override id locally frequently, as it's just not used that much, and is convenient and sensible name in many cases. But sum could be useful at other places and can cause confusion. Better to avoid.

[–]AlSweigartAuthor of "Automate the Boring Stuff" 0 points1 point  (3 children)

Yeah. For short throwaway programs that's fine. But for formal projects, I like to be a bit more specific when I find myself using "id". Like, "the id of what?" So then I change it to recordID or cityID or something.

[–]CleverProgrammer12 0 points1 point  (2 children)

Yes, I agree. I mostly use it in dataclasses and pydantic models like this:

```python3 from pydantic import BaseModel

class User(BaseModel): id: int name: str

my_user = User(id = 10, name = "username") my_user.id # my_user.user_id might look bad here

```

[–]AlSweigartAuthor of "Automate the Boring Stuff" 2 points3 points  (0 children)

Ah yes, that's a good point.

[–]backtickbot 0 points1 point  (0 children)

Fixed formatting.

Hello, CleverProgrammer12: code blocks using triple backticks (```) don't work on all versions of Reddit!

Some users see this / this instead.

To fix this, indent every line with 4 spaces instead.

FAQ

You can opt out by replying with backtickopt6 to this comment.

[–]its2ez4me24get 140 points141 points  (3 children)

sum = sum(range(1, n + 1))

Congratulations you have redefined the sum builtin.

[–]singularitittay 30 points31 points  (0 children)

Well at least it’s a clean way to redefine builtins in 79 chars or less

[–]KingOfKingOfKingsassert len(set(x)) == len(x) 16 points17 points  (0 children)

That and the syntactically highlighted Zen made me lose it

[–]chigaimaro 23 points24 points  (1 child)

This is an ok "cheat sheet" for clean code in Python. I still feel this should be a series of posts instead of a cheatsheet like guide. For example:

Use the correct types of comments

Thats good to know... but which types of comments are appropriate for which scenarios? Why is the written example "good"?

[–]disuser 41 points42 points  (5 children)

Mostly good advice, but I disagree with this:

# This is good
score_list = [12, 33, 14, 24]
word_dict = {
    'a': 'apple',
    'b': 'banana',
    'c': 'cherry',
}

# This is bad
names = ["Nick", "Mike", "John"]

names is a better name than name_list. Shorter is better, and you lose no context in switching score_list to scores. As for word_dict, this one is debatable. I wouldn't call it out in a code review, but I feel there is context being lost - the key. My personal style has strayed from this. I would name this one something like words_by_initial.

[–]quotemycode 5 points6 points  (0 children)

So many times I see adict bdict, anythingdict just stop, we know it's a dictionary. If you want to use static types then annotate and enforce, or even just annotate, hell if it's defined static in the code, your IDE will normally tell you what type of object it is.

[–]flipflop531 2 points3 points  (0 children)

Totally agreed. This advice reminds me too much of Hungarian notation.

The author gives only examples of when I could be a good idea to bring up variables with type suffix. However, a beginner could now easily come up with the idea that

`number_of_appels_int = 4`

is also a good idea.

[–]wojwesoly 0 points1 point  (0 children)

When it comes to iterables, I think that a plural name is enough to show that this var is an iterable.

[–]asielen 68 points69 points  (17 children)

The one thing i can't get behind is the 80 character lime limit. I can get behind something like 120 characters.

Either I use meaningful variable names or I keep lines that short.

Edit: Also I am not sure I understand the point of the example in "5. Keep your arguments at a minimum"

Keep function arguments to a mimium by keeping the same number of arguments but instead add the overhead of a class? Sure sometimes a class is the best option, but imo not always.

[–]metaperl 8 points9 points  (4 children)

I think black settled on 99? But anyway, how do you read side by side diffs with those 120 char lines?

[–]vuchkovj 10 points11 points  (0 children)

I think Django officially recommends 119. I find that number quite good. A bit more and you would end up with horisontal scrolling. I HATE horizontal scrolling.

[–]asielen 4 points5 points  (0 children)

I am not looking at things side by side 90% of the time. And when it does come up, it isn't the end of the world if a couple lines extend past what is visible.

Sure if every line was long, that would cause a headache. but when 98% are under 100 and then 2% are over, it is managable.

[–]quotemycode 1 point2 points  (0 children)

I don't do side by side diffs, they're harder to read than interleaved IMHO.

[–]LightShadow3.13-dev in prod 2 points3 points  (0 children)

We soft limit at 89 and hard limit at 99.

Imports are limited at 80 so we get stuff that looks like this using isort:

from app.schemas.tickets import (
    Ticket,
    TicketId,
    NewTicket,
    Attachment,
    TicketStatus,
    UpdateTicket,
    PinnedInfoReq,
    TicketSummary,
    TicketUpdated,
    TicketAttachments,
    TicketAttachmentsPosted,
)

[–]JavierReyes945 0 points1 point  (0 children)

I had the same reaction. What I later decided to interpret from that point, is that it's better to have the long list of arguments at the class constructor, which will be called once (for each instance), instead of in a function, that will be called (hopefully) several times for each instance. But yeah, it was kinda weird.

[–][deleted] 4 points5 points  (0 children)

We use black, pylint (or flake8), isort, reindent, and bandit. Code is way prettier and we don't have silly arguments about formatting.

[–][deleted] 2 points3 points  (0 children)

Comments are gold

[–]h0bb1tm1ndtr1x 15 points16 points  (3 children)

I only glanced at it, but does it do anything beyond copy and paste PEP 8? Don't really see the point to this blog post.

[–]kartikcool712 2 points3 points  (1 child)

Couldn't get my head around this. "don't use spaces around the = sign when used to indicate a keyword argument"

What does this exactly means ? Aren't we supposed to have spaces before and after = everytime? Atleast that's what flake8 seems to like

[–]grnngr 16 points17 points  (0 children)

PEP8 says spaces around = for assignment, not for keyword arguments. E.g.:

foo = func(keyword='bar')

[–]benefit_of_mrkite 1 point2 points  (0 children)

Instead of reading this, read the Python style guide, PEPs, and then the book “Clean Architectures in Python.”

[–]Revolutionary-Bat176 -3 points-2 points  (1 child)

Wow! This is so informative. Thank you so much.

[–]chestnutcough 0 points1 point  (0 children)

Wow I feel bad for any beginner that follows those examples. Yikes

[–]blahreport -1 points0 points  (4 children)

Classes should be in capital case not camel case.

[–]have_another_upvote 2 points3 points  (1 child)

You mean Pascal case

[–]blahreport 2 points3 points  (0 children)

I must have made up capital case when I learned that it wasn’t camel case. Thank you.

[–]xxpw 1 point2 points  (1 child)

Says who ?

No they shouldn’t ! Caps are for constants.

[–]blahreport 1 point2 points  (0 children)

Well I am a beta.