15 bad Python habits. Did you get caught?

Hello, I'm Chen Cheng.

Today I will share 15 Python bad habits. The main reason for these bad habits is that developers are inexperienced in Python. By abandoning these habits and writing code in a python way, you can not only improve the quality of your code, but also make a good impression on those who see the code~

1. Concatenate strings with + sign

Bad practices:

def manual_str_formatting(name, subscribers):

if subscribers > 100000:
    print("Wow " + name + "! you have " + str(subscribers) + " subscribers!")
else:
    print("Lol " + name + " that's not many subs")

The adjusted method is to use f-string, and the efficiency will be higher:

def manual_str_formatting(name, subscribers):

# better
if subscribers > 100000:
    print(f"Wow {name}! you have {subscribers} subscribers!")
else:
    print(f"Lol {name} that's not many subs")

2. Use final instead of the context manager

Bad practices:

def finally_instead_of_context_manager(host, port):

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
    s.connect((host, port))
    s.sendall(b'Hello, world')
finally:
    s.close()

The adjusted method is to use the context manager. Even if an exception occurs, the socket:: will be closed

def finally_instead_of_context_manager(host, port):

# close even if exception
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((host, port))
    s.sendall(b'Hello, world')

3. Try closing the file manually

Bad practices:

def manually_calling_close_on_a_file(filename):

f = open(filename, "w")
f.write("hello!\n")
f.close()

The adjusted method is to use the context manager. Even if an exception occurs, the file will be closed automatically. If there is a context manager, you should first use:

def manually_calling_close_on_a_file(filename):

with open(filename) as f:
    f.write("hello!\n")
# close automatic, even if exception

4. Nothing is written after except

Bad practices:

def bare_except():

while True:
    try:
        s = input("Input a number: ")
        x = int(s)
        break
    except:  # oops! can't CTRL-C to exit
        print("Not a number, try again")

This will catch all exceptions, so that the program will not terminate after pressing CTRL-C. the adjusted method is

def bare_except():

while True:
    try:
        s = input("Input a number: ")
        x = int(s)
        break
    except Exception:  # Better than this is to use ValueError
        print("Not a number, try again")

5. Function arguments use mutable objects

If the function parameters use mutable objects, the next call may produce unexpected results, which is a bad practice

def mutable_default_arguments():

def append(n, l=[]):
    l.append(n)
    return l
l1 = append(0)  # [0]
l2 = append(1)  # [0, 1]

The adjusted approach is as follows:

def mutable_default_arguments():

def append(n, l=None):
    if l is None:
        l = []
    l.append(n)
    return l

l1 = append(0)  # [0]
l2 = append(1)  # [1]

6. Never use derivation

Bad practice

squares = {}
for i in range(10):

squares[i] = i * i

Adjusted approach

odd_squares = {i: i * i for i in range(10)}

7. Addiction for derivation

Although the derivation is easy to use, it can not sacrifice readability and bad practice

c = [

sum(a[n * i + k] * b[n * k + j] for k in range(n))
for i in range(n)
for j in range(n)

]

The adjusted approach is as follows:

c = []
for i in range(n):

for j in range(n):
    ij_entry = sum(a[n * i + k] * b[n * k + j] for k in range(n))
    c.append(ij_entry)

8. Use = = to judge whether it is a single case

Bad practice

def equality_for_singletons(x):

if x == None:
    pass
if x == True:
    pass

if x == False:
    pass

The adjusted approach is as follows:

def equality_for_singletons(x):

# better
if x is None:
    pass
if x is True:
    pass
if x is False:
    pass

9. Use a C-like style for loop

Bad practice

def range_len_pattern():

a = [1, 2, 3]
for i in range(len(a)):
    v = a[i]
    ...
b = [4, 5, 6]
for i in range(len(b)):
    av = a[i]
    bv = b[i]

    ...

The adjusted approach is as follows:

def range_len_pattern():

a = [1, 2, 3]
# instead
for v in a:
    ...
# or if you wanted the index
for i, v in enumerate(a):
    ...
# instead use zip
for av, bv in zip(a, b):
    ...

10. Not practical dict.items

Bad practice

def not_using_dict_items():

d = {"a": 1, "b": 2, "c": 3}
for key in d:
    val = d[key]
    ...

The adjusted approach is as follows:

def not_using_dict_items():

d = {"a": 1, "b": 2, "c": 3}
for key, val in d.items():
    ...

11. Use time Time() counts the elapsed time

Bad practice

def timing_with_time():

start = time.time()
time.sleep(1)
end = time.time()
print(end - start)

The adjusted approach is to use time perf_ Counter (), more accurate:

def timing_with_time():
# more accurate

start = time.perf_counter()
time.sleep(1)
end = time.perf_counter()
print(end - start)

12. Use print instead of logging for logging

Bad practice

def print_vs_logging():

print("debug info")
print("just some info")
print("bad error")

The adjusted approach is as follows:

def print_vs_logging():

# versus
# in main
level = logging.DEBUG
fmt = '[%(levelname)s] %(asctime)s - %(message)s'
logging.basicConfig(level=level, format=fmt)
# wherever
logging.debug("debug info")
logging.info("just some info")
logging.error("uh oh :(")

13. shell=True when calling external commands

Bad practice

subprocess.run(["ls -l"], capture_output=True, shell=True)

If shell=True, passing ls -l to / bin/sh(shell) instead of ls program on Unix will cause subprocess to generate an intermediate shell process. In other words, using an intermediate shell means that variables, glob mode and other special shell functions in the command string will be preprocessed before the command runs. For example, $HOME will be processed before the echo command is executed.

The adjusted method is to refuse execution from the shell, as follows:

subprocess.run(["ls", "-l"], capture_output=True)

14. Never try to use numpy

Bad practice

def not_using_numpy_pandas():

x = list(range(100))
y = list(range(100))
s = [a + b for a, b in zip(x, y)]

The adjusted approach is as follows:

import numpy as np
def not_using_numpy_pandas():

# Faster performance
x = np.arange(100)
y = np.arange(100)
s = x + y

15. Like import*

The adjusted approach is as follows:

from itertools import *
count()

In this case, no one knows that there are many variables in this script. It is better to:

from mypackage.nearby_module import awesome_function
def main():
awesome_function()
if name == '__main__':

main()

The above are some tips I summarized. That's the end

If you have any other supplementary or different opinions, you are welcome to discuss in the comments or send me a private letter~

Keywords: Python

Added by Shock_CNOP on Mon, 13 Dec 2021 10:08:40 +0200