Conseils à consulter avant de commencer à écrire Python

Je suis tombé sur différents points en utilisant Python, mais voici quelques conseils que j'aurais dû connaître avant de commencer à écrire afin d'éviter de tels pièges et d'avoir une vie Python confortable.

À propos de Python 2 et 3

Il existe 2 séries et 3 séries en Python, et la série 3 a des changements qui affectent la compatibilité descendante. Autrement dit, le code Python3 peut ne pas fonctionner dans Python2 (et vice versa).

Python3 a amélioré divers points dans Python2, et si vous l'utilisez à partir de maintenant, c'est essentiellement fait avec la dernière version de Python3 (également ci-dessous, j'ai spécifié ce qui sera amélioré avec Python3). Mieux encore, Python2 est fin du support au 1er janvier 2020. Il n'y a donc aucune raison d'utiliser Python 2 à partir de maintenant. Ceux qui utilisent encore Python 2 sont renvoyés par les élèves du primaire.

Cependant, il existe certains packages qui ne sont pas encore compatibles avec Python3, et que vous puissiez ou non atteindre un tel package dans votre propre projet est un tournant dans votre destin. Vous pouvez vérifier l'état du support dans une liste à partir de ici. Cependant, je pense que la plupart des packages sont déjà pris en charge ou peuvent être exécutés avec Python3 [Il existe également une conversion automatique de 2 à 3](http://docs.python.jp/2/library/2to3. html). Au contraire, s'il ne supporte pas Python3, on peut dire que l'état de maintenance doit être mis en doute. Google App Engine est également enfin compatible avec Python 3 dans la deuxième génération. Même OpenAI, un institut de recherche de premier plan sur l'intelligence artificielle, est passé à Python 3, donc ceux qui disent que "l'apprentissage automatique n'est pas encore ..." ne sont pas au moins avancés. Étant humain, vous n'avez pas à vous fier à ce que vous dites.

Configuration de Python

Lors du développement de Python, il est presque essentiel d'installer pip et virtualenv en plus de Python lui-même, voici donc un résumé de la configuration de Python, pip et virtualenv dans chaque environnement.

Si vous voulez faire du machine learning

Je pense qu'il y a de nombreuses raisons pour lesquelles je veux faire de l'apprentissage automatique comme raison de choisir Python, donc je vais d'abord présenter la méthode pour cela. Pour créer un environnement d'apprentissage automatique, nous vous recommandons d'utiliser Miniconda, qu'il s'agisse de Mac / Linux / Windows.

Miniconda

La méthode d'installation est celle indiquée sur la page ci-dessus. Miniconda a une fonction pour créer un environnement (environnement virtuel) pour chaque application, et il est facile d'installer des packages liés à l'apprentissage automatique. De plus, cuda requis pour le GPU et mingw, qui est un environnement de build Windows, peuvent être installés. C'est possible, et il est facile d'introduire des outils autres que de simples packages. Pour TensorFlow, les outils autour du GPU seront installés en installant avec conda, et la version CPU fonctionnera à grande vitesse (Détails. tensorflow-in-anaconda /)).

Après avoir installé Miniconda, vous pouvez créer un environnement d'apprentissage automatique général tel que scikit-learn sur Jupyter Notebook avec la commande suivante.

conda create -n ml_env numpy scipy scikit-learn matplotlib jupyter
activate ml_env

Un environnement appelé ml_env est créé avec conda create, et il est activé avec ʻactivate. Pour plus de détails sur l'utilisation de la commande conda`, reportez-vous à here (elle ne démarre pas pour Windows / Powershell. Pour plus de détails, voir [section Windows] ](Https://qiita.com/icoxfog417/items/e8f97a6acad07903b5b0#windows%E3%81%AE%E5%A0%B4%E5%90%88) Référence).

L'environnement de Miniconda est également fourni dans Dockerfile, et vous pouvez facilement créer un conteneur en l'héritant avec FROM continuumio / miniconda3 etc.

Si vous souhaitez partager un environnement d'apprentissage automatique avec un conteneur Docker, ou si vous envisagez de le déployer dans un environnement PaaS tel que Heroku, nous vous recommandons d'envisager d'utiliser Docker ([Heroku prend en charge docker push avec la fonction Container Registry. [Https://devcenter.heroku.com/articles/container-registry-and-runtime).

Anaconda n'est pas recommandé comme environnement d'apprentissage automatique pour les deux raisons suivantes.

Notez que même avec Miniconda, si vous ne supprimez pas régulièrement les paquets inutilisés avec conda clean --all, vous pourrez prendre quelques G à la légère **. C'est parce que conda stocke les paquets qui ont été téléchargés une fois en tant que cache. Même les anciens packages qui ne sont pas utilisés actuellement resteront tant qu'ils ne seront pas supprimés, il est donc bon de les supprimer.

Introduction de Python

Pour Mac / Linux

Python est inclus par défaut, mais il peut ne pas correspondre à la version que vous souhaitez développer. Par conséquent, il est bon d'utiliser pyenv pour changer la version de Python utilisée pour chaque projet. Cependant, comme mentionné ci-dessus, si vous utilisez Miniconda, vous pouvez gérer la version de Python ici, vous n'avez donc pas besoin d'installer pyenv. De plus, lors de l'utilisation de Miniconda, il est préférable de ne pas installer pyenv car la commande au bâton se produit et le shell se bloque lors de l'activation de l'environnement virtuel (ʻactivate`).

Python utilisé dans chaque projet est défini dans pyenv local x.x.x. Après avoir installé un nouvel environnement Python avec pyenv, pyenv rehash est requis. Si vous ne trouvez toujours pas l'installation, essayez de redémarrer le terminal.

Pour les fenêtres

Vous pouvez l'installer normalement, mais nous vous recommandons Miniconda.

Veuillez noter qu'à partir de 2018, [ʻactivatene démarre pas encore dans PowerShell](https://github.com/conda/conda/issues/626). Si vous ne voulez pas passer àcmd à chaque fois, vous pouvez l'utiliser en installant pscondaenvs (ce qui suit est le cas de l'installation dans l'environnement global ( root`)).

conda install -n root -c pscondaenvs pscondaenvs

Introduction de la gestion de paquets (pip) / bibliothèque de construction d'environnement virtuel (virtualenv)

La gestion des packages est introduite pour installer des bibliothèques et un environnement virtuel est introduit pour isoler la version Python et les bibliothèques à utiliser pour chaque projet.

Puisque pip est installé en standard à partir de Python 3.4, il n'est pas nécessaire de l'installer séparément pour le moment. Si vous utilisez l'ancien Python, installez-le avec get_pip.py.

virtualenv peut être installé avec pip install virtualenv.

Cependant, officiellement, il est recommandé d'utiliser Pipenv qui inclut la fonction de pip / virtualenv. Avec Pipenv, comme npm dans Node.js, il est facile d'écrire des bibliothèques dépendantes en même temps que l'installation, et de séparer les bibliothèques d'installation de développement / production.

Flux de développement en Python

Le développement Python est généralement effectué par la configuration suivante.

  1. Créez un environnement virtuel pour votre projet En Python, les bibliothèques requises pour exécuter un projet ne sont pas installées globalement, mais sont généralement installées dans des environnements virtuels individuels, et les outils pour cela sont virtualenv, conda, etc.
  2. Installez les modules requis dans l'environnement virtuel Après avoir activé l'environnement virtuel, utilisez pip etc. pour installer les bibliothèques nécessaires pour le projet. Écrivez la bibliothèque installée dans un fichier afin que d'autres puissent l'installer. Au contraire, lorsque vous utilisez des outils créés par d'autres personnes, installez les bibliothèques dépendantes écrites dans le fichier.
  3. Créez et exécutez des programmes Python

Une fois réécrit en tant que commande, il a la forme suivante. Nous présenterons trois cas lors de l'utilisation du nouveau pipenv, lors de l'utilisation du pip / virtualenv conventionnel et lors de l'utilisation de conda.

Lors de l'utilisation de pipenv

Dans pipenv, il n'est pas nécessaire de demander explicitement la création d'un environnement virtuel. Si vous installez avec pipenv install, il créera un environnement virtuel et l'installera ici. Cependant, il est créé dans un chemin qui n'est pas bien compris par défaut et il est difficile de bénéficier des avantages du stockage de code dans un environnement de développement intégré tel qu'il est.

Par conséquent, il est préférable de définir PIPENV_VENV_IN_PROJECT = 1 (ou true) avant utilisation. En faisant cela, un environnement virtuel sera construit dans .venv du dossier actuel.

# 1.Créer un dossier de projet
mkdir myproject 
cd myproject

# 2.Installez les bibliothèques requises avec pipenv

pipenv install xxxx

##Bibliothèque utilisée uniquement pour le développement(Bibliothèques utilisées pour les tests, etc.)À`-dev`Mettez

pipenv install --dev xxxx

##La bibliothèque installée par pipenv est automatiquement Pipfile.Écrit pour verrouiller. Si vous souhaitez le charger et l'installer, lancez simplement pipenv install

pipenv install

# 3.Exécuter
pipenv run python xxx.py

##Si vous souhaitez démarrer le shell, utilisez pipenv shell

pipenv shell

#Lors de la suppression de l'environnement créé,

pipenv --rm

Lors de l'utilisation de pip / virtualenv

# 1.Créer un dossier de projet
mkdir myproject 
cd myproject

# 2.Création d'un environnement virtuel venv est un nom de dossier et l'environnement du projet est préparé ici
virtualenv venv 

# 3.Activez l'environnement virtuel et installez les modules requis avec pip
#Pour Windows, venv/Scripts/activate.bat De plus, si vous utilisez le shell de Git, vous pouvez le faire avec source de la même manière
#Notez que si vous n'activez pas l'environnement virtuel, il sera installé globalement, alors désactivez-le.

source venv/bin/activate

pip install xxxx

#Liste créée par pip freeze(requirements.txt)Lors de l'installation depuis
pip install -r requirements.txt

# 4.Exécuter
python xxx.py

Lors de l'utilisation de conda

# 1.Créer un environnement virtuel(quelque chose comme virtualenv)
conda create -n my_env numpy scipy

##Afficher une liste d'environnements virtuels
conda info -e

# 2.Activer l'environnement virtuel
activate my_env # Windows
source activate my_env # Max/Linux

##Installation supplémentaire dans un environnement virtuel(Lors de la spécification de la version conda install scipy=0.12.0 etc.)
conda install scikit-learn

##Installer avec pip pour les choses qui ne peuvent pas être obtenues avec conda(Support en mettant pip dans l'environnement virtuel)
conda install pip
pip install Flask

##Mise à jour des packages installés(conda lui-même est conda mise à jour conda)
conda update numpy

# 3.Exportez l'environnement construit avec conda/Lis
conda env export > environment.yml
conda env create -f environment.yml

# 4.Désactiver l'environnement virtuel
deactivate # Windows
source deactivate # Max/Linux

Voir ici pour plus de détails.

À propos de la gestion par Git

Les dossiers d'environnement virtuel ci-dessus (venv, etc.) et les fichiers .pyc doivent être exclus pour la gestion des versions. Le fichier .pyc est un fichier pour accélérer l'exécution, et une fois exécuté, un fichier est créé pour chaque fichier. Si vous mettez cela dans la gestion des versions, le fichier sera doublé, vous devez donc le supprimer (vous pouvez également ajouter l'option -B ou définir la variable d'environnement PYTHONDONTWRITEBYTECODE pour empêcher sa génération. Can (référence)). Pour les autres fichiers qui doivent être ignorés, reportez-vous à Python .gitignore.

Tips

