Skip to content

Latest commit

 

History

History
394 lines (351 loc) · 6.93 KB

python_noob_to_professional.md

File metadata and controls

394 lines (351 loc) · 6.93 KB

Reference

Arguments Defaults

Arguments Defaults is defined when the function is defined not called

Bad Code

def bad_append(n, l=[]):
    l.append(n)
    return l 


l1 = bad_append(0) # [0]
l2 = bad_append(1) # [0, 1] oops 

Professional Code

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

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

manually calling close on a file

Bad Code

def write_to_file(filename, content):
    f = open(filename, 'w')
    f.write(content)
    f.close()

if this f.write()call throws an exception, the file will never be closed

Professional Code

def write_to_file(filename, content):
    with open(filename) as f:
        f.write(content)

Using a bare except

Bad Code

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')

bare except will catch CTRL+C

Professional Code

def bare_except():
    while True:
        try:
            s = input('input a number: ')
            x = int(s)
            break
        except ValueError: 
            print('Not a number, try again')

Caret and exponentiation

y = x ^ p # bitwise XOR
y = x ** p # Exponentiation

Comprehensions

Bad Code

def never_using_comprehensions():
    squares = {}
    for i in range(10):
        squares[i] = i * i 

Professional Code

def using_comprehensions():
    dict_comp = {i: i * i for i in range(10)}
    list_comp = [i * i for i in range(10)]
    set_comp = {i * i for i in range(10)}
    gen_comp = (i * i for i in range(10))
    
    print(dict_comp)
    print(list_comp)
    print(set_comp)
    print(gen_comp)
    
    for i in gen_comp:
        print(i)


####
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# {0, 1, 64, 4, 36, 9, 16, 49, 81, 25}
# <generator object <genexpr> at 0x7f8c30cc0270>
# 0
# 1
# 4
# 9
# 16
# 25
# 36
# 49
# 64
# 81
####

Checking Type Equality

  • noob code use ==
def checking_type_equality():
    chlid_obj = child_class(1, 2)

    if type(p) == parent:
        print('child')
    else: 
        print('not a child')

Professional Code use isinstance()

def checking_type_equality():
    chlid_obj = child_class(1, 2)

    if isinstance(chlid_obj, parent_class):
        print('child')
    else: 
        print('not a child')

Checking Non, True or False

Bad Code use ==

if x == None:
    print('none')

if x == True:
    print('True')

if x == False:
    print('False')

Professional Code use is

if x is None:
    print('none')

if x is True:
    print('True')

if x is False:
    print('False')
  • checks identity not equality

using if bool() or if len(x)

Bad Code

if bool(x):
    return "it's boolean"
if len(y) != 0:
    return "not empty"

Professional Code

if x:
    return "it's boolean"
 if y:
    return "not empty"
  • the same result but using if bool() or if len() just shows that you don't know the language that well

Type Hints & Annotations

x: int = 1 
x: list[int] = []
x = list[int]()
  • Multiple return
def multiple_return() -> Union[str, bool]:
    return 'done', True
from typing import Any
def write_to_file(filename: str, data: str) -> Any:
    try:
        with open(filename, 'a') as file:
            file.write(data)
            return 'done'

    except FileNotFoundError as Error:
        print(Error)
        return Error

Iteration

Bad Code

def range_len_pattern():
    a = [1, 2, 3]
    for i in range(len(a)):
        v = a[i]

Professional Code

def iterate_on_items():
    a = [1, 2, 3]
    for item in a:
        v = item

if you still need the indexes to use

def use_enumerate():
    a = [1, 2, 3]
    for index, value in enumerate(a):
        v = value
        i = index

if you want to use i as a syncronizing varialbe to get corresponding items

  • Noob
def use_enumerate():
    a = [1, 2, 3]
    b = [4, 5, 6]
    for i in range(len(b)):
        aValue = a[i]
        bValue = b[i]
  • Professional code use zip(list, list)
def use_enumerate():
    a = [1, 2, 3]
    b = [4, 5, 6]
    for aValue, bValue in zip(a, b):
        pass
  • if you still need the index use enumerate(zip(list, list))
def use_enumerate():
    a = [1, 2, 3]
    b = [4, 5, 6]
    for index, (aValue, bValue) in enumerate(zip(a, b)):
        pass

looping over the dictionary keys

Bad Code

def for_key_in_dict_keys():
    d = {'a': 1, 'b': 2, 'c': 3}
    for key in d.keys(): 
        pass

Professional Code

  • the default iterate on the key
def for_key_in_dict_keys():
    d = {'a': 1, 'b': 2, 'c': 3}
    for key in d:
        pass

Tuple unpacking

Bad Code

mytuple = (1, 2)
x = mytuple[0]
y = mytuple[1]

Professional Code

mytuple = (1, 2)
x, y = mytuple

index counter variable

Bad Code

l = [1, 2, 3]
i = 0
for i in l:
    i += 1
    pass

Professional Code

l = [1, 2, 3]
for index, value in enumerate(l):
    pass

using time.time to time

Bad Code

def execution_time(func: Callable):
    start = time.time()
    func()
    end = time.time()
    print(end - start)
execution_time(do_something)

Professional Code

def real_execution_time(func: Callable):
    start = time.perf_counter()
    func()
    end = time.perf_counter()
    print(end - start)



real_execution_time(so_something)

Using shell=True in subprocess module

Bad Code

    import subprocess
    result = subprocess.run(['ls -l'], capture_output=True, shell=True)
    print(result.stdout.decode('utf-8'))
  • shell=True is a source of a lot of security problems
  • people did this to add command arguments like -l but you can add the command and it's arguments in a list

Professional Code

import subprocess
result = subprocess.run(['ls', '-l'], capture_output=True)
print(result.stdout.decode('utf-8'))

Using from module import *

Bad Code

from requests import *
  • it litters your namespace with variables, Just import the things you actually need

Professional Code

from requests import get, post

pep8

Bad Code

def not_following_pep8():
    x = (1, 2)
    y=5
    l = [1,2,3]

    def func(x = 5):
        pass

Professional Code

def following_pep8():
    x = 1, 2
    y = 5
    l = [1, 2, 3]

    def func(x=5):
        pass

Using Python2

  • use python3 instead