Skip to content

Instantly share code, notes, and snippets.

@bachloxo
Forked from JohnStuartRutledge/python_idioms.md
Last active November 7, 2022 14:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bachloxo/32234c787f8b09ec89faff58d4db8d2b to your computer and use it in GitHub Desktop.
Save bachloxo/32234c787f8b09ec89faff58d4db8d2b to your computer and use it in GitHub Desktop.
A gist for tracking examples of idiomatic Python. The goal is to accrue a list of concrete examples to help develop an intuition of what constitutes "Pythonic" code.

This page is designed to give you a list of concrete examples demonstrating idiomatic (Pythonic) code.

Many of the examples were taken from the following resources:

Summary

Python philosophically distinguishes itself from other programming languages by it's particularly strong emphasis on readability –code that conforms itself to known best practices/standards.

Within the Python community, well written code is said to be "Pythonic" if it adheres to the Python philosophy. People who have mastered coding in a Pythonic way are known as "Pythonistas."

The most canonical example of the tenets that distinguish un-Pythonic from Pythonic code can be found in Tim Peters famous poem, "The Zen of Python." To read it you need only open a Python prompt on your command line, and type the words, "import this."

The Zen of Python

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly. / Đẹp còn hơn xấu.
Explicit is better than implicit. / Rõ ràng tốt hơn là ngầm hiểu.
Simple is better than complex. / Đơn gi tốt hơn là phức hợp.
Complex is better than complicated. /  Phức hợp là tốt hơn phức tạp.
Flat is better than nested. / Phẳng là tốt hơn lồng vào nhau.
Sparse is better than dense. / Thưa thớt tốt hơn dày đặc.
Readability counts. / Số lượng khả năng đọc.
Special cases aren't special enough to break the rules. / Các trường hợp đặc biệt không đủ đặc biệt để phá vỡ các quy tắc.
Although practicality beats purity. / Mặc dù tính thực tế đánh bại sự thuần khiết.
Errors should never pass silently. / Những sai sót không bao giờ nên trôi qua một cách âm thầm.
Unless explicitly silenced. / Trừ khi im lặng rõ ràng.
In the face of ambiguity, refuse the temptation to guess. / Khi đối mặt với sự mơ hồ, hãy từ chối sự cám dỗ của sự phỏng đoán 
There should be one-- and preferably only one --obvious way to do it. / Nên có một-- và tốt nhất là chỉ có một - cách thức đơn giản để làm điều đó.
Although that way may not be obvious at first unless you're Dutch. / Mặc dù cách đó có thể không rõ ràng lúc đầu trừ khi bạn là người Hà Lan.
Now is better than never. / Bây giờ tốt hơn là không bao giờ
Although never is often better than *right* now.
If the implementation is hard to explain, it's a **BAD** idea.
If the implementation is easy to explain, it may be a **GOOD** idea.
Namespaces are one honking great idea -- let's do more of those!

The two lines most relevant to this page are

  • Readability counts
  • There should be one-- and preferably only one -- obvious way to do it

Idioms

Name Formatting

Indicate seperate words in variable names using underscores

my_variable_name = True

Indicate seperate words in function names using underscores

def my_function_name():
    pass

Indicate seperate words in class names using CamelCase / Chỉ ra các từ riêng biệt trong tên lớp bằng CamelCase

class MyClassName(object):
    pass

Prefix a single underscore to class members/functions meant for internal use only / Bắt đầu một dấu gạch dưới duy nhất cho các thành viên / chức năng của lớp chỉ dành cho mục đích sử dụng nội bộ

class MyClassName(object):
    def _internal_function(self):
        pass

Use all caps to indicate constants / Sử dụng tất cả các chữ hoa để biểu thị các hằng số

class ConnectDB(object):
    DB = "mysql",
    USER = "Steve",
    PASS = "fzHx$"
    def __init__(self):
       pass

List of GOOD and BAD Examples

Use 4 spaces per indentation level / Sử dụng 4 dấu cách cho mỗi mức thụt lề

BAD

if x is True:
  print(x)

GOOD

if x is True:
    print(x)

Limit the length of your lines to 79 characters in width / Giới hạn chiều dài dòng của bạn ở 79 ký tự chiều rộng

BAD

def my_function(a, b, c):
    my_str = "a, b, and c contains the following values {0}, {1}, {2}".format(a, b, c)

GOOD