De plus, en fonction de la bibliothèque, il y en a qui ne peuvent pas être entrés docilement avec pip install. Cela se remarque sous Windows. Dans de nombreux cas, cela peut être évité par conda install, mais si le problème persiste, prenez les mesures suivantes.

  1. Trouvez le package approprié dans Unofficial Windows Binaries for Python Extension Packages et installez-le avec pip install <file_path> (à part) Toutefois, à l'aide de wheel, les bibliothèques dépendantes peuvent être incluses dans le référentiel dans un état compilé. Cela évite que l'installation de pip ne puisse être effectuée dans l'environnement de l'autre partie lors de la distribution et du déploiement. Pour plus de détails Référence du document).
  2. Si un fichier au format exe est fourni, [Faites de votre mieux pour insérer easy_install](http://qiita.com/icoxfog417/items/c91ba9555a247e9e8979#easy_install%E3%81%AE%E3%82%A4 % E3% 83% B3% E3% 82% B9% E3% 83% 88% E3% 83% BC% E3% 83% AB) Installer.
  3. Si vous n'avez pas d'autre choix que de compiler ... Installez d'abord Visual Studio. Après cela, définissez les variables d'environnement en vous référant à ce qui suit.
  1. En dernier recours, développez dans un environnement Linux à l'aide du sous-système Windows pour Linux. Pour la méthode de configuration, reportez-vous à ici. Avec ce dernier recours, la situation «impossible» sous Windows a pratiquement disparu.

Maintenant que l'environnement de développement Python est en place, voici quelques points à garder à l'esprit lors du développement avec Python, qui est le sujet principal.

Le codage du fichier doit être déclaré (2 uniquement)

Veuillez noter que si vous n'ajoutez pas ce qui suit au début de chaque fichier, les caractères japonais seront déformés. Comme mentionné dans here, c'est une bonne idée de toujours le mettre au début du fichier.

# -*- coding: utf-8 -*-

En Python3, le codage par défaut est UTF-8, donc ce support est inutile (PEP 3120 --Utilisation de UTF-8 comme codage source par défaut. / dev / peps / pep-3120 /)).

Comme mentionné ci-dessous, s'il est supposé que Python 2/3 sera pris en charge, et si vous souhaitez bénéficier des avantages de Python 3 (en particulier l'unification Unicode), vous devez également importer les éléments suivants ([here](http: http :). //methane.hatenablog.jp/entry/2014/01/18/Python_2/3_%E4%B8%A1%E5%AF%BE%E5%BF%9C%E3%81%AE%E3%81%9F% E3% 82% 81% E3% 81% AB_% 60unicode_literals% 60_% E3% 82% 92% E4% BD% BF% E3% 81% 86% E3% 81% B9% E3% 81% 8D% E3% 81% 8B) Référence).

from __future__ import division, print_function, absolute_import, unicode_literals

Il existe un guide de codage et vous pouvez le vérifier dans l'environnement de développement intégré

Python a un guide de codage officiellement défini (PEP8) (original/ [traduction en japonais](http: //) pep8-ja.readthedocs.io/ja/latest/)), de nombreux environnements de développement intégrés permettent de vérifier en utilisant ceci.

C'est pratique car vous pouvez vérifier en détail les points tels que le trop grand nombre de sauts de ligne et la présence de caractères vides, et vous pouvez corriger les points que vous avez négligés. Au contraire, si vous ne le mettez pas depuis le début, il sera difficile de le réparer plus tard, alors mettons-le lors de la configuration de l'environnement.

Comme son nom l'indique, le package pep8 qui vérifie la conformité PEP8 n'est actuellement pas maintenu [pycodestyle](https: //). Veuillez noter qu'il s'agit de github.com/PyCQA/pycodestyle) (Le contexte est qu'il est difficile de savoir si le nom du package "pep8" est une convention ou un outil, donc Renommé Parce qu'il a été suggéré).

Si vous souhaitez ne conserver que les vérifications logiques (importations inutiles, variables inutilisées, etc.) avec pep8, pycodestyle qui vérifie pep8 et pyflakes qui effectuent des vérifications logiques sont emballés [flake8](http: //: flake8.pycqa.org/en/latest/) est recommandé. Pylint peut être vérifié de différentes manières, mais il existe de nombreuses scènes qui peuvent être ennuyeuses, et il est nécessaire de payer un coût raisonnable pour le régler à un niveau approprié.

Par conséquent, je voudrais d'abord recommander le chemin de flake8, puis passer à Pylint lorsqu'il est nécessaire d'améliorer la norme de codage.

Le cadre de test unitaire est installé en standard

Python est livré en standard avec ʻunittest` (http://docs.python.jp/2/library/unittest.html), il n'est donc pas nécessaire d'ajouter un package pour les tests unitaires.

ʻUnittest2` ressemble à un nouveau framework, mais comme il s'agit d'utiliser le framework de test unitaire pour la nouvelle version de l'ancienne version, il n'est fondamentalement pas nécessaire de l'introduire (en aparté, j'ai donné ce numéro) J'aimerais que vous arrêtiez d'utiliser le nom du package, tel que urllib2).

Les chaînes incluent des chaînes régulières et des chaînes Unicode (2 uniquement)

En Python, la chaîne de caractères normale str et la chaîne de caractères Unicode ʻunicode` sont séparées.

str = "abc" # An ordinary string
uni_str = u"abc" # A Unicode string

En interne, il n'y a pas beaucoup de problème avec str tel quel, mais lorsque des entrées externes / sorties externes telles que des applications Web sont impliquées, il est préférable de s'unifier avec unicode (lors de l'utilisation d'un framework, lequel Vous devez savoir s'il arrive ou si vous devez transmettre la valeur). En Python3, il est unifié en unicode. De plus, en Python2, il peut être unifié en ʻunicode en utilisant from future import unicode_literals`.

Le résultat de la division ne devient pas de type float (2 uniquement)

Dans le système Python2, le résultat de la division entre des entiers tels que 1/3 ne devient pas de type float.

>>> 1/3
0
>>> 3/2
1

Ceci est résolu dans Python3 (dans l'exemple ci-dessus, cela devient un résultat d'opération arithmétique normal tel que 0,333 ..., 1,5). Si vous souhaitez rendre Python2 identique à Python3, vous pouvez le résoudre en effectuant l'importation suivante au début.

from __future__ import division

De plus, il y a aussi un signe «//» en division. À première vue, cela semble être un opérateur pour faire un quotient, mais ce n'est pas le cas. Strictement parlant, l'opération par «//» est la «valeur entière maximale qui ne dépasse pas le résultat du calcul». Par exemple, si 3 est divisé par 2, ce sera 1,5 et le nombre entier maximum qui ne dépasse pas ce sera 1. C'est aussi bon qu'un quotient, mais le problème est lorsque la valeur est négative.

>>> -3 / 2
-2

Le résultat change simplement parce que le signe devient négatif. Qu'est-ce que c'est ça? Vous pourriez penser, mais s'il est négatif, l'entier maximum qui ne dépasse pas -1,5 est «-2», qui est une spécification, pas un bogue. Et cette spécification est la même en Python3. Par conséquent, si vous souhaitez calculer le quotient en toute sécurité, il est préférable de calculer de sorte que le résultat soit flottant et tronqué après la virgule décimale. Pour Python3, cela tronque simplement le résultat calculé par /.

Il existe une fonction intégrée appelée divmod qui calcule le quotient et le reste en même temps, mais soyez prudent car le" quotient "dans cette fonction est le même que le résultat du calcul de // (tant que le document dit "quotient". , Je pense que c'est un bug, mais ...).

Les spécifications d'arrondi sont des arrondis bancaires (à partir de 3)

Le processus «round», qui consiste à arrondir en Python, est l'arrondi bancaire (également appelé arrondi au nombre pair le plus proche, arrondi JIS et arrondi ISO). Plus précisément, lorsque le nombre après la virgule décimale est "0,5", il est rapproché d'un nombre pair. C'est un processus qui est effectué car si 0,5 est toujours arrondi à un plus, la valeur du total après arrondi (arrondi au supérieur) sera plus grande dans le total avant et après arrondi = il y aura un biais ( Voir Traitement des fractions de Wikipedia (https://ja.wikipedia.org/wiki/%E7%AB%AF%E6%95%B0%E5%87%A6%E7%90%86) pour plus de détails).

>>> round(3 / 2)
2
>>> round(1 / 2)
0

Puisque «1/2 = 0,5», je pense que c'est 1, mais c'est une histoire d'arrondi arithmétique, et dans le cas de l'arrondi bancaire, comme mentionné ci-dessus, il est arrondi à «même le plus proche de 0,5», c'est-à-dire à 0. Notez que ** Python2 est une arithmétique arrondie, alors soyez prudent **.

Les autres langages utilisant l'arrondi bancaire incluent C # (voir [ici](https://qiita.com/nekonenene/items/05b85048feb05a6bb9ee#%E4%B8%80%E8%A6%] Voir A7% E8% A1% A8)).

Il existe une nouvelle classe de style et une ancienne classe de style (2 uniquement)

Dans la déclaration de classe bien présentée ci-dessous, il s'agit d'une classe de style ancien.

class MyClass():
    pass

Qu'est-ce qui est différent de la classe de style ancien? Il y a beaucoup de choses, mais au moins créer avec l'ancienne classe de style n'a plus aucun mérite. Dans l'ancienne classe de style, super qui appelle la classe parente ne fonctionne pas, donc je ne sais pas à quoi sert l'héritage.

Par conséquent, la classe est déclarée comme suit.

class MyClass(object):
    pass

Cela signifie hériter de «objet». Depuis Python3, ce sera une nouvelle classe de style par défaut l'ancienne classe de style sera supprimée.

Python 3 simplifie également le processus d'appel de la classe parent. En Python2, c'était une méthode d'appel compliquée telle que super (nom de la classe enfant, self) .parent_method (), mais en Python3, elle peut être appelée normalement avec super (). Parent_method ().

Aucune classe / interface abstraite

L'héritage est possible, mais il n'existe aucun mécanisme pour forcer l'implémentation à des classes inférieures. Cependant, abc a été ajouté en standard à partir de Python 2.6, et il est devenu possible d'implémenter une pseudo classe abstraite (abc est une abréviation de classe de base abstraite).

from abc import ABCMeta

class MyABC:
    __metaclass__ = ABCMeta
    
    def describe(self):
        print("I'm abc")
    
    @abstractmethod
    def must_implements(self):
        pass

En Python3, vous pouvez utiliser metaclass lors de la création d'une classe, afin de pouvoir l'écrire plus simplement.

from abc import ABCMeta

class MyABC(metaclass=ABCMeta):
    ...

Vous pouvez également enregistrer une classe qui utilise register sous votre contrôle (sous-classe). Cependant, comme il "lui donne simplement l'apparence", tuple n'est pas réellement une classe héritée de MyABC même dans l'exemple suivant, et les méthodes réellement implémentées dans MyABC ne peuvent pas être utilisées.

MyABC.register(tuple)

assert issubclass(tuple, MyABC)
assert isinstance((), MyABC)

().describe()  # Attribute Error

Même s'il est vrai dans «cette instance», il semble déroutant d'obtenir une erreur d'attribut dans la méthode, donc je ne peux pas vraiment imaginer la scène d'utilisation. Je pense qu'il vaut mieux en hériter normalement. Bien sûr, une méthode qui déclare normalement une classe et est forcée de l'implémenter lève une exception dans la classe parente.

L'héritage multiple est possible

Python sera l'un des rares langages à prendre en charge l'héritage multiple.

class MultiInheritance(Base1, Base2, Base3):
...

La solution se fait dans l'ordre à partir de la gauche, et dans ce qui précède, si ce n'est pas en soi, Base1 est recherchée, puis Base2, et ainsi de suite. super est la classe la plus à gauche lorsqu'elle est appelée normalement.

Comme mentionné ci-dessus, Python n'a pas d'interface, il utilisera donc à la place l'héritage multiple (ou Module / Mix-in). Je pense qu'il vaut mieux ne pas utiliser l'héritage multiple à d'autres fins. Cependant, puisque tout le monde ressemble à une classe, il est préférable de décider de la règle du nom de la classe telle que commencer par ʻI` pour celle à utiliser comme interface (ou créer une classe telle que Interface / Module et en hériter).

Il y a deux constructeurs (ce que je pense)

En Python, «new» et «init» sont tous deux des constructeurs, n'est-ce pas? Il y a deux fonctions qui ressemblent à. En gros, utilisez «init». Cependant, comme vous pouvez le voir à partir de l'argument self, __init __ est un "processus d'initialisation après la création de l'instance", pas strictement un constructeur. __new__ est le processus de retour de l'instance pour l'initialisation avec __init__. Si vous voulez le faire, vous pouvez renvoyer une instance autre que votre propre classe, mais le mérite n'est pas si grand. Est-il utilisé pour l'implémentation singleton?

Il y a un attribut caché dans la classe

Les instances Python ont des attributs cachés entourés de deux traits de soulignement, comme le __init __ ci-dessus (également dans la définition de classe / fonction elle-même). Celles-ci sont utilisées pour stocker des méta-informations et effectuer des opérations de base (telles que le comportement lors de la définition / récupération de valeurs dans les attributs). Les détails sont détaillés dans Modèle de données, mais ceux qui sont souvent utilisés / utiles sont les suivants.

Nom d'attribut Contenu
__class__ Définition de classe.__class__.__name__Vous pouvez obtenir le nom de la classe avec
__dict__ Tous les attributs(Y compris la méthode)dictionnaire
__doc__ De classes et de méthodesdocstringPeut être obtenu. Si vous ne savez pas comment l'utiliser, mais qu'il est difficile de trouver le code source ou la documentation de l'API, vous pouvez le voir rapidement.
Nom de la méthode Contenu
__getattr__ Appelé lorsque l'accès à l'attribut est effectué et que l'attribut cible n'existe pas
__getattribute__ Toujours appelé lors de l'accès aux attributs
__setattr__ Appelé lors de l'attribution à un attribut
__delattr__ Appelé lors de la suppression d'un attribut(del obj.xxx)
__getstate__ Sérialisation d'objets(Cornichon)je fais
__setstate__ Restaurer à partir d'objets sérialisés
__str__ Méthode de stringification d'une classe(Soi-disant toString)
__repr__ Méthode de sortie de la notation d'instance(Notation de type et de certains membres)

__Str__ est similaire à __repr__, mais __str__ permet aux humains de connaître le contenu de la variable (lisible), et __repr__ sert à vérifier si la variable est du type prévu ( Sans ambiguïté) (Référence). C'est une bonne utilisation d'inclure la forme dans __repr__ dans une variable de matrice, etc., et vous pouvez vérifier si la variable prévue est reçue et traitée. Il est intentionnel de formater l'état de l'instance avec «str» afin qu'elle puisse être lue par des humains lorsqu'elle est sortie vers la console de journalisation.

Il y a de nombreux cas où vous voulez accéder avec l'attribut ʻobj.xxxau lieu de la chaîne de caractères telle que ʻobj ["xxx"], mais dans ce cas, le ci-dessus __getattr__ etc. est valide. Ci-dessous, Exemple d'implémentation dans soundcloud-python (obj transmis dans __init__ depuis l'API Web Obtenu un objet de type dictionnaire).

class Resource(object):
    """Object wrapper for resources.

    Provides an object interface to resources returned by the Soundcloud API.
    """
    def __init__(self, obj):
        self.obj = obj

    def __getstate__(self):
        return self.obj.items()

    def __setstate__(self, items):
        if not hasattr(self, 'obj'):
            self.obj = {}
        for key, val in items:
            self.obj[key] = val

    def __getattr__(self, name):
        if name in self.obj:
            return self.obj.get(name)
        raise AttributeError

    def fields(self):
        return self.obj

    def keys(self):
        return self.obj.keys()

C'est une technique qui peut être utilisée lorsque vous souhaitez modifier dynamiquement des attributs en fonction de la réponse de l'autre partie, comme un wrapper pour WebAPI. Pour plus de détails sur son utilisation, voir [ici](https://www.inkling.com/read/learning-python-mark-lutz-4th/chapter-37/-getattr --- et --- get attribute-) détaillé.

Les attributs tels que les définitions d'instance / classe peuvent être extraits avec le module ʻinspect`.

>>> import inspect
>>> inspect.getmembers(some_instance)

No Enum (2 seulement)

Installation standard de Python 3.4.1, mais il n'y a pas d'énumération jusque-là. Si vous voulez l'utiliser, installez et utilisez enum avec pip install enum34.

import enum


class Color(enum.Enum):
    Red = 10
    Blue = 20
    Yellow = 30

>>> Color.Red == Color.Red
True

>>> Color.Red == 10
False
#Ceci est faux car Enum est simplement un objet de type Enum. Il y a aussi un IntEnum qui rend ce True

>>> Color.Red == Color(10)
True
#Vous pouvez créer l'énumération correspondante en passant une valeur au constructeur

>>> Color.Red == Color["Red"]
True
#Lors de la création à partir du nom[]Spécifiez le nom avec

>>> {Color.Red:"red", Color.Blue:"blue"}
{<Color.Blue: 20>: 'blue', <Color.Red: 10>: 'red'}
#Peut également être utilisé comme clé de liste

Si vous souhaitez définir la chaîne de caractères de chaque élément, vous pouvez l'utiliser avec __str__. Ceci est utile lorsque vous ne souhaitez pas disperser la définition lors de l'affichage des étiquettes.

class Color(enum.Enum):
    Red = 10
    Blue = 20
    Yellow = 30
    
    def __str__(self):
        if self.value == Color.Red.value:
            return "rouge"
        elif self.value == Color.Blue.value:
            return "Bleu"
        elif self.value == Color.Yellow.value:
            return "Bleu"
>>> print(Color.Red)
rouge

Non privé ou protégé

Il n'y en a pas, mais il est d'usage d'ajouter «» ou «_» au début des privés. Il n'y a pas de concept équivalent au soi-disant Protégé, comme vouloir le montrer uniquement aux classes héritées. Alors, quelle est la différence entre «» et «_»? Le degré auquel cela est caché de l'extérieur change.

class Test(object):
    def __init__(self):
        self.__a = 'a' # two underscores
        self._b = 'b' # one underscore

>>> t = Test()
>>> t._b
'b'

>>> t.__a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__a'
t.__a isn't found because it no longer exists due to namemangling

>>> t._Test__a
'a'

Comme mentionné ci-dessus, si vous avez un trait de soulignement, vous pouvez y accéder comme d'habitude (il vous avertira si vous le vérifiez avec PEP), mais si vous avez deux traits de soulignement, vous ne pouvez pas y accéder à moins de faire _Test__a. Cela en fait une forme privée (généralement invisible).


Référence
The meaning of a single- and a double-underscore before an object name in Python Difference between _, __ and xx in Python

Il n'y a pas de const / final

Vous ne pouvez pas définir de constantes en Python. Cependant, comme les tuples décrits plus tard sont des listes immuables, il est possible de créer des pseudo constantes en utilisant ceci (je pense que const est bien s'il y a une liste immuable ... ).

Ici, dans PEP8, les constantes doivent être connectées avec toutes les majuscules et les traits de soulignement, mais il n'y a pas de contrôle pour cela.

Le premier argument de la méthode est réservé

class Test(object):
    def __init__():
        pass

    def get_num(self):
        return 1

    def add_num(self, num):
        return self.get_num() + num
    
    @classmethod
    def test_print(cls):
        print "test"

Le get_num ci-dessus semble apparemment prendre un argument, mais c'est essentiellement une méthode sans argument. Ensuite, les fonctions membres de la même classe sont appelées en utilisant ce premier argument implicite self et cls afin qu'elles soientself.get_num ().

List et taple (+ argument de longueur variable)

En Python, il existe un objet appelé Taple, qui est à peu près une "liste immuable". Ceux-ci ont différentes méthodes de déclaration.

v_list = [10, 20, 30] # list
v_tuple = (10, 20, 30) # tuple

v_list[1] = 11 # ok
v_tuple[1] = 11 # error! 'tuple' object does not support item assignment

Taple peut également être la clé du dictionnaire en raison de ses caractéristiques. Les listes et taples sont également profondément impliqués dans les fonctions / méthodes qui gèrent des arguments de longueur variable.

def out_with_tuple(a,b,*args):
    # a,Les arguments après b sont combinés en tuple
    print(a,b,args)

>>> out_with_tuple(1,2,3,4,5)
(1, 2, (3, 4, 5))

def out_with_dict(a,b,**args):
    print(a,b,args)

>>> out_with_dict(1,2,one=3,two=4,three=5)
(1, 2, {'three': 5, 'two': 4, 'one': 3})

Il est facile de considérer «» comme un pointeur, mais il représente un nombre arbitraire d'arguments et peut être regroupé en un taple pour «» et un dictionnaire pour «**» (peut être utilisé ensemble).

Ensuite, si l'appelant utilise «*», «**», la valeur list / taple peut être développée et passée en argument.

>>> def out(a,b):
...    print(a,b)

>>> out([1,2])  #Si vous passez la liste normalement, naturellement NG
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: out() takes exactly 2 arguments (1 given)


>>> out(*[1,2])
(1,2)  # *Développe les éléments de la liste et les sort(1,2)Sera la même chose que d'appeler

>>> out_with_dict(**{"a":1,"b":2})
(1, 2, {})  #Similaire à ce qui précède**Développe les arguments passés dans le dictionnaire

L'argument par défaut doit être immuable

La valeur donnée comme argument par défaut pour une méthode ou une fonction doit être immuable. C'est généralement le cas, donc il n'y a pas de problème, mais sachez que les tableaux vides sont mutables.

>>> class ArrayDefault():
>>>    def __init__(self, array=[]):
>>>        self.array = array  #! mutable default value

>>> a = ArrayDefault()
>>> len(a.array)
0
>>> a.array += [1,2,3]
>>> a.array
[1,2,3]

>>> b = ArrayDefault()
>>> b.array
[1, 2, 3]  # !!!!!

Pour une raison quelconque, la valeur est pré-remplie dans l'instance de «b» qui n'a rien à voir avec «a». Cela semble complètement compliqué et bizarre, c'est pourquoi l'argument doit être immuable. La portée de l'argument par défaut semble être la même que celle de cette méthode / fonction, et si elle n'est pas immuable, elle se comporte comme une variable globale et se comporte comme décrit ci-dessus.

Par conséquent, dans le cas ci-dessus, il est nécessaire de passer à un processus tel que définir Aucun comme argument par défaut et définir [] si Aucun. Comme avec les tableaux, des précautions doivent être prises dans les cas où la référence est définie comme valeur initiale.

Default Parameter Values in Python

Impossible de surcharger la méthode

Les surcharges avec des arguments différents et définies avec le même nom ne peuvent pas être utilisées en Python. Par conséquent, si vous souhaitez utiliser la surcharge, vous devez utiliser l'argument par défaut ou déterminer le type de l'argument en interne pour le gérer en créant des branches dans une seule méthode. De plus, les méthodes de classe et les méthodes membres portant le même nom ne sont pas autorisées.

Cependant, en utilisant singledispatch, le branchement conditionnel peut être éliminé et une implémentation surchargée peut être réalisée (standard de Python 3.4). Alimenté par).

Les calculs de l'opérateur peuvent être mis en œuvre (surcharge de l'opérateur)

En Python, il est possible d'implémenter des calculs par des opérateurs tels que «+» et «-» (soi-disant surcharge d'opérateurs) (Reference) ).

class Point(object):
    def __init__(self, x, y):
        self.x = 0 if x is None else x
        self.y = 0 if y is None else y
    def __add__(self, other):
        x = self.x + other.x
        y = self.y + other.y
        return Point(x, y)
    def __str__(self):
        return "x:{0}, y:{1}".format(self.x, self.y)

>>> print(Point(1, 2))
x:1, y:2
>>> print(Point(1, 2) + Point(1, 2))
x:2, y:4

Il est également possible d'implémenter des opérateurs logiques tels que «==» et «>». Cependant, il est assez difficile de définir tous les opérateurs sans aucune lacune. S'il s'agit d'un système de calcul numérique, il est préférable de vérifier s'il existe une bibliothèque appropriée plutôt que de l'implémenter par vous-même.

Peut décrire la définition de type (à partir de 3)

À partir de Python3 (notamment à partir de Python3.5), il est possible d'écrire des types pour les valeurs de retour des arguments et des fonctions.

def greeting(name: str) -> str:
    return 'Hello ' + name

À partir de Python 3.6, vous pouvez également ajouter des informations de type aux variables (PEP 526).

my_string: str
my_dict: Dict[str, int] = {}

Ceci est appelé annotation de type, et bien que cela ne donne pas d'erreur à l'exécution, il peut être vérifié à l'avance en utilisant ces informations. Les outils de vérification incluent mypy, qui peut être utilisé pour vérifier l'intégrité du type avant l'exécution. Voir ci-dessous pour plus de détails.

Monde typé commençant par Python

De plus, il y en a qui ont @ qui ressemble à l'annotation Java, mais ce n'est pas une annotation mais un "décorateur", et son comportement est complètement différent, ce qui affecte l'exécution de la fonction. Comme son nom l'indique, «décorer» fonctionne comme une «fonction qui encapsule une fonction».

import functools

def makebold(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        return "<b>" + func(*args, **kwargs) + "</b>"
    return wrapper

def makeitalic(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        return "<i>" + func(*args, **kwargs) + "</i>"
    return wrapper

@makebold
@makeitalic
def hello(your_name):
    return "hello {0}.".format(your_name)

>>> print hello("hoge") ## returns <b><i>hello hoge.</i></b>

Référence: Comment puis-je créer une chaîne de décorateurs de fonctions en Python?

Ce qui précède est identique à l'exécution de makebold (makeitalic (hello)) (your_name) (exécuté séquentiellement à partir du décorateur le plus proche de la définition de la fonction). Si vous souhaitez vérifier avant d'exécuter la méthode (autorisation, etc. Vérifier les remplacements, Etc.), ou lorsque vous souhaitez insérer un traitement avant et après l'exécution (mesure du temps d'exécution, etc.). De plus, functools.wrap évite que les informations de la fonction ne soient remplacées par la fonction décorée au lieu de la fonction d'origine en décorant (here. 20090427/1240838573)).

Il est assez difficile d'obtenir les décorateurs donnés à une méthode Par conséquent, à des fins de méta-programmation (comme obtenir une méthode annotée et l'exécuter), il est préférable de la mettre à niveau vers Python3 et d'utiliser l'annotation.

À propos des espaces de noms et des importations

En Python, l'espace de noms est coupé (automatiquement) pour chaque fichier sans déclarer d'espace de noms ou de package. Le nom de l'espace de noms coupé pour chaque fichier est synonyme du nom du fichier, donc lorsque vous appelez TestClass défini dans package / test_class.py, il est nécessaire d'utiliser from package.test_class import TestClass. Il y a.

De plus, comme il est coupé en unités de fichiers, une déclaration d'importation est requise lors du référencement de fichiers dans le même dossier. Notez que le dossier est reconnu comme un package s'il existe un fichier appelé __init __. Py (il ne doit pas nécessairement provenir de Python3).

Comme avec Java, si vous souhaitez importer par nom de package / classe (comme from package import TestClass), vous pouvez le gérer en écrivant l'instruction d'importation du fichier dans __init __. Py. C'est parce que la partie from package est chargée avec __init __. Py dans le dossier, donc s'il y a une instruction d'importation ici, ce sera la même chose que l'importation du fichier.

Notez que lors de l'importation de fichiers référencés mutuellement (A fait référence à B et B fait référence à A), cela devient un blocage et ne peut pas être importé. Pour éviter cela, il est nécessaire de prendre certaines mesures telles que l'importation dans le cadre du traitement nécessaire plutôt qu'au début du fichier (Référence. python)).

Tout fichier peut être exécuté en tant que script

ʻSi name == "main": peut décrire ce qui se passe quand il est exécuté comme un script (lorsqu'il est exécuté avec python xxx.py`) (voir [Environnement de script de premier niveau](http: // docs). .python.jp / 2 / bibliothèque / __ main __. html)).

if __name__ == "__main__":
    print "Run Script"

Peu importe que ce soit le fichier qui définit la classe ou le fichier qui définit la fonction. Par conséquent, si vous voulez vérifier le fonctionnement de la classe que vous définissez pendant un moment, mettez l'instruction if ci-dessus au bas du fichier et écrivez le processus de vérification de l'opération sous python xxx.py Vous pouvez le vérifier en définissant . C'est très pratique.

Le traitement peut être décrit dans un tableau (notation d'inclusion de liste)

En Python, il est possible d'effectuer des opérations dans un tableau comme suit.

>>> [ x for x in [1, 2, 3, 4, 5] if x > 3]
[4, 5]

>>> [ x*2 for x in [1, 2, 3, 4, 5]]
[2, 4, 6, 8, 10]

#Il est également possible d'utiliser des fonctions
>>>def calc_double(x):
>>>    return x*2

>>> [ calc_double(x) for x in [1, 2, 3, 4, 5]]
[2, 4, 6, 8, 10] 

Cela fonctionne de la même manière que les fonctions intégrées telles que map et filter, mais dans certains cas, il est plus facile d'écrire avec une meilleure lisibilité. Depuis Python3, map et filter ne renvoient pas la liste elle-même, mais il renvoie un itérateur. -list-in-python-3-x), donc si vous voulez le gérer avec une liste comme Python2, utilisez la notation d'inclusion de liste, si vous voulez enchaîner de l'itérateur au traitement suivant, utilisez map / filter etc. Il est facile de prendre en charge les deux versions si vous les conservez. De plus, Il semble que la vitesse d'exécution est rapide.

Depuis Python3.6, il est possible de gérer des itérateurs asynchrones même avec cette notation d'inclusion de liste (PEP 530). ..

result = [i async for i in async_iter() if i % 2]
result = [await fun() for fun in async_funcs if await condition()]

Créer une fonction anonyme

En Python, vous pouvez créer des fonctions anonymes en utilisant lambda.

>>> list(map(lambda x: x * 2, range(5)))
[0, 2, 4, 6, 8]

Dans ce qui précède, «map» est utilisé et la fonction «lambda x: x * 2» est appliquée à chaque valeur de «range (5)». La fonction créée par lambda peut également être affectée à une variable, et ce qui précède est équivalent à ce qui suit.

>>> f = lambda x: x * 2
>>> list(map(f, range(5)))
[0, 2, 4, 6, 8]

Combiné avec la notation d'inclusion de liste ci-dessus, le traitement suivant est également appliqué.

>>> f = lambda a, b: a + b
>>> [f(*z) for z in zip([1, 2, 3], [4, 5, 6])]
[5, 7, 9]

zip est une fonction pratique qui prend plusieurs tableaux comme arguments et les rassemble pour chaque index, et zip ([1, 2, 3], [4, 5, 6]) ʻis [(1, 4), ( 2, 5), (3, 6)] ». Ceci est étendu à l'argument de la fonction f using` * ʻet traité.

À propos de l'instruction for

Les instructions Python for sont identiques à chacune et ne peuvent pas être indexées par défaut. Si vous souhaitez utiliser index dans une instruction de boucle, procédez comme suit.

for index, value in enumerate(list):
    print "index:" + index

Si vous voulez juste tourner par index, vous pouvez également écrire comme suit (Comme il n'y a pas de list.length en Python, utilisez len (list) pour obtenir la longueur).

for index in range(len(list)):
    print "index:" + index

Comme propriété pratique, vous pouvez définir else dans l'instruction Python for (bien que while puisse être utilisé plus souvent).

child = "Bob"
for c in ["Alice", "Tom", "Ann", "Cony"]:
    if c == child:
        break
else:
    print("{} is not here.".format(child))

Le processus défini par ʻelse est traité lorsque break` n'est pas exécuté. Par conséquent, il peut être utilisé pour décrire le traitement lorsque la détection ne peut pas être effectuée dans la boucle.

à propos de l'instruction if

Puisque Python n'a pas d'instruction switch, if-else est utilisé à la place. Eh bien, vous pourriez penser, mais Python a une indentation et si est assez propre, donc ce n'est pas trop un problème.

Aussi, pour cette raison, vous pouvez penser que vous ne pouvez pas écrire une instruction if sur une ligne (soi-disant opérateur ternaire) en Python, mais en Python 2.5 ou supérieur, vous pouvez écrire comme suit ([PEP 308-] - Expressions conditionnelles](voir http://legacy.python.org/dev/peps/pep-0308/).

>>> test = 1
>>> "test eq 1" if test == 1 else "test not eq 1"
'test eq 1'

Il existe une syntaxe pour implémenter le traitement asynchrone (à partir de 3)

A partir de Python3.5, le traitement asynchrone peut être facilement implémenté en utilisant la syntaxe ʻasync / ʻawait (bien qu'il était possible d'implémenter avec ʻasyncio` avant cela, en tant que grammaire Mis en œuvre). Lors du traitement d'un certain processus continu («tâches» dans ce qui suit) dans plusieurs processus, il peut être écrit comme suit.

import asyncio
import random


tasks = asyncio.Queue()
for t in range(10):
    tasks.put_nowait(t)


async def execute(p):
    while not tasks.empty():
        t = await tasks.get()
        await asyncio.sleep(random.randint(0, 3))  # emulate the waiting time until task t finish
        print("Process{} done task {}".format(p, t))
    return True


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    execution = asyncio.wait([execute(process_no) for process_no in range(2)])
    loop.run_until_complete(execution)

Le résultat de l'exécution est le suivant (* Bien sûr, le résultat sera différent à chaque exécution).

Process1 done task 0
Process0 done task 1
Process1 done task 2
Process0 done task 3
Process1 done task 4
Process0 done task 5
Process1 done task 6
Process0 done task 7
Process0 done task 9
Process1 done task 8

Veuillez vous référer à l'article suivant pour plus de détails.

Traitement asynchrone en Python: référence inverse asyncio

Il est maintenant possible de créer des itérateurs asynchrones plus facilement en utilisant yield de Python 3.6 ([PEP 525](https://docs.python.org/3.6/whatsnew/3.6.html#" whatsnew36-pep525)).

async def ticker(delay, to):
    """Yield numbers from 0 to *to* every *delay* seconds."""
    for i in range(to):
        yield i
        await asyncio.sleep(delay)

Le package créé peut être publié (PyPI)

En Python, il existe un site appelé PyPI qui héberge des packages, et en publiant le package créé ici, il peut être largement utilisé par d'autres personnes avec pip install etc. Vous pouvez l'obtenir (comme Maven en Java, rubygems.org en Ruby, nuget en .NET).

En ce qui concerne cette méthode, si vous recherchez normalement, l'ancienne méthode sera souvent interceptée, veuillez donc vous référer à ce qui suit pour la dernière méthode de téléchargement.

Publier la bibliothèque créée en Python sur PyPI

Autre

Voir également ci-dessous pour tout autre chose que ceux répertoriés ici. [python] 10 vrais pièges de Python qui sont trop détaillés pour être véhiculés

Recommended Posts

Conseils à consulter avant de commencer à écrire Python
Avant d'écrire du code Python
Commencez à Selenium en utilisant python
3 raisons pour lesquelles les débutants en programmation devraient commencer avec Python
~ Conseils pour les débutants de Python présentés avec amour par Pythonista ③ ~
Ravi de vous rencontrer avec python
Python facile à apprendre en écrivant
Convertir un mémo à la fois avec Python 2to3
Conseils pour faciliter la lecture des documents d'audition Python
Analyse des données en Python Résumé des sources que les débutants devraient d'abord consulter
Démarrer python
Astuces Python
Astuces Python
[Astuces] Écriture facile à lire lors de la connexion de fonctions en Python
Comment démarrer Python (Flask) au démarrage d'EC2
Écriture de journaux dans un fichier CSV (Python, langage C)
A vous qui développez Python sous Windows & Proxy
Commerce de système à partir de Python3: les stocks de bio-santé à examiner dans le nouveau Corona