Python está fuertemente tipado dinámicamente.
- Una escritura fuerte significa que el tipo de un valor no cambia de manera inesperada. Una cadena que contiene solo dígitos no se convierte mágicamente en un número, como puede suceder en Perl. Cada cambio de tipo requiere una conversión explícita.
- La tipificación dinámica significa que los objetos de tiempo de ejecución (valores) tienen un tipo, a diferencia de la tipificación estática donde las variables tienen un tipo.
En cuanto a tu ejemplo
bob = 1
bob = "bob"
Esto funciona porque la variable no tiene un tipo; Puede nombrar cualquier objeto. Después bob=1
, encontrarás que type(bob)
vuelve int
, pero después bob="bob"
, vuelve str
. (Tenga en cuenta que type
es una función regular, por lo que evalúa su argumento y luego devuelve el tipo del valor).
Contraste esto con los dialectos más antiguos de C, que eran débilmente, tipados estáticamente, de modo que los punteros y los enteros eran prácticamente intercambiables. (La ISO C moderna requiere conversiones en muchos casos, pero mi compilador todavía es indulgente con esto de forma predeterminada).
Debo agregar que la tipificación fuerte frente a débil es más un continuo que una elección booleana. C ++ tiene una escritura más fuerte que C (se requieren más conversiones), pero el sistema de tipos se puede subvertir mediante el uso de conversiones de puntero.
La fuerza del sistema de tipos en un lenguaje dinámico como Python está realmente determinada por cómo sus primitivas y funciones de biblioteca responden a diferentes tipos. Por ejemplo, +
está sobrecargado para que funcione en dos números o dos cadenas, pero no en una cadena y un número. Esta es una elección de diseño realizada cuando +
se implementó, pero no es realmente una necesidad derivada de la semántica del lenguaje. De hecho, cuando se sobrecarga +
en un tipo personalizado, puede convertirlo implícitamente en un número:
def to_number(x):
"""Try to convert function argument to float-type object."""
try:
return float(x)
except (TypeError, ValueError):
return 0
class Foo:
def __init__(self, number):
self.number = number
def __add__(self, other):
return self.number + to_number(other)
La instancia de clase Foo
se puede agregar a otros objetos:
>>> a = Foo(42)
>>> a + "1"
43.0
>>> a + Foo
42
>>> a + 1
43.0
>>> a + None
42
Observe que aunque fuertemente tipado Python es completamente bien con la adición de objetos del tipo int
y float
y devuelve un objeto de tipo float
(por ejemplo, int(42) + float(1)
rendimientos 43.0
). Por otro lado, debido a la falta de coincidencia entre los tipos, Haskell se quejaría si uno intenta lo siguiente (42 :: Integer) + (1 :: Float)
. Esto convierte a Haskell en un lenguaje estrictamente tipado, donde los tipos son completamente disjuntos y solo es posible una forma controlada de sobrecarga a través de las clases de tipos.
True
oFalse
. ¿Pero qué pasa con la promoción de números?1.0 + 2
funciona igual de bien en Python que en Perl o C, aunque"1.0" + 2
no lo hace. Estoy de acuerdo con @jbrendel en que esta no es realmente una conversión implícita, es solo una sobrecarga, pero en el mismo sentido, Perl tampoco está haciendo ninguna conversión implícita. Si las funciones no tienen tipos de parámetros declarados, no hay lugar para que ocurran conversiones implícitas.if isValid(value) - 1
puede perderse un accidente . El booleano se convierte en entero, que luego se evalúa como un valor verdadero.False - 1
se vuelve verdadero yTrue - 1
falso, lo que lleva a un error de dos capas vergonzosamente difícil de depurar. En este sentido, python es principalmente fuertemente tipado; Las coacciones de tipo no suelen causar errores lógicos.Hay algunos problemas importantes que creo que se han perdido todas las respuestas existentes.
La escritura débil significa permitir el acceso a la representación subyacente. En C, puedo crear un puntero a caracteres, luego decirle al compilador que quiero usarlo como puntero a enteros:
En una plataforma little endian con enteros de 32 bits, esto se convierte
i
en una matriz de números0x64636261
y0x00676665
. De hecho, incluso puede lanzar punteros a números enteros (del tamaño apropiado):Y, por supuesto, esto significa que puedo sobrescribir la memoria en cualquier parte del sistema. *
* Por supuesto, los sistemas operativos modernos usan memoria virtual y protección de página, por lo que solo puedo sobrescribir la memoria de mi propio proceso, pero no hay nada en C que ofrezca tal protección, como cualquiera que haya codificado, por ejemplo, Classic Mac OS o Win16 puede decirte.
Lisp tradicional permitió tipos similares de piratería informática; en algunas plataformas, las celdas flotantes de doble palabra y las contras eran del mismo tipo, y podría pasar una a una función esperando la otra y "funcionaría".
La mayoría de los lenguajes de hoy en día no son tan débiles como lo fueron C y Lisp, pero muchos de ellos todavía son algo permeables. Por ejemplo, cualquier lenguaje OO que tenga un "downcast" no verificado, * es una filtración de tipo: esencialmente le está diciendo al compilador "Sé que no le di suficiente información para saber que esto es seguro, pero estoy bastante seguro es "cuando el objetivo de un sistema de tipos es que el compilador siempre tenga suficiente información para saber qué es seguro.
* Un downcast verificado no hace que el sistema de tipos de lenguaje sea más débil simplemente porque mueve la verificación al tiempo de ejecución. Si lo hiciera, entonces el polimorfismo de subtipo (también conocido como llamadas a funciones virtuales o completamente dinámicas) sería la misma violación del sistema de tipos, y no creo que nadie quiera decir eso.
Muy pocos lenguajes de "scripting" son débiles en este sentido. Incluso en Perl o Tcl, no puede tomar una cadena y simplemente interpretar sus bytes como un entero. * Pero vale la pena señalar que en CPython (y de manera similar para muchos otros intérpretes para muchos idiomas), si es realmente persistente, usted puede usar
ctypes
para cargarlibpython
, lanzar un objetoid
a unPOINTER(Py_Object)
y forzar la fuga del sistema de tipos. Si esto debilita o no el sistema de tipos depende de sus casos de uso: si está tratando de implementar un entorno limitado de ejecución restringido en el idioma para garantizar la seguridad, tiene que lidiar con este tipo de escapes ...* Puede usar una función como
struct.unpack
leer los bytes y construir un nuevo int a partir de "cómo representaría C estos bytes", pero eso obviamente no tiene fugas; incluso Haskell lo permite.Mientras tanto, la conversión implícita es realmente algo diferente de un sistema de tipo débil o con fugas.
Cada idioma, incluso Haskell, tiene funciones para, por ejemplo, convertir un número entero en una cadena o un flotante. Pero algunos lenguajes realizarán automáticamente algunas de esas conversiones; por ejemplo, en C, si llama a una función que quiere un
float
y lo pasaint
, se convierte por usted. Esto definitivamente puede conducir a errores con, por ejemplo, desbordamientos inesperados, pero no son los mismos tipos de errores que se obtienen de un sistema de tipo débil. Y C no está siendo realmente más débil aquí; puedes agregar un int y un float en Haskell, o incluso concatenar un float en una cadena, solo tienes que hacerlo más explícitamente.Y con lenguajes dinámicos, esto es bastante turbio. No hay tal cosa como "una función que quiera un flotador" en Python o Perl. Pero hay funciones sobrecargadas que hacen cosas diferentes con diferentes tipos, y hay una fuerte sensación intuitiva de que, por ejemplo, agregar una cadena a otra cosa es "una función que quiere una cadena". En ese sentido, Perl, Tcl y JavaScript parecen hacer muchas conversiones implícitas (
"a" + 1
le da"a1"
), mientras que Python hace mucho menos ("a" + 1
genera una excepción, pero1.0 + 1
le da2.0
*). Es difícil poner ese sentido en términos formales: ¿por qué no debería haber un+
que tome una cadena y un int, cuando obviamente hay otras funciones, como la indexación, que sí?* En realidad, en Python moderno, eso puede explicarse en términos de subtipo OO, ya que
isinstance(2, numbers.Real)
es cierto. No creo que tenga sentido que2
sea una instancia del tipo de cadena en Perl o JavaScript ... aunque en Tcl, en realidad lo es, ya que todo es una instancia de cadena.Finalmente, hay otra definición, completamente ortogonal, de mecanografía "fuerte" frente a "débil", donde "fuerte" significa poderoso / flexible / expresivo.
Por ejemplo, Haskell le permite definir un tipo que es un número, una cadena, una lista de este tipo o un mapa de cadenas a este tipo, que es una manera perfecta de representar cualquier cosa que pueda decodificarse desde JSON. No hay forma de definir ese tipo en Java. Pero al menos Java tiene tipos paramétricos (genéricos), por lo que puede escribir una función que tome una Lista de T y saber que los elementos son de tipo T; otros lenguajes, como los primeros Java, lo obligaron a usar una Lista de objetos y bajarlos. Pero al menos Java le permite crear nuevos tipos con sus propios métodos; C solo te permite crear estructuras. Y BCPL ni siquiera tenía eso. Y así sucesivamente hasta el ensamblaje, donde los únicos tipos son diferentes longitudes de bits.
Entonces, en ese sentido, el sistema de tipos de Haskell es más fuerte que el de Java moderno, que es más fuerte que el de Java anterior, que es más fuerte que el de C, que es más fuerte que el de BCPL.
Entonces, ¿dónde encaja Python en ese espectro? Eso es un poco complicado. En muchos casos, la escritura de pato le permite simular todo lo que puede hacer en Haskell e incluso algunas cosas que no puede hacer; claro, los errores se detectan en tiempo de ejecución en lugar de tiempo de compilación, pero aún se detectan. Sin embargo, hay casos en los que la escritura de patos no es suficiente. Por ejemplo, en Haskell, puede decir que una lista vacía de entradas es una lista de entradas, por lo que puede decidir que reducir
+
sobre esa lista debería devolver 0 *; en Python, una lista vacía es una lista vacía; no hay información de tipo que lo ayude a decidir qué reducción+
debería hacer.* De hecho, Haskell no te deja hacer esto; Si llama a la función de reducción que no toma un valor de inicio en una lista vacía, obtendrá un error. Sin embargo, su sistema de tipos es lo suficientemente potente que podría hacer este trabajo, y Python no lo es.
fuente
char sz[]
no es un puntero a char, es una matriz de char, y en la asignación se descompone en puntero.Está confundiendo 'fuertemente tipado' con 'tipeado dinámicamente' .
No puedo cambiar el tipo
1
agregando la cadena'12'
, pero puedo elegir qué tipos almaceno en una variable y cambiar eso durante el tiempo de ejecución del programa.Lo contrario de la escritura dinámica es la escritura estática; La declaración de tipos de variables no cambia durante la vida útil de un programa. Lo contrario de escribir fuerte es escribir débil; El tipo de valores puede cambiar durante la vida útil de un programa.
fuente
De acuerdo con este artículo de Python wiki, Python tiene un tipo dinámico y fuerte (también proporciona una buena explicación).
Quizás esté pensando en lenguajes tipados estáticamente donde los tipos no pueden cambiar durante la ejecución del programa y la verificación de tipos ocurre durante el tiempo de compilación para detectar posibles errores.
Esta pregunta SO podría ser de interés: los lenguajes de tipo dinámico versus los lenguajes de tipo estático y este artículo de Wikipedia sobre sistemas de tipos proporciona más información
fuente
TLDR;
La escritura de Python es dinámica, por lo que puede cambiar una variable de cadena a un int
La escritura en Python es fuerte, por lo que no puede combinar tipos:
En Javascript débilmente tipado esto sucede ...
En cuanto a la inferencia de tipos
Java te obliga a declarar explícitamente tus tipos de objeto
Kotlin usa la inferencia para darse cuenta de que es un
int
Pero debido a que ambos idiomas usan tipos estáticos ,
x
no se pueden cambiar de unint
. Ninguno de los dos idiomas permitiría un cambio dinámico comofuente
'x' + 3
puede estaroperator+
sobrecargando y haciendo la conversión de tipo detrás de escena.Ya ha sido respondido varias veces, pero Python es un lenguaje fuertemente tipado:
Lo siguiente en JavaScript:
Esa es la diferencia entre escribir débil y escribir fuerte. Los tipos débiles intentan convertir automáticamente de un tipo a otro, dependiendo del contexto (por ejemplo, Perl). Los tipos fuertes nunca se convierten implícitamente.
Su confusión radica en un malentendido de cómo Python une los valores a los nombres (comúnmente conocidos como variables).
En Python, los nombres no tienen tipos, por lo que puede hacer cosas como:
Y los nombres pueden estar vinculados a cualquier cosa:
Para más lectura:
https://en.wikipedia.org/wiki/Dynamic_dispatch
y el poco relacionado pero más avanzado:
http://effbot.org/zone/call-by-object.htm
fuente
"3"*4
en python. El resultado, por supuesto, es"3333"
. No dirías que está convirtiendo ninguna de las dos cosas. Por supuesto, eso podría ser solo discutir la semántica.float
fuera de la combinación defloat
yint
que está convirtiendo el tipo implícitamente. Existe una relación natural entre float e int, y de hecho, la jerarquía de tipos lo explica. Supongo que se podría argumentar que Javascript considera'3'+4
y'e'+4
que ambas son operaciones bien definidas de la misma manera que Python considera3.0 + 4
que están bien definidas, pero en ese momento, en realidad, no existen los tipos fuertes o débiles, simplemente (no) definidos operacionesUna variable de Python almacena una referencia sin tipo al objeto de destino que representa el valor.
Cualquier operación de asignación significa asignar la referencia sin tipo al objeto asignado, es decir, el objeto se comparte a través de las referencias originales y nuevas (contadas).
El tipo de valor está vinculado al objeto de destino, no al valor de referencia. La verificación de tipo (fuerte) se realiza cuando se realiza una operación con el valor (tiempo de ejecución).
En otras palabras, las variables (técnicamente) no tienen tipo: no tiene sentido pensar en términos de un tipo de variable si se quiere ser exacto. Pero las referencias se desreferencian automáticamente y realmente pensamos en términos del tipo del objeto de destino.
fuente
El término "mecanografía fuerte" no tiene una definición definida.
Por lo tanto, el uso del término depende de con quién está hablando.
No considero ningún lenguaje, en el que el tipo de una variable no se declare explícitamente o se escriba de forma estática para que se escriba con fuerza.
La escritura fuerte no solo impide la conversión (por ejemplo, la conversión "automática" de un entero a una cadena). Impide la asignación (es decir, cambiar el tipo de una variable).
Si el siguiente código compila (interpreta), el idioma no es de tipo fuerte:
Foo = 1 Foo = "1"
En un lenguaje fuertemente tipado, un programador puede "contar" con un tipo.
Por ejemplo, si un programador ve la declaración,
UINT64 kZarkCount;
y él o ella sabe que 20 líneas más tarde, kZarkCount sigue siendo un UINT64 (siempre que ocurra en el mismo bloque), sin tener que examinar el código intermedio.
fuente
Acabo de descubrir una excelente forma concisa de memorizarlo:
fuente
Creo que este simple ejemplo debería explicar las diferencias entre tipeo fuerte y dinámico:
Java:
fuente
Lo anterior crearía una pesadilla de código inmanejable en un sistema grande durante un largo período de tiempo. Llámalo como quieras, pero la capacidad de cambiar "dinámicamente" un tipo de variables es solo una mala idea ...
fuente