def my_function(a, b, c):
    my_str = "a, b, and c contains the following values {0}, {1}, {2}".format(
        a, b, c)

Create readable multi-line text with the use of parentheses / Tạo văn bản nhiều dòng có thể đọc được bằng cách sử dụng dấu ngoặc đơn

BAD

big_string = """This is the first line in the text \
this is the second line in the text \
this is the third line in the text"""

GOOD

big_string = (
    "This is the first line in the text "
    "this is the second line in the text "
    "this is the third line in the text"
    )

In general, try to only import one module per line / Nói chung, hãy cố gắng chỉ nhập một mô-đun trên mỗi dòng

BAD

import sys, os, requests

GOOD

import os
import sys
import requests

Avoid using a temporary variable when swapping two variables / Tránh sử dụng một biến tạm thời khi hoán đổi hai biến

BAD

c = a
a = b
b = c

GOOD

a, b = b, a

Use tuples to unpack data / Sử dụng bộ giá trị để lấy dữ liệu

BAD

li = [1, 2, 3]
a = li[0]
b = li[1]
c = li[2]

GOOD

li = [1, 2, 3]
(a, b, c) = li

Use ''.join() on an empty string to concatonate a collection of strings / Sử dụng '' .join () trên một chuỗi trống để nối một tập hợp các chuỗi

BAD

li = ['a', 'b', 'c']
result = ''
for x in li:
    result += x

GOOD

li = ['a', 'b', 'c']
result = ''.join(li)

Use dict.get() to return a default value from a dictionary / Sử dụng dict.get () để trả về giá trị mặc định từ dictionary

BAD

x = None
if 'item' in my_dict:
    x = my_dict['item']
else:
    x = 'fallback value'

GOOD

x = my_dict.get('item', 'fallback value')

Open files using using the with statement / Mở tệp bằng câu lệnh with

BAD

f = open(path_to_file)
for line in f.readlines():
    # do something...
f.close()

GOOD

with open(path_to_file) as f:
    for line in f:
        # do something...
# no need to call close()

Avoid repeating a variable within a compound if statement / Tránh lặp lại một biến trong câu lệnh if ghép

BAD

if name=='Tom' or name=='Sam' or name=='Ron':
    pass

GOOD

if name in ('Tom', 'Sam', 'Ron'):
    pass

Don't place conditional code on the same line as the colon / Không đặt mã có điều kiện trên cùng một dòng với dấu hai chấm

BAD

if item: print(item)

GOOD

if item:
    print(item)

Avoid putting multiple statements on a single line / Tránh đặt nhiều câu lệnh trên một dòng

BAD

if condition: my_function(); my_other_function();

GOOD

if condition:
    my_function()
    my_other_function()

Use list comprehensions to create lists that are subsets of existing data / Sử dụng khả năng hiểu danh sách để tạo danh sách là tập hợp con của dữ liệu hiện có

BAD

l1 = range(1, 100)
l2 = []
for x in l1:
    if is_prime(x):
        l2.append(x)

GOOD

l1 = range(1, 100)
l2 = [x for x in l1 if is_prime(x)]

Use the 'in' keyword to iterate over an Iterable / Sử dụng từ khóa 'in' để lặp lại một Lặp lại

BAD

li = ['a', 'b', 'c']
index = 0
while index < len(li):
    print(li[index])
    index += 1

GOOD

li = ['a', 'b', 'c']
for element in li:
    print(element)

Use the 'enumerate' built-in function to keep count on an Iterable / Sử dụng hàm tích hợp 'liệt kê' để tiếp tục đếm trên một Lặp lại

BAD

li = ['a', 'b', 'c']
index = 0
for item in li:
    print(index, item)
    index += 1

GOOD

for index, item in enumerate(li):
    print(index, item)

Create a length-N list composed of the same specific item / Tạo một danh sách dài-N bao gồm cùng một mục cụ thể

BAD

four_nones = []
for x in range(1,5):
    four_nones.append(None)

GOOD

four_nones = [None] * 4

Create a length-N list composed of empty lists / Tạo một danh sách dài-N bao gồm các danh sách trống

BAD

li = []
for _ in range(1, 5):
    li.append([])

GOOD

li = [[] for _ in range(4)]

Use isinstance() to do object type comparisons / Sử dụng isinstance () để so sánh loại đối tượng

BAD

x = 5
if type(x) is type(1):
    print('x is an int')

GOOD

x = 5
if isinstance(x, int):
    print('x is an int')

For strings, lists, and tuples, use the fact that empty sequences are false / Đối với chuỗi, danh sách và bộ giá trị, hãy sử dụng thực tế là các chuỗi trống là sai

BAD

x = []
if not len(x):
    print('x is false')

GOOD

x = []
if not x:
    print('x is false')

Avoid using a mutable values as a default function parameter / Tránh sử dụng các giá trị có thể thay đổi làm tham số hàm mặc định

BAD

def fn(x=[]):
    x.append(1)
    print(x)

GOOD

def fn(x=None):
    x = [] if x is None else x
    x.append(1)
    print(x)

Check that all items in a large set of items are true / Kiểm tra xem tất cả các mục trong một tập hợp lớn các mục có đúng không

BAD

if a and b and c and d and e and f and g and h:
    print('all true')

GOOD

if all([a, b, c, d, e, f, g, h]):
    print('all true')

Check if at least one item in a set of three or more items are true / Kiểm tra xem ít nhất một mục trong bộ ba mục trở lên có đúng không

BAD

if a or b or c:
    print('at least one is true')

GOOD

if any([a, b, c]):
    print('at least one is true')

Be careful how you use the is operator when checking for empty/unset variables.
Inherently falsy values like None, [], (), "", '', and 0 do not all mean the same thing.

Hãy cẩn thận cách bạn sử dụng toán tử is khi kiểm tra các biến empty/unset. Vốn dĩ các giá trị giả như Không, [], (), "", '' và 0 không phải tất cả đều có nghĩa giống nhau.

BAD

import random
x = random.choice([ None, [] ])

if x is not None:
    print(x) 
    
# if x=[] then print(x) will run

GOOD

import random
x = random.choice([ None, [] ])

if x:
    print(x)
# neither None or [] will pass the if statment

Be aware of scope. Using the same variable name for a global and local variables can lead to errors / Hãy nhận biết về phạm vi. Sử dụng cùng một tên biến cho biến cục bộ và toàn cục có thể dẫn đến lỗi

BAD

x = 1
def fn():
    print(x) 
    x = 2

fn()     # UnboundLocalError: local variable 'x' referenced before assignment
print(x) # prints 1

GOOD

# things work as expected as long as we don't locally redfine x in the function scope
x = 1
def fn():
    print(x)
    y = 2

fn()     # prints 1
print(x) # prints 1


# to modify the global variable x, you could do
x = 1
def fn():
    global x
    print(x)
    x = 2

fn()     # prints 1
print(x) # prints 2

Take advantage of extended slice notation to reverse a string / Tận dụng extended slice để đảo ngược một chuỗi

BAD

backward = ''
for c in reversed('hello'):
    backward += c

print(backward) # 'olleh'

GOOD

# the faster albiet less readable approach is
backward = 'hello'[::-1]

# the slower but more readable approach is:
backward = ''.join(reversed('hello'))

print(backward) # 'olleh'

Counting frequency

BAD

ls = ['a', 'a', 'b', 'c', 'a']
foo = {}
for x in ls:
    if x in foo:
        foo[x] += 1
    else:
        foo[x] = 1

print(foo) # {'a': 3, 'b': 1, 'c': 1}

GOOD

from collections import Counter

ls = ['a', 'a', 'b', 'c', 'a']
foo = Counter(ls)
print(foo) # Counter({'a': 3, 'b': 1, 'c': 1})

Use for..else to run some code if the break statment is never reached. / Sử dụng for..else để chạy một số mã nếu câu lệnh break không bao giờ đạt được.

BAD

# bad example here that uses a tracking variable to determine if break has run or not

GOOD

 
for f in file_list:
    if is_img(f):
        break
else: # no break encountered
    batch_process_files(file_list)

Good Practices

Add __repr__ to all your classes for more beautiful debugging

class Example:
    def __init__(self, x):
        self.x = x
    
    def __repr__(self):
        return 'Example(x={})'.format(self.x)

Misc Observations For Programming in Python

Use virtualenv - don't install python packages at the system level

Take advantage of ipython/Juptyers profiling functions like %time and %prun to profile code.

Avoid *args and **kwargs unless you need them - they make function signatures hard to read and code-completion less helpful

Incorporate a linting tool like pyflakes or pylint into your IDE.

Learn to approach unit tests as a brain-storming exercise on how best to write your application.

In general prefer smaller individual functions dedicated to doing a single thing to larger functions that do many things.

Give every function a docstring.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment