Écrire du code de type python

Sur Youtube, Raymond Hettinger (développeur du noyau python) explique les erreurs courantes et l'écriture correcte en python Vidéo J'ai trouvé? V = OSGv2VnC0go), je vais donc le résumer. Dans la vidéo, j'utilise principalement python2 comme exemple (car c'est une vidéo de 2013), mais ici je l'ai convertie en python3 autant que possible. Maintenant qu'il a peut-être déjà été écrit d'une manière ancienne, veuillez l'utiliser tout en le vérifiant comme il convient.

Loop

Boucle simple

Mauvais exemple


for i in [0, 1, 2, 3, 4, 5]:
  print(i**2)

Mettez la liste entière en mémoire. ↓

Bon exemple


for i in range(6):
  print(i**2)

Puisque «range» est généré un par un en tant qu'itérateur, la mémoire n'est pas gaspillée.

En python2, range est une liste et xrange est un itertor En python3, range est un itérateur (le nom de xrange en python2 a changé)

Boucle de liste

Mauvais exemple


colors = ['red', 'green', 'blue', 'yellow']

for i in range(len(colors)):
  print(colors[i])

Bon exemple


colors = ['red', 'green', 'blue', 'yellow']

for color in colors:
  print(color)

Écrire ci-dessous est plus rapide

Boucle inversée

Mauvais exemple


colors = ['red', 'green', 'blue', 'yellow']

for i in range(len(colors)-1, -1, -1):
  print(colors[i])

Bon exemple


colors = ['red', 'green', 'blue', 'yellow']

for color in reversed(colors):
  print(color)

Je veux aussi avoir un index

Mauvais exemple


colors = ['red', 'green', 'blue', 'yellow']

for i in range(len(colors)):
  print(i, '--->', colors[i])

Bon exemple


colors = ['red', 'green', 'blue', 'yellow']

for i, color in enumerate(colors):
  print(i, '--->', color)

Bouclez deux listes en même temps

Mauvais exemple


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]

Bon exemple


names = ['raymond', 'rachel', 'matthew']
colors = ['red', 'green', 'blue', 'yellow']

for name, color in zip(names, colors):
  print(name, '--->', color)

Lorsque des itérateurs de différentes longueurs sont saisis dans le zip, ils seront alignés sur le plus court. ʻItertools.zip_longest` pour s'aligner sur le plus long

En python2, zip génère une liste (ʻizipest un itérateur), En python3,zip` génère un itérateur

Tri personnalisé

Mauvais exemple


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)

Bon exemple


colors = ['red', 'green', 'blue', 'yellow']

print(sorted(colors, key=len))

** Le tri par clé est-il suffisant? ** ** Dans certains cas, ce n'est pas suffisant, mais dans la plupart des cas, ce n'est pas grave. (SQL fait beaucoup de tri, mais il le fait par tri par clé)

Arrêtez la boucle avec la valeur sentinelle

Mauvais exemple


blocks = []
while True:
  block = f.read(32)
  if block == '':
    break
  blocks.append(block)

Bon exemple


blocks = []

for block in iter(functool.partial(f.read, 32), ''):
  blocks.append(block)

partiel est désagréable, mais le mérite de pouvoir le gérer comme un itérateur est grand Il vaut mieux éviter la valeur sentinelle

Quitter la boucle en fonction de la condition

Mauvais exemple


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

Exemple lorsque vous devez utiliser un drapeau (found) ↓

Bon exemple


def find(seq, target):
  for i, value in enumerate(seq):
    if value == target:
      break
  else:
    return -1
  return i

S'il n'y a pas de pause pour, l'instruction else est exécutée. Il regrette qu'il aurait dû le nommer «nobreak» au lieu d'autre.

Dictionary

Clés de dictionnaire en boucle

d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}

for k in d:
  print(k)

↑ Quelque chose d'étrange se produit lorsque vous modifiez le dictionnaire

d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}

for k in d.keys():
  if k.startswith('r'):
    del d[k]

d.keys () fait une copie de la liste à l'avance, vous pouvez donc changer le dictionnaire

Clé et valeur de la boucle

Mauvais exemple


d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}

for k in d:
  print(k, '--->', d[k])

Bon exemple


d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}

for k, v in d.items():
  print(k, '--->', v)

Créer un dictionnaire à partir d'une liste

names = ['raymond', 'rachel', 'matthew']
colors = ['red', 'green', 'blue']

d = dict(zip(names, colors))

Comptez le nombre d'occurrences dans la liste

Méthode inefficace


colors = ['red', 'green', 'red', 'blue', 'green', 'red']

d = {}
for color in colors:
  if color in d:
    d[color] = 0
  d[color] += 1

Le droit chemin


d = {}
for color in colors:
  d[color] = d.get(color, 0) + 1

Méthode récente


d = defaultdict(int)
for color in colors:
  d[color] += 1

Regrouper la liste

Mauvais exemple


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)

Le droit chemin


d = {}
for name in names:
  key = len(name)
  d.setdefault(key, []).append(name)

Méthode récente


d = defaultdict(list)
for name in names:
  key = len(name)
  d[key].append(name)

get n'affecte pas au dictionnaire. substituts de setdefault

Coller plusieurs dictionnaires ensemble

Mauvais exemple


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)

Un grand nombre de dictionnaires sont copiés ↓

Bon exemple


d = collections.ChainMap(command_line_args, os.environ, defaults)

Conservez le dictionnaire original tel quel sans le copier

Meilleure lisibilité du code

Argument de mot clé de fonction

Mauvais exemple


twitter_search('@obama', False, 20, True)

Je ne comprends pas le sens de l'argument ↓

Bon exemple


twitter_search('@obama', retweets=False, numtweets=20, popular=True)

NamedTuple

Mauvais exemple


> doctest.testmod()
(0, 4)

Je ne comprends pas la signification de 0,4 ↓

Bon exemple


> doctest.testmod()
TestResults(failed=0, attempted=4)

TestResults est

TestResults = namedtuple('TestResults', ['failed', 'attempted'])

Peut être fait avec

déballage de tuple

Mauvais exemple


p = 'Raymond', 'Hettinger', 0x30, '[email protected]'

fname = p[0]
lname = p[1]
age = p[2]
email = p[3]

Bon exemple


fname, lname, age, email = p

Mettre à jour plusieurs états en même temps

Mauvais exemple


def fibonacci(n):
  x = 0
  y = 1
  for i in range(n):
    print(x)
    t = y
    y = x + y
    x = t

Il y a un moment où l'état s'effondre pendant l'exécution. Facile de se tromper dans l'ordre des lignes ↓

Bon exemple


def fibonacci(n):
  x, y = 0, 1
  for i in range(n):
    print(x)
    x, y = y, x+y

C'est plus proche de la pensée humaine.

Efficacité (haute vitesse, économie de mémoire)

Concaténation de chaînes

Mauvais exemple


names = ['raymond', 'raychel', 'matthew', 'roger', 'betty', 'melisa', 'judith', 'charlie']

s = names[0]
for name in names[1:]:
  s += ', ' + name

Bon exemple


', '.join(names)

Mettre à jour la liste

Mauvais exemple


names = ['raymond', 'raychel', 'matthew', 'roger', 'betty', 'melisa', 'judith', 'charlie']

del names[0]
names.pop(0)
names.insert(0, 'mark')

lent ↓

Bon exemple


names = deque(['raymond', 'raychel', 'matthew', 'roger', 'betty', 'melisa', 'judith', 'charlie'])

del names[0]
names.popleft()
names.appendleft('mark')

vite

décorateur et gestionnaire de contexte

cache

Mauvais exemple


def web_lookup(url, saved={}):
  if url in saved:
    return saved[url]
  page = urlib.urlopen(url).read()
  saved[url] = page
  return page

Bon exemple


@lru_cache()
def web_lookup(url):
  return urllib.urlopen(url).read()

La logique métier et la logique administrative sont séparées

Contexte temporaire

Mauvais exemple


oldcontext = getcontext().copy()
getcontext().prec = 50
print(Decimal(355) / Decimal(113))
setcontext(oldcontext)

Bon exemple


with localcontext(Context(prec=50)):
  print(Decimal(355) / Decimal(113))

Ouverture et fermeture de fichiers

Mauvais exemple


f = open('data.txt')
try:
  data = f.read()
finally:
  f.close()

Bon exemple


with open('data.txt') as f:
  data = f.read()

Verrouillage du fil

Mauvais exemple


lock = threading.Lock()
lock.acquire()
try:
  print('Critical section 1')
  print('Critical section 2')
finally:
  lock.release()

Bon exemple


lock = threading.Lock()
with lock:
  print('Critical section 1')
  print('Critical section 2')

Ignorer l'erreur

Mauvais exemple


try:
  os.remove('somefile.tmp')
except OSError:
  pass

Bon exemple


with ignored(OSError):
  os.remove('somefile.tmp')

Remplacer temporairement la sortie standard

Mauvais exemple


with open('help.txt', 'w') as f:
  oldstdout = sys.stdout
  sys.stdout = f
  try:
    help(pow)
  finally:
    sys.stdout = oldstdout

Bon exemple


with open('help.txt', 'w') as f:
  with redirect_stdout(f):
    help(pow)

Méthode d'inclusion de liste

Mauvais exemple


result = []
for i in range(10):
  s = i**2
  result.append(a)
print(sum(result))

Bon exemple


print(sum([i**2 for i in range(10)])

Bon exemple


print(sum(i**2 for i in range(10)))

Recommended Posts

Écrire du code de type python
Ecrire l'entrée standard dans le code
Ecrire Spigot dans VS Code
Écrivez, compilez et exécutez du code sur codeanywhere.com
Ecrire le code de test du sélénium en python
Notes pour écrire du code de type Python
Écrivez le code de contrat Ethereum en utilisant Serpent
Qiita (1) Comment écrire un nom de code
Écrivez du code FizzBuzz piloté par les tests à l'aide de Python doctest.
N'est-il pas acceptable d'écrire du code de test?
Code de caractère
Mauvais code