Python é fortemente digitado dinamicamente.
- Digitação forte significa que o tipo de um valor não muda de maneira inesperada. Uma string contendo apenas dígitos não se torna magicamente um número, como pode acontecer no Perl. Toda mudança de tipo requer uma conversão explícita.
- A digitação dinâmica significa que os objetos (valores) de tempo de execução têm um tipo, em oposição à digitação estática, onde as variáveis têm um tipo.
Quanto ao seu exemplo
bob = 1
bob = "bob"
Isso funciona porque a variável não possui um tipo; pode nomear qualquer objeto. Depois bob=1
, você verá que type(bob)
retorna int
, mas depois bob="bob"
retorna str
. (Observe que type
é uma função regular, portanto, ele avalia seu argumento e, em seguida, retorna o tipo do valor.)
Compare isso com os dialetos mais antigos de C, que eram fracamente digitados estaticamente, de modo que ponteiros e números inteiros eram praticamente intercambiáveis. (O ISO C moderno requer conversões em muitos casos, mas meu compilador ainda é indulgente com isso por padrão.)
Devo acrescentar que a tipagem forte versus fraca é mais um continuum do que uma escolha booleana. O C ++ possui digitação mais forte que o C (são necessárias mais conversões), mas o sistema de tipos pode ser subvertido usando conversões de ponteiro.
A força do sistema de tipos em uma linguagem dinâmica como Python é realmente determinada pela forma como suas primitivas e funções de biblioteca respondem a diferentes tipos. Por exemplo, +
está sobrecarregado para funcionar em dois números ou duas strings, mas não em uma string e um número. Essa é uma escolha de design feita quando +
foi implementada, mas não é realmente uma necessidade decorrente da semântica da linguagem. De fato, quando você sobrecarrega +
um tipo personalizado, é possível convertê-lo implicitamente em um 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)
A instância da classe Foo
pode ser adicionada a outros objetos:
>>> a = Foo(42)
>>> a + "1"
43.0
>>> a + Foo
42
>>> a + 1
43.0
>>> a + None
42
Observe que, apesar de fortemente tipado Python é completamente bem com a adição de objetos do tipo int
e float
e retorna um objeto do tipo float
(por exemplo, int(42) + float(1)
retornos 43.0
). Por outro lado, devido à incompatibilidade entre os tipos, Haskell se queixaria se alguém tentasse o seguinte (42 :: Integer) + (1 :: Float)
. Isso faz do Haskell uma linguagem estritamente digitada, onde os tipos são totalmente disjuntos e apenas uma forma controlada de sobrecarga é possível através de classes de tipos.
True
ouFalse
. Mas e a promoção de números?1.0 + 2
funciona tão bem em Python quanto em Perl ou C, mesmo que"1.0" + 2
não. Concordo com @jbrendel que essa não é realmente uma conversão implícita, é apenas uma sobrecarga - mas, no mesmo sentido, o Perl também não está fazendo nenhuma conversão implícita. Se as funções não tiverem tipos de parâmetro declarados, não haverá lugar para conversões implícitas.if isValid(value) - 1
pode vazar. O booleano é coagido a um número inteiro, que é então avaliado como um valor de verdade.False - 1
torna-True - 1
se verdadeiro e falso, levando a um erro de duas camadas embaraçosamente difícil de depurar. Nesse sentido, o python é tipicamente fortemente tipado; coerções de tipo geralmente não causam erros lógicos.Há algumas questões importantes que acho que todas as respostas existentes perderam.
Digitação fraca significa permitir acesso à representação subjacente. Em C, posso criar um ponteiro para caracteres e dizer ao compilador que quero usá-lo como ponteiro para números inteiros:
Em uma plataforma little-endian com números inteiros de 32 bits, isso cria
i
uma matriz dos números0x64636261
e0x00676665
. De fato, você pode até converter ponteiros para números inteiros (do tamanho apropriado):E é claro que isso significa que posso substituir a memória em qualquer lugar do sistema. *
* É claro que os sistemas operacionais modernos usam memória virtual e proteção de página para que eu possa sobrescrever a memória do meu próprio processo, mas não há nada no C que ofereça essa proteção, como qualquer pessoa que já tenha codificado, digamos, no Classic Mac OS ou no Win16 pode lhe dizer.
Lisp tradicional permitia tipos semelhantes de hackery; em algumas plataformas, as células flutuantes e contras de duas palavras eram do mesmo tipo, e você poderia simplesmente passar uma para uma função que espera a outra e ela funcionaria.
Atualmente, a maioria dos idiomas não é tão fraca quanto C e Lisp, mas muitos deles ainda são um pouco vazados. Por exemplo, qualquer linguagem OO que tenha um "downcast" desmarcado, * é um vazamento de tipo: você está basicamente dizendo ao compilador "Eu sei que não lhe dei informações suficientes para saber que isso é seguro, mas tenho certeza é "quando o ponto principal de um sistema de tipos é que o compilador sempre tem informações suficientes para saber o que é seguro.
* Um downcast verificado não torna o sistema de tipos do idioma mais fraco apenas porque move a verificação para o tempo de execução. Se isso acontecesse, o subtipo de polimorfismo (também conhecido como chamadas de função virtuais ou totalmente dinâmicas) seria a mesma violação do sistema de tipos, e acho que ninguém quer dizer isso.
Pouquíssimas linguagens de "script" são fracas nesse sentido. Mesmo em Perl ou Tcl, você não pode pegar uma string e apenas interpretar seus bytes como um número inteiro. * Mas vale a pena notar que no CPython (e da mesma forma para muitos outros intérpretes para muitas linguagens), se você é realmente persistente, pode ser usado
ctypes
para carregarlibpython
, converter um objeto emid
aPOINTER(Py_Object)
e forçar o vazamento do sistema de tipos. Se isso enfraquece ou não o sistema de tipos depende de seus casos de uso - se você estiver tentando implementar uma sandbox de execução restrita no idioma para garantir a segurança, precisará lidar com esses tipos de escapes ...* Você pode usar uma função como
struct.unpack
ler os bytes e criar um novo int de "como C representaria esses bytes", mas obviamente isso não é vazado; até Haskell permite isso.Enquanto isso, a conversão implícita é realmente algo diferente de um sistema do tipo fraco ou com vazamento.
Todo idioma, mesmo Haskell, tem funções para, digamos, converter um número inteiro em uma string ou um float. Porém, alguns idiomas farão algumas dessas conversões automaticamente para você - por exemplo, em C, se você chamar uma função que deseja a
float
e passá-laint
, ela será convertida para você. Definitivamente, isso pode levar a erros com, por exemplo, estouros inesperados, mas eles não são os mesmos tipos de erros que você obtém de um sistema de tipos fracos. E C realmente não está sendo mais fraco aqui; você pode adicionar um int e um float no Haskell ou até concatenar um float em uma string, basta fazer isso de forma mais explícita.E com linguagens dinâmicas, isso é bastante obscuro. Não existe algo como "uma função que queira flutuar" em Python ou Perl. Mas existem funções sobrecarregadas que fazem coisas diferentes com tipos diferentes, e há uma forte sensação intuitiva de que, por exemplo, adicionar uma string a outra coisa é "uma função que deseja uma string". Nesse sentido, Perl, Tcl e JavaScript parecem fazer muitas conversões implícitas (
"a" + 1
dá a você"a1"
), enquanto o Python faz muito menos ("a" + 1
gera uma exceção, mas1.0 + 1
dá a você2.0
*). É difícil colocar esse sentido em termos formais - por que não deveria haver um+
que tenha uma string e um int, quando obviamente existem outras funções, como a indexação, que fazem?* Na verdade, no Python moderno, isso pode ser explicado em termos de subtipo OO, pois
isinstance(2, numbers.Real)
é verdade. Eu não acho que exista algum sentido em que2
seja uma instância do tipo string em Perl ou JavaScript ... embora em Tcl, na verdade seja, pois tudo é uma instância de string.Finalmente, há outra definição completamente ortogonal de digitação "forte" vs. "fraca", em que "forte" significa poderoso / flexível / expressivo.
Por exemplo, Haskell permite definir um tipo que é um número, uma sequência, uma lista desse tipo ou um mapa de sequências para esse tipo, que é uma maneira perfeita de representar qualquer coisa que possa ser decodificada no JSON. Não há como definir esse tipo em Java. Mas pelo menos Java possui tipos paramétricos (genéricos), para que você possa escrever uma função que obtenha uma Lista de T e saiba que os elementos são do tipo T; outras linguagens, como o Java inicial, forçaram você a usar uma lista de objetos e fazer o downcast. Mas pelo menos Java permite criar novos tipos com seus próprios métodos; C apenas permite criar estruturas. E o BCPL nem sequer tinha isso. E assim por diante, até a montagem, onde os únicos tipos têm diferentes comprimentos de bits.
Portanto, nesse sentido, o sistema de tipos de Haskell é mais forte que o Java moderno, que é mais forte que o Java anterior, que é mais forte que o C, que é mais forte que o BCPL.
Então, onde o Python se encaixa nesse espectro? Isso é um pouco complicado. Em muitos casos, a digitação com patos permite simular tudo o que você pode fazer em Haskell e até algumas coisas que não pode; Certamente, os erros são detectados no tempo de execução, em vez do tempo de compilação, mas ainda são detectados. No entanto, há casos em que a digitação com patos não é suficiente. Por exemplo, em Haskell, você pode dizer que uma lista vazia de ints é uma lista de ints, para poder decidir que a redução
+
nessa lista deve retornar 0 *; no Python, uma lista vazia é uma lista vazia; não há informações de tipo para ajudá-lo a decidir o que a redução+
deve fazer.* De fato, Haskell não deixa você fazer isso; se você chamar a função de redução que não assume um valor inicial em uma lista vazia, você recebe um erro. Mas seu sistema de tipos é poderoso o suficiente para que você possa fazer isso funcionar, e o Python não é.
fonte
char sz[]
não é um ponteiro para char, é uma matriz de char e, na atribuição, ele se decompõe em ponteiro.Você está confundindo 'digitado fortemente' com 'digitado dinamicamente' .
Não posso alterar o tipo de
1
adição da string'12'
, mas posso escolher quais tipos armazeno em uma variável e alterá-lo durante o tempo de execução do programa.O oposto da digitação dinâmica é a estática; a declaração dos tipos de variáveis não muda durante a vida útil de um programa. O oposto de digitação forte é digitação fraca; o tipo de valores pode mudar durante a vida útil de um programa.
fonte
De acordo com este artigo do wiki do Python, o Python é do tipo dinâmico e fortemente tipado (fornece uma boa explicação também).
Talvez você esteja pensando em linguagens de tipo estaticamente onde os tipos não podem mudar durante a execução do programa e a verificação de tipos ocorre durante o tempo de compilação para detectar possíveis erros.
Esta pergunta do SO pode ser interessante: Linguagens de tipos dinâmicas versus linguagens de tipos estáticas e este artigo da Wikipedia em Sistemas de tipos fornece mais informações
fonte
TLDR;
A digitação do Python é Dinâmica, para que você possa alterar uma variável de string para uma int
A digitação em Python é Forte, portanto você não pode mesclar tipos:
Em Javascript de tipo fraco, isso acontece ...
Em relação à inferência de tipo
Java força você a declarar explicitamente seus tipos de objetos
Kotlin usa inferência para perceber que é um
int
Mas como os dois idiomas usam tipos estáticos ,
x
não pode ser alterado de umint
. Nenhum idioma permitiria uma mudança dinâmica comofonte
'x' + 3
pode estaroperator+
sobrecarregando e fazendo a conversão de tipo nos bastidores?Já foi respondido algumas vezes, mas Python é uma linguagem fortemente tipada:
O seguinte em JavaScript:
Essa é a diferença entre digitação fraca e digitação forte. Tipos fracos tentam converter automaticamente de um tipo para outro, dependendo do contexto (por exemplo, Perl). Tipos fortes nunca se convertem implicitamente.
Sua confusão está em um mal-entendido de como o Python vincula valores a nomes (geralmente chamados de variáveis).
No Python, os nomes não têm tipos, então você pode fazer coisas como:
E os nomes podem ser vinculados a qualquer coisa:
Para leitura adicional:
https://en.wikipedia.org/wiki/Dynamic_dispatch
e os ligeiramente relacionados, mas mais avançados:
http://effbot.org/zone/call-by-object.htm
fonte
"3"*4
em python também. O resultado, claro, é"3333"
. Você não diria que está convertendo qualquer coisa. Claro que isso poderia ser apenas argumentar semântica.float
partir da combinação defloat
eint
que está convertendo o tipo implicitamente. Existe uma relação natural entre float e int e, de fato, a hierarquia de tipos explica isso. Suponho que você possa argumentar que o Javascript considera'3'+4
e'e'+4
ambas são operações bem definidas da mesma maneira que o Python considera3.0 + 4
bem definidas, mas nesse momento não há realmente tipos fortes ou fracos, apenas (des) definidos operações.Uma variável Python armazena uma referência sem tipo para o objeto de destino que representa o valor.
Qualquer operação de atribuição significa atribuir a referência não digitada ao objeto atribuído - ou seja, o objeto é compartilhado através das referências originais e novas (contadas).
O tipo de valor é vinculado ao objeto de destino, não ao valor de referência. A verificação do tipo (forte) é feita quando uma operação com o valor é executada (tempo de execução).
Em outras palavras, as variáveis (tecnicamente) não têm tipo - não faz sentido pensar em termos de um tipo de variável se alguém quiser ser exato. Mas as referências são automaticamente desreferenciadas e, na verdade, pensamos em termos do tipo do objeto de destino.
fonte
O termo "digitação forte" não tem uma definição definida.
Portanto, o uso do termo depende de com quem você está falando.
Não considero nenhum idioma, no qual o tipo de uma variável não seja declarado explicitamente ou digitado estaticamente para ser fortemente digitado.
A digitação forte não exclui apenas a conversão (por exemplo, a conversão "automática" de um número inteiro para uma string). Isso impede a atribuição (ou seja, alterar o tipo de uma variável).
Se o seguinte código for compilado (interpretado), o idioma não será do tipo forte:
Foo = 1 Foo = "1"
Em uma linguagem fortemente tipada, um programador pode "contar" com um tipo.
Por exemplo, se um programador vê a declaração,
UINT64 kZarkCount;
e ele sabe que, 20 linhas depois, o kZarkCount ainda é um UINT64 (desde que ocorra no mesmo bloco) - sem ter que examinar o código intermediário.
fonte
Acabei de descobrir uma excelente maneira concisa de memorizá-lo:
fonte
Eu acho que, neste exemplo simples, você deve explicar as diferenças entre a digitação forte e a dinâmica:
Java:
fonte
O exemplo acima criaria um pesadelo de código impossível de manter em um sistema grande por um longo período. Chame como quiser, mas a capacidade de "dinamicamente" alterar um tipo de variável é apenas uma má idéia ...
fonte