On Youtube, Raymond Hettinger (python core developper) explains common mistakes and correct writing in python Video I found? v = OSGv2VnC0go), so I will summarize it. In the video, I mainly use python2 as an example (because it is a 2013 video), but here I converted it to python3 as much as possible. Now that it may already be written in an old way, please use it while checking it as appropriate.
Loop
--Use iterator as much as possible
Bad example
for i in [0, 1, 2, 3, 4, 5]:
  print(i**2)
Put the entire list in memory. ↓
Good example
for i in range(6):
  print(i**2)
Since range is generated one by one as an iterator, memory is not wasted.
In python2,
rangeis a list andxrangeis an itertor In python3,rangeis iterator (name ofxrangein python2 has changed)
Bad example
colors = ['red', 'green', 'blue', 'yellow']
for i in range(len(colors)):
  print(colors[i])
↓
Good example
colors = ['red', 'green', 'blue', 'yellow']
for color in colors:
  print(color)
Writing below is faster
Bad example
colors = ['red', 'green', 'blue', 'yellow']
for i in range(len(colors)-1, -1, -1):
  print(colors[i])
↓
Good example
colors = ['red', 'green', 'blue', 'yellow']
for color in reversed(colors):
  print(color)
Bad example
colors = ['red', 'green', 'blue', 'yellow']
for i in range(len(colors)):
  print(i, '--->', colors[i])
↓
Good example
colors = ['red', 'green', 'blue', 'yellow']
for i, color in enumerate(colors):
  print(i, '--->', color)
Bad example
names = ['raymond', 'rachel', 'matthew']
colors = ['red', 'green', 'blue', 'yellow']
n = min(len(names), len(colors))
for i in range(n):
  print(names[i], '--->'. colors[i]
↓
Good example
names = ['raymond', 'rachel', 'matthew']
colors = ['red', 'green', 'blue', 'yellow']
for name, color in zip(names, colors):
  print(name, '--->', color)
When iterators of different lengths are entered in the zip, they will be aligned to the shorter one. ʻItertools.zip_longest` to align to the longer one
In python2,
zipproduces a list (ʻizipis an iterator), In python3zip` generates iterator
Bad example
colors = ['red', 'green', 'blue', 'yellow']
def compare_length(c1, c2):
  if len(c1) < len(c2):
    return -1
  elif len(c1) > len(c2):
    return 1
  else:
    return 0
print(sorted(colors, cmp=compare_length)
↓
Good example
colors = ['red', 'green', 'blue', 'yellow']
print(sorted(colors, key=len))
** Is sorting by key sufficient? ** ** In some cases it is not enough, but in most cases it is okay. (SQL does a lot of sorting, but sorts by key)
Bad example
blocks = []
while True:
  block = f.read(32)
  if block == '':
    break
  blocks.append(block)
↓
Good example
blocks = []
for block in iter(functool.partial(f.read, 32), ''):
  blocks.append(block)
partial is unpleasant, but the merit of being able to handle it as an iterator is great It is better to avoid sentinel value
Bad example
def find(seq, target):
  found = False
  for i, value in enumerate(seq):
    if value == target:
      found = True
      break
  if not found:
    return -1
  return i
Example when you have to use a flag (found)
↓
Good example
def find(seq, target):
  for i, value in enumerate(seq):
    if value == target:
      break
  else:
    return -1
  return i
If there is no break in for, the else statement is executed. He regrets that he should have named it
nobreakinstead of else.
Dictionary
d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}
for k in d:
  print(k)
↑ Something strange happens when you make changes to the dictionary
d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}
for k in d.keys():
  if k.startswith('r'):
    del d[k]
↑ d.keys () makes a copy of the list in advance, so you can change the dictionary
Bad example
d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}
for k in d:
  print(k, '--->', d[k])
↓
Good example
d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}
for k, v in d.items():
  print(k, '--->', v)
names = ['raymond', 'rachel', 'matthew']
colors = ['red', 'green', 'blue']
d = dict(zip(names, colors))
Inefficient method
colors = ['red', 'green', 'red', 'blue', 'green', 'red']
d = {}
for color in colors:
  if color in d:
    d[color] = 0
  d[color] += 1
↓
The right way
d = {}
for color in colors:
  d[color] = d.get(color, 0) + 1
↓
Recent method
d = defaultdict(int)
for color in colors:
  d[color] += 1
Bad example
names = ['raymond', 'raychel', 'matthew', 'roger', 'betty', 'melisa', 'judith', 'charlie']
d = {}
for name in names:
  key = len(name)
  if key not in d:
    d[key] = []
  d[key].append(name)
↓
The right way
d = {}
for name in names:
  key = len(name)
  d.setdefault(key, []).append(name)
↓
Recent method
d = defaultdict(list)
for name in names:
  key = len(name)
  d[key].append(name)
getdoes not assign to the dictionary.setdefaultsubstitutes
Bad example
defaults = {'color': 'red', 'user': 'guest'}
parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user')
parser.add_argument('-c', '--color')
namespace = parser.parse_args([])
command_line_args = {k: v for k, v in vars(namespace).items() if v}
d = defaults.copy()
d.update(os.environ)
d.update(command_line_args)
A large number of dictionaries are copied ↓
Good example
d = collections.ChainMap(command_line_args, os.environ, defaults)
Keep the original dictionary as it is without copying
Bad example
twitter_search('@obama', False, 20, True)
I don't understand the meaning of the argument ↓
Good example
twitter_search('@obama', retweets=False, numtweets=20, popular=True)
NamedTuple
Bad example
> doctest.testmod()
(0, 4)
I don't understand the meaning of 0,4 ↓
Good example
> doctest.testmod()
TestResults(failed=0, attempted=4)
TestResults is
TestResults = namedtuple('TestResults', ['failed', 'attempted'])
Can be made with
Bad example
p = 'Raymond', 'Hettinger', 0x30, '[email protected]'
fname = p[0]
lname = p[1]
age = p[2]
email = p[3]
↓
Good example
fname, lname, age, email = p
Bad example
def fibonacci(n):
  x = 0
  y = 1
  for i in range(n):
    print(x)
    t = y
    y = x + y
    x = t
There is a moment when the state collapses during execution. Easy to get the line order wrong ↓
Good example
def fibonacci(n):
  x, y = 0, 1
  for i in range(n):
    print(x)
    x, y = y, x+y
This is closer to human thinking.
Bad example
names = ['raymond', 'raychel', 'matthew', 'roger', 'betty', 'melisa', 'judith', 'charlie']
s = names[0]
for name in names[1:]:
  s += ', ' + name
↓
Good example
', '.join(names)
Bad example
names = ['raymond', 'raychel', 'matthew', 'roger', 'betty', 'melisa', 'judith', 'charlie']
del names[0]
names.pop(0)
names.insert(0, 'mark')
slow ↓
Good example
names = deque(['raymond', 'raychel', 'matthew', 'roger', 'betty', 'melisa', 'judith', 'charlie'])
del names[0]
names.popleft()
names.appendleft('mark')
fast
--Separate business logic and administrative logic --The code is clean ――If you don't name it correctly, it will be a mess.
Bad example
def web_lookup(url, saved={}):
  if url in saved:
    return saved[url]
  page = urlib.urlopen(url).read()
  saved[url] = page
  return page
↓
Good example
@lru_cache()
def web_lookup(url):
  return urllib.urlopen(url).read()
Business logic and administrative logic are separated
Bad example
oldcontext = getcontext().copy()
getcontext().prec = 50
print(Decimal(355) / Decimal(113))
setcontext(oldcontext)
↓
Good example
with localcontext(Context(prec=50)):
  print(Decimal(355) / Decimal(113))
Bad example
f = open('data.txt')
try:
  data = f.read()
finally:
  f.close()
↓
Good example
with open('data.txt') as f:
  data = f.read()
Bad example
lock = threading.Lock()
lock.acquire()
try:
  print('Critical section 1')
  print('Critical section 2')
finally:
  lock.release()
↓
Good example
lock = threading.Lock()
with lock:
  print('Critical section 1')
  print('Critical section 2')
Bad example
try:
  os.remove('somefile.tmp')
except OSError:
  pass
↓
Good example
with ignored(OSError):
  os.remove('somefile.tmp')
Bad example
with open('help.txt', 'w') as f:
  oldstdout = sys.stdout
  sys.stdout = f
  try:
    help(pow)
  finally:
    sys.stdout = oldstdout
↓
Good example
with open('help.txt', 'w') as f:
  with redirect_stdout(f):
    help(pow)
Bad example
result = []
for i in range(10):
  s = i**2
  result.append(a)
print(sum(result))
↓
Good example
print(sum([i**2 for i in range(10)])
↓
Good example
print(sum(i**2 for i in range(10)))
        Recommended Posts