Python est-il fortement tapé?
j'ai trouvé des liens qui disent que Python est un langage fortement typé.
cependant, j'ai pensé que dans les langues fortement dactylographiées vous ne pourriez pas faire cela:
bob = 1
bob = "bob"
je pensais qu'un langage fortement dactylographié n'acceptait pas de changer de type à l'exécution. Peut-être que j'ai une mauvaise définition (ou trop simpliste) des types forts/faibles.
donc, Python est-il un langage fortement ou faiblement typé?
10 réponses
Python est fortement, dynamiquement typé.
- fort taper signifie que le type d'une valeur ne change pas soudainement. Une chaîne ne contenant que des chiffres ne devient pas magiquement un nombre, comme cela peut arriver en Perl. Chaque changement de type nécessite une conversion explicite.
- Dynamique taper signifie que les objets d'exécution (valeurs) ont un type, par opposition à typage statique où les variables ont un type.
comme pour votre exemple
bob = 1
bob = "bob"
cela fonctionne parce que la variable n'a pas de type; elle peut nommer n'importe quel objet. Après bob=1
, vous trouverez que type(bob)
retourne int
, mais après bob="bob"
, il retourne str
. (Notez que type
est une fonction régulière, donc elle évalue son argument, puis renvoie le type de la valeur.)
contraste avec les dialectes plus anciens de C, qui étaient faiblement, statiquement typés, de sorte que les pointeurs et les entiers étaient à peu près interchangeables. (L'ISO C moderne nécessite des conversions dans de nombreux cas, mais mon compilateur est encore indulgent à ce sujet par défaut.)
je dois ajouter que le fort vs. faible typage est plus un continuum qu'un choix booléen. C++ a un typage plus fort que C (plus de conversions nécessaires), mais le système de type peut être subverti en utilisant des lancements de pointeurs.
La force du système de type dans un langage dynamique tel que Python est vraiment déterminée par la façon dont ses primitives et ses fonctions de bibliothèque répondent aux différents types. Par exemple, +
est surchargé de sorte qu'il fonctionne sur deux numéros ou deux chaînes, mais pas une chaîne et un nombre. Il s'agit d'un choix de conception fait lorsque +
a été mis en œuvre, mais pas vraiment une nécessité découlant de la sémantique du langage. En fait, quand vous surchargez +
sur un type personnalisé, vous pouvez le faire convertir implicitement n'importe quoi en un nombre:
def to_number(x):
"""Try to convert x to a number."""
if x is None:
return 0
# more special cases here
else:
return float(x) # works for numbers and strings
class Foo(object):
def __add__(self, other):
other = to_number(other)
# now do the addition
(le seul langage que je connaisse qui soit complètement fortement dactylographié, alias strictement dactylographié, est Haskell, où les types sont entièrement disjoints et où seule une forme contrôlée de surcharge est possible via les classes de types.)
il y a des questions importantes que je pense que toutes les réponses existantes ont manquées.
faible Dactylographie signifie permettre l'accès à la représentation sous-jacente. En C, je peux créer un pointeur vers des caractères, puis dire au compilateur que je veux l'utiliser comme pointeur vers des entiers:
char sz[] = "abcdefg";
int *i = (int *)sz;
sur une plateforme little-endian avec des entiers de 32 bits, cela fait i
dans un tableau des nombres 0x64636261
et 0x00676665
. En fait, vous pouvez même lancer des pointeurs eux-mêmes à entiers (de la taille appropriée):
intptr_t i = (intptr_t)&sz;
et bien sûr cela signifie que je peux écraser la mémoire n'importe où dans le système.*
char *spam = (char *)0x12345678
spam[0] = 0;
* bien sûr, les systèmes D'exploitation modernes utilisent la mémoire virtuelle et la protection des pages de sorte que je ne peux que réécrire la mémoire de mon propre processus, mais il n'y a rien au sujet de C lui-même qui offre une telle protection, comme quiconque codé sur, disons, Classique Mac OS ou Win16 peut vous le dire.
Lisp traditionnel a permis des genres similaires de hackery; sur certaines plates-formes, les flotteurs de double-mot et les cellules contre étaient le même type, et vous pourriez passer un à une fonction attendant l'autre et il serait "travailler".
la plupart des langues aujourd'hui ne sont pas aussi faibles que le C et le Lisp, mais beaucoup d'entre elles sont encore un peu floues. Par exemple, n'importe quel langage OO qui a un "downcast" non vérifié,* c'est une fuite de type: vous dites essentiellement au compilateur "je sais que je ne vous ai pas donné assez d'informations pour savoir que c'est sûr, mais je suis presque sûr que c'est sûr", quand le but d'un système de type est que le compilateur a toujours assez d'informations pour savoir ce qui est sûr.
* un downcast vérifié ne rend pas le système de type de langue plus faible juste parce qu'il déplace le check vers l'exécution. Si c'était le cas, le polymorphisme des sous-Types (aussi appelé "appel de fonction virtuel" ou "appel de fonction entièrement dynamique") la même violation du système de type, et je ne pense pas que quelqu'un veuille dire ça.
très peu de langues de" scripting " sont faibles dans ce sens. Même en Perl ou Tcl, vous ne pouvez pas prendre une chaîne de caractères et interpréter ses octets comme un entier.* Mais il est intéressant de noter qu'en CPython (et de la même façon pour beaucoup d'autres interprètes pour beaucoup de langues), si vous êtes vraiment persistant, vous pouvez utiliser ctypes
pour charger libpython
, lancer id
d'un objet à un POINTER(Py_Object)
, et forcer le système de type à fuir. Si cela rend le système de type faible ou non dépend de vos cas d'utilisation-si vous essayez de mettre en œuvre un bac à sable d'exécution restreinte dans la langue pour assurer la sécurité, Vous avez à faire face à ce genre d'évasion...
* vous pouvez utiliser une fonction comme struct.unpack
pour lire les octets et construire un nouvel int à partir de "comment C représenterait ces octets", mais ce n'est évidemment pas leaky; même Haskell le permet.
en attendant, la conversion implicite est vraiment une chose différente d'un système faible ou leaky type.
chaque langue, même Haskell, a des fonctions pour, disons, convertir un entier en une chaîne ou un flotteur. Mais certaines langues feront certaines de ces conversions pour vous automatiquement-par exemple, en C , si vous appelez une fonction qui veut un float
, et que vous la passez dans int
, elle est convertie pour vous. Cela peut indubitablement conduire à des bugs avec, par exemple, des débordements inattendus, mais ils ne sont pas les mêmes types de bugs que vous obtenez d'un système de type faible. Et C n'est pas vraiment plus faible ici; vous pouvez ajouter un int et un float dans Haskell, ou même concaténer un float à une chaîne, vous avez juste à le faire plus explicitement.
et avec les langues dynamiques, c'est assez obscur. Il n'y a rien de tel que "une fonction qui veut un char" en Python ou Perl. Mais il y a des fonctions surchargées qui ne différentes choses avec différents types, et il y a un fort sentiment intuitif que, par exemple, ajouter une chaîne à quelque chose d'autre est "une fonction qui veut une chaîne". En ce sens, Perl, Tcl et JavaScript semblent faire beaucoup de conversions implicites ( "a" + 1
vous donne "a1"
), alors que Python en fait beaucoup moins ( "a" + 1
soulève une exception, mais 1.0 + 1
vous donne 2.0
*). Il est juste difficile de mettre ce sens en termes formels-pourquoi ne devrait-il pas y avoir un +
cela prend une chaîne et un int, quand il y a évidemment d'autres fonctions, comme l'indexation, qui font?
* en fait, en Python moderne, cela peut être expliqué en termes de sous-typage OO, puisque isinstance(2, numbers.Real)
est vrai. Je ne pense pas qu'il y ait un sens dans lequel 2
est une instance du type string dans Perl ou JavaScript... bien que dans Tcl, il est en fait, depuis tout est une instance de string.
enfin, il y a une autre définition, complètement orthogonale, de" Fort "vs." faible "Dactylographie, où" fort " signifie puissant/souple/expressif.
par exemple, Haskell vous permet de définir un type qui est un nombre, une chaîne, une liste de ce type, ou une carte à partir des chaînes de ce type, ce qui est une façon parfaite de représenter tout ce qui peut être décodé à partir de JSON. Il n'y a aucun moyen de définir un tel type en Java. Mais au moins Java a paramétrique types (generic), de sorte que vous pouvez écrire une fonction qui prend une liste de T et de savoir que les éléments sont de type T; d'autres langues, comme Java tôt, vous a forcé à utiliser une liste D'objet et downcast. Mais au moins Java vous permet de créer de nouveaux types avec leurs propres méthodes; C vous permet seulement de créer des structures. Et BCPL n'avait même pas ça. Et ainsi de suite jusqu'à l'assemblage, où les seuls types sont différentes longueurs de bits.
donc, dans ce sens, le système de type de Haskell est plus fort que le système moderne Java, qui est plus fort que Java, qui est plus fort que C, qui est plus fort que BCPL.
alors, où se situe Python dans ce spectre? C'est un peu délicat. Dans de nombreux cas, taper duck vous permet de simuler tout ce que vous pouvez faire dans Haskell, et même certaines choses que vous ne pouvez pas; bien sûr, les erreurs sont attrapées à l'exécution au lieu de compiler le temps, mais elles sont toujours attrapées. Cependant, il y a des cas où le type canard n'est pas suffisant. Par exemple, à Haskell, vous pouvez dites qu'une liste vide de ints est une liste de ints, de sorte que vous pouvez décider que la réduction de +
sur cette liste devrait retourner 0*; en Python, une liste vide est une liste vide; il n'y a aucune information de type pour vous aider à décider ce que la réduction de +
sur elle devrait faire.
* en fait, Haskell ne vous laisse pas faire cela; si vous appelez la fonction reduce qui ne prend pas une valeur de départ sur une liste vide, vous obtenez une erreur. Mais son système de type est assez puissant que vous pourrait faire ce travail, et Python n'est pas.
Vous confondez "fortement typé' avec 'typées dynamiquement' .
Je ne peux pas changer le type de 1
en ajoutant la chaîne '12'
, mais je peux choisir quels types je stocke dans une variable et changer cela pendant le temps d'exécution du programme.
le contraire du typage dynamique est le typage statique; la déclaration des types variables ne change pas au cours de la durée de vie d'un programme. Le contraire du typage fort est le typage faible; le type de valeurs peut changer pendant la durée de vie d'un programme.
selon cet wiki Python article Python est à la fois dynamiquement et fortement dactylographié (fournit une bonne explication aussi).
peut-être pensez-vous à des langues statically typed où les types ne peuvent pas changer pendant l'exécution du programme et où la vérification des types se produit pendant la compilation pour détecter d'éventuelles erreurs.
cette question pourrait être d'intérêt: langues de type dynamique versus langues de type statique et cet article de Wikipédia sur systèmes de Type fournit plus d'information
il a déjà été répondu quelques fois, mais Python est un langage fortement typé:
>>> x = 3
>>> y = '4'
>>> print(x+y)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
ce qui suit en JavaScript:
var x = 3
var y = '4'
alert(x + y) //Produces "34"
c'est la différence entre un faible typage et un fort typage. Les types faibles essaient automatiquement de passer d'un type à un autre, selon le contexte (par exemple Perl). Types forts jamais convertir implicitement.
votre confusion réside dans un mauvaise compréhension de la façon dont Python lie les valeurs aux noms (communément appelé variables).
en Python, les noms n'ont pas de type, donc vous pouvez faire des choses comme:
bob = 1
bob = "bob"
bob = "An Ex-Parrot!"
et les noms peuvent être liés à n'importe quoi:
>>> def spam():
... print("Spam, spam, spam, spam")
...
>>> spam_on_eggs = spam
>>> spam_on_eggs()
Spam, spam, spam, spam
pour une lecture ultérieure:
https://en.wikipedia.org/wiki/Dynamic_dispatch
et le légèrement lié mais plus avancé:
une variable Python stocke une référence non typée à l'objet cible qui représente la valeur.
toute opération d'assignation signifie assigner la référence non typée à l'objet assigné, c'est-à-dire que l'objet est partagé via les références originales et les nouvelles (comptées) références.
le type de valeur est lié à l'objet cible et non à la valeur de référence. La vérification de type (forte) est effectuée lorsqu'une opération avec la valeur est effectuée (temps d'exécution).
en d'autres termes, les variables (techniquement) n'ont pas de type -- cela n'a pas de sens de penser en termes de type de variable si l'on veut être exact. Mais les références sont automatiquement déréférencées et nous pensons réellement en termes de type de l'objet cible.
l'expression" forte Dactylographie " n'a pas de définition précise.
par conséquent, l'utilisation du terme dépend avec qui vous parlez.
Je ne considère aucune langue, dans laquelle le type d'une variable n'est pas explicitement déclaré, ou statiquement typé pour être fortement typé.
forte Dactylographie n'empêche pas seulement la conversion (par exemple," automatiquement " conversion d'un entier à une chaîne de caractères). Il s'oppose à affectation (c'est à dire, changer le type d'une variable).
si le code suivant est compilé( interprété), le langage n'est pas fortement typé:
Foo = 1 Foo = "1"
Dans un langage fortement typé, un programmeur peut "compter sur" un type.
Par exemple, si un programmeur voit la déclaration,
UINT64 kZarkCount;
et il ou elle sait que 20 lignes plus tard, kZarkCount est toujours un UINT64 (aussi longtemps qu'il se produit dans le même bloc) - sans avoir à examiner le code intermédiaire.
TLDR;
le typage de Python est dynamique donc vous pouvez changer une variable int en chaîne
x = 'somestring'
x = 50
le typage Python est fort donc vous ne pouvez pas fusionner les types:
'x' + 3 --> TypeError: cannot concatenate 'str' and 'int' objects
en Javascript faiblement dactylographié cela arrive...
'x'+3 = 'x3'
Concernant L'Inférence De Type
Java forces vous de déclarer explicitement vos types d'objet
int x = 50
Kotlin utilise l'inférence pour réaliser que c'est un int
x = 50
mais parce que les deux langues utilisent des types statiques, x
ne peut pas être changé d'un int
. Ni l'un ni l'autre ne permettrait un dynamique changement comme
x = 50
x = 'now a string'
je pense, cet exemple simple devrait vous expliquer les différences entre fort et dynamique Dactylographie:
>>> tup = ('1', 1, .1)
>>> for item in tup:
... type(item)
...
<type 'str'>
<type 'int'>
<type 'float'>
>>>
java:
public static void main(String[] args) {
int i = 1;
i = "1"; //will be error
i = '0.1'; // will be error
}
class testme(object):
''' A test object '''
def __init__(self):
self.y = 0
def f(aTestMe1, aTestMe2):
return aTestMe1.y + aTestMe2.y
c = testme #get a variable to the class
c.x = 10 #add an attribute x inital value 10
c.y = 4 #change the default attribute value of y to 4
t = testme() # declare t to be an instance object of testme
r = testme() # declare r to be an instance object of testme
t.y = 6 # set t.y to a number
r.y = 7 # set r.y to a number
print(f(r,t)) # call function designed to operate on testme objects
r.y = "I am r.y" # redefine r.y to be a string
print(f(r,t)) #POW!!!! not good....
ce qui précède créerait un cauchemar de code inaccessible dans un grand système sur une longue période. Appelez cela comme vous voulez, mais la capacité de changer "dynamiquement" un type de variables est juste une mauvaise idée...