Sauf erreur, la création d'une fonction en Python fonctionne comme ceci:
def my_func(param1, param2):
# stuff
Cependant, vous ne donnez pas réellement les types de ces paramètres. De plus, si je me souviens bien, Python est un langage fortement typé, en tant que tel, il semble que Python ne devrait pas vous laisser passer un paramètre d'un type différent de celui attendu par le créateur de la fonction. Cependant, comment Python sait-il que l'utilisateur de la fonction transmet les types appropriés? Le programme va-t-il simplement mourir s'il n'est pas du bon type, en supposant que la fonction utilise réellement le paramètre? Devez-vous spécifier le type?
python
function
parameters
Leif Andersen
la source
la source
Réponses:
Python est fortement typé car chaque objet a un type, chaque objet connaît son type, il est impossible d'utiliser accidentellement ou délibérément un objet d'un type "comme si" c'était un objet d'un type différent , et toutes les opérations élémentaires sur l'objet sont déléguée à son type.
Cela n'a rien à voir avec les noms . Un nom en Python n'a pas "de type": si et quand un nom est défini, le nom fait référence à un objet , et l' objet a un type (mais cela ne force pas en fait un type sur le nom : a nom est un nom).
Un nom en Python peut parfaitement faire référence à différents objets à des moments différents (comme dans la plupart des langages de programmation, mais pas tous) - et il n'y a pas de contrainte sur le nom de telle sorte que, s'il a déjà fait référence à un objet de type X, il est alors contraint forevermore de se référer uniquement à d' autres objets de type X. les contraintes sur les noms ne font pas partie du concept de « frappe fort », bien que certains amateurs de statique taper (où les noms ne se pressèrent, et dans une statique, Alias compile- le temps, la mode aussi) abusent du terme de cette façon.
la source
try
/except
) se produira quand et si une opération est tentée que l'objet ne prend pas en charge. Dans Python 3.5, vous pouvez désormais éventuellement "spécifier les types" d'arguments, mais aucune erreur ne se produit, en soi, si la spécification est violée; la notation de frappe est uniquement destinée à aider à séparer les outils qui effectuent l'analyse, etc., elle ne modifie pas le comportement de Python lui-même.Les autres réponses ont bien expliqué le typage du canard et la réponse simple par tzot :
Cependant , une chose intéressante a changé depuis 2010 (lorsque la question a été posée pour la première fois), à savoir l'implémentation de PEP 3107 (implémenté en Python 3). Vous pouvez maintenant réellement spécifier le type d'un paramètre et le type du type de retour d'une fonction comme ceci:
Nous pouvons voir ici que cela
pick
prend 2 paramètres, une listel
et un entierindex
. Il doit également renvoyer un entier.Il s'agit donc ici d'
l
une liste d'entiers que nous pouvons voir sans trop d'effort, mais pour des fonctions plus complexes, cela peut être un peu déroutant quant à ce que la liste doit contenir. Nous voulons également que la valeur par défautindex
soit 0. Pour résoudre ce problème, vous pouvez choisir d'écrirepick
comme ceci à la place:Notez que nous mettons maintenant une chaîne comme type de
l
, ce qui est autorisé syntaxiquement, mais ce n'est pas bon pour l'analyse par programme (que nous reviendrons plus tard).Il est important de noter que Python n'augmentera pas
TypeError
si vous passez un flotteurindex
, la raison en est l'un des principaux points de la philosophie de conception de Python: "Nous sommes tous des adultes consentants ici" , ce qui signifie que vous êtes censé soyez conscient de ce que vous pouvez passer à une fonction et de ce que vous ne pouvez pas. Si vous voulez vraiment écrire du code qui lance TypeErrors, vous pouvez utiliser laisinstance
fonction pour vérifier que l'argument passé est du type approprié ou d'une sous-classe de celui-ci comme ceci:Plus d'informations sur les raisons pour lesquelles vous devriez rarement faire cela et sur ce que vous devriez faire à la place sont discutées dans la section suivante et dans les commentaires.
Le PEP 3107 améliore non seulement la lisibilité du code, mais propose également plusieurs cas d'utilisation appropriés que vous pouvez lire ici .
L'annotation de type a attiré beaucoup plus d'attention dans Python 3.5 avec l'introduction de PEP 484 qui introduit un module standard pour les indications de type.
Ces indices de type provenaient du vérificateur de type mypy ( GitHub ), qui est maintenant conforme au PEP 484 .
Avec le module de frappe est livré avec une collection assez complète d'indices de type, y compris:
List
,Tuple
,Set
,Map
- pourlist
,tuple
,set
etmap
respectivement.Iterable
- utile pour les générateurs.Any
- quand ça pourrait être n'importe quoi.Union
- quand il pourrait être n'importe quoi dans un ensemble spécifié de types, par opposition àAny
.Optional
- quand ce pourrait être Aucun. Sténographie pourUnion[T, None]
.TypeVar
- utilisé avec des génériques.Callable
- utilisé principalement pour les fonctions, mais pourrait être utilisé pour d'autres callables.Ce sont les indices de type les plus courants. Une liste complète se trouve dans la documentation du module de saisie .
Voici l'ancien exemple utilisant les méthodes d'annotation introduites dans le module de frappe:
Une fonctionnalité puissante est la
Callable
qui vous permet de taper des méthodes d'annotation qui prennent une fonction en argument. Par exemple:L'exemple ci-dessus pourrait devenir plus précis avec l'utilisation de
TypeVar
au lieu deAny
, mais cela a été laissé au lecteur car je pense avoir déjà rempli ma réponse avec trop d'informations sur les merveilleuses nouvelles fonctionnalités activées par l'indication de type.Auparavant, lorsque l'on documentait du code Python avec par exemple Sphinx, certaines des fonctionnalités ci-dessus pouvaient être obtenues en écrivant des docstrings formatés comme ceci:
Comme vous pouvez le voir, cela prend un certain nombre de lignes supplémentaires (le nombre exact dépend de la façon dont vous voulez être explicite et de la façon dont vous formatez votre docstring). Mais il devrait maintenant être clair pour vous que le PEP 3107 fournit une alternative qui est à bien des égards (toutes?) Supérieure. Cela est particulièrement vrai en combinaison avec PEP 484 qui, comme nous l'avons vu, fournit un module standard qui définit une syntaxe pour ces types d'indications / annotations qui peut être utilisée de telle sorte qu'elle soit sans ambiguïté et précise mais flexible, ce qui en fait un combinaison puissante.
À mon avis, c'est l'une des meilleures fonctionnalités de Python. J'ai hâte que les gens commencent à en exploiter le pouvoir. Désolé pour la longue réponse, mais c'est ce qui se passe quand je m'excite.
Un exemple de code Python qui utilise fortement l'indication de type peut être trouvé ici .
la source
TypeError
, quel est l'intérêt d'utiliserpick(l: list, index: int) -> int
comme une définition sur une ligne alors? Ou je me suis trompé, je ne sais pas.__annotations__
attribut de l'objet fonction).def f(a) -> Tuple[int, int]:
Vous ne spécifiez pas de type. La méthode échouera (au moment de l'exécution) uniquement si elle essaie d'accéder à des attributs qui ne sont pas définis sur les paramètres transmis.
Donc, cette fonction simple:
... n'échouera pas, quels que soient les deux arguments passés.
Cependant, cette fonction:
... échouera à l'exécution si
param1
etparam2
n'ont pas tous les deux des attributs appelables nommésquack
.la source
De nombreuses langues ont des variables, qui sont d'un type spécifique et ont une valeur. Python n'a pas de variables; il a des objets, et vous utilisez des noms pour faire référence à ces objets.
Dans d'autres langues, quand vous dites:
puis une variable (généralement entière) change son contenu à la valeur 1.
En Python,
signifie "utiliser le nom a pour faire référence à l'objet 1 ". Vous pouvez effectuer les opérations suivantes dans une session Python interactive:
La fonction
type
est appelée avec l'objet1
; puisque chaque objet connaît son type, il est faciletype
de trouver ce type et de le renvoyer.De même, chaque fois que vous définissez une fonction
la fonction reçoit deux objets, les nomme
param1
etparam2
, quel que soit leur type. Si vous voulez vous assurer que les objets reçus sont d'un type spécifique, codez votre fonction comme s'ils appartenaient au (x) type (s) requis et interceptez les exceptions levées si elles ne le sont pas. Les exceptions levées sont généralementTypeError
(vous avez utilisé une opération non valide) etAttributeError
(vous avez essayé d'accéder à un membre inexistant (les méthodes sont également des membres)).la source
Python n'est pas fortement typé dans le sens d'une vérification de type statique ou à la compilation.
La plupart du code Python relève de ce qu'on appelle le "Duck Typing" - par exemple, vous recherchez une méthode
read
sur un objet - vous ne vous souciez pas si l'objet est un fichier sur disque ou une socket, vous voulez juste lire N octets de celui-ci.la source
Comme l' explique Alex Martelli ,
Lisez le reste de son article pour des informations utiles.
la source
Python ne se soucie pas de ce que vous transmettez à ses fonctions. Lorsque vous appelez
my_func(a,b)
, les variables param1 et param2 contiendront alors les valeurs de a et b. Python ne sait pas que vous appelez la fonction avec les types appropriés et attend du programmeur qu'il s'en occupe. Si votre fonction sera appelée avec différents types de paramètres, vous pouvez encapsuler le code y accédant avec des blocs try / except et évaluer les paramètres comme vous le souhaitez.la source
Vous ne spécifiez jamais le type; Python a le concept de typage canard ; Fondamentalement, le code qui traite les paramètres fera certaines hypothèses à leur sujet - peut-être en appelant certaines méthodes qu'un paramètre devrait implémenter. Si le paramètre est du mauvais type, une exception sera levée.
En général, c'est à votre code de s'assurer que vous passez des objets du type approprié - il n'y a pas de compilateur pour appliquer cela à l'avance.
la source
Il y a une exception notoire à la frappe de canard qui mérite d'être mentionnée sur cette page.
Lorsque la
str
fonction appelle__str__
la méthode de classe, elle vérifie subtilement son type:Comme si Guido nous indiquait quelle exception un programme devrait lever s'il rencontre un type inattendu.
la source
En Python, tout a un type. Une fonction Python fera tout ce qui lui est demandé si le type d'arguments la prend en charge.
Exemple:
foo
ajoutera tout ce qui peut être__add__
édité;) sans trop se soucier de son type. Cela signifie donc que pour éviter l'échec, vous ne devez fournir que les éléments qui prennent en charge l'ajout.la source
Je n'ai pas vu cela mentionné dans d'autres réponses, alors je vais l'ajouter au pot.
Comme d'autres l'ont dit, Python n'applique pas le type sur les paramètres de fonction ou de méthode. On suppose que vous savez ce que vous faites et que si vous avez vraiment besoin de savoir le type de chose qui a été transmise, vous le vérifierez et déciderez quoi faire par vous-même.
L'un des principaux outils pour ce faire est la fonction isinstance ().
Par exemple, si j'écris une méthode qui s'attend à obtenir des données de texte binaires brutes, plutôt que les chaînes encodées en utf-8 normales, je pourrais vérifier le type des paramètres en chemin et soit m'adapter à ce que je trouve, soit élever un exception à refuser.
Python fournit également toutes sortes d'outils pour creuser dans des objets. Si vous êtes courageux, vous pouvez même utiliser importlib pour créer vos propres objets de classes arbitraires, à la volée. J'ai fait cela pour recréer des objets à partir de données JSON. Une telle chose serait un cauchemar dans un langage statique comme C ++.
la source
Pour utiliser efficacement le module de frappe (nouveau dans Python 3.5), incluez all (
*
).Et vous serez prêt à utiliser:
Cependant, vous pouvez toujours utiliser les noms de type comme
int
,list
,dict
, ...la source
J'ai implémenté un wrapper si quelqu'un souhaite spécifier des types de variables.
Utilisez-le comme:
ÉDITER
Le code ci-dessus ne fonctionne pas si aucun type d'argument (ou de retour) n'est déclaré. La modification suivante peut aider, d'autre part, elle ne fonctionne que pour les kwargs et ne vérifie pas les arguments.
la source