Por que não existem operadores ++
e --
em Python?
Por que não existem operadores ++
e --
em Python?
Respostas:
Não é porque não faz sentido; faz todo o sentido definir "x ++" como "x + = 1, avaliando a ligação anterior de x".
Se você quiser saber o motivo original, precisará percorrer as listas de discussão antigas do Python ou perguntar a alguém que estava lá (por exemplo, Guido), mas é fácil o suficiente para justificar o fato:
Incremento e decremento simples não são necessários tanto quanto em outros idiomas. Você não escreve coisas como for(int i = 0; i < 10; ++i)
em Python com muita frequência; em vez disso, você faz coisas como for i in range(0, 10)
.
Como não é necessário com tanta frequência, há muito menos motivos para fornecer a sua própria sintaxe especial; quando você precisa incrementar, +=
geralmente está bem.
Não é uma decisão sobre se faz sentido ou se pode ser feito - faz e pode. É uma questão de saber se vale a pena adicionar o benefício à sintaxe principal do idioma. Lembre-se, são quatro operadores - postinc, postdec, preinc, predec, e cada um deles precisa ter suas próprias sobrecargas de classe; todos precisam ser especificados e testados; adicionaria opcodes ao idioma (implicando um mecanismo VM maior e, portanto, mais lento); toda classe que suporta um incremento lógico precisaria implementá-las (em cima +=
e -=
).
Tudo isso é redundante +=
e -=
, portanto, se tornaria uma perda líquida.
i
diretamente - se você realmente precisa dele e não pode simplesmente por exemplo, usoarray.append()
i++
e ++i
...
++
e --
é usado de maneiras que resultam em indefinidas ou não especificadas comportamento. Eles tornam possível escrever código complicado e difícil de analisar corretamente.
Esta resposta original que escrevi é um mito do folclore da computação : desmembrado por Dennis Ritchie como "historicamente impossível", conforme observado nas cartas aos editores de Comunicações da ACM de julho de 2012 doi: 10.1145 / 2209249.2209251
Os operadores de incremento / decremento de C foram inventados em um momento em que o compilador C não era muito inteligente e os autores queriam especificar a intenção direta de que um operador de linguagem de máquina deveria ser usado, o que economizava alguns ciclos para um compilador que pode fazer um
load memory
load 1
add
store memory
ao invés de
inc memory
e o PDP-11 até suportava instruções de "incremento automático" e "adiamento automático de adiamento" correspondentes a *++p
e *p++
, respectivamente. Veja a seção 5.3 do manual, se for terrivelmente curioso.
Como os compiladores são inteligentes o suficiente para lidar com os truques de otimização de alto nível incorporados na sintaxe de C, agora são apenas uma conveniência sintática.
O Python não possui truques para transmitir intenções ao assembler porque ele não usa um.
Eu sempre assumi que tinha a ver com esta linha do zen de python:
Deve haver uma - e preferencialmente apenas uma - maneira óbvia de fazê-lo.
x ++ e x + = 1 fazem exatamente a mesma coisa, portanto não há razão para ter os dois.
one--
é zero?
one--
é um na frase, mas zero imediatamente depois. Portanto, esse 'koan' também sugere que os operadores de incremento / decremento não são óbvios.
É claro que poderíamos dizer "Guido acabou de decidir dessa maneira", mas acho que a pergunta é realmente sobre os motivos dessa decisão. Eu acho que existem várias razões:
Porque, em Python, números inteiros são imutáveis (int's + = realmente retorna um objeto diferente).
Além disso, com ++ / - você precisa se preocupar com pré e pós-incremento / decremento, e é preciso apenas mais um pressionamento de tecla para escrever x+=1
. Em outras palavras, evita possíveis confusões à custa de muito pouco ganho.
42++
... Algo assim (modificar uma constante literal) era realmente possível em alguns compiladores Fortran antigos (ou pelo menos eu li): Todos os usos futuros desse literal nessa execução do programa teria realmente um valor diferente. Feliz depuração!
int
em geral são imutáveis. Um int
em C simplesmente designa um lugar na memória. E os bits nesse lugar são muito mutáveis. Você pode, por exemplo, criar uma referência de int
e alterar o referente dessa referência. Essa alteração é visível em todas as referências (incluindo a int
variável original ) a esse local. O mesmo não se aplica a um objeto inteiro Python.
Python tem muito a ver com clareza e é provável que nenhum programador adivinhe corretamente o significado, a --a
menos que tenha aprendido uma linguagem com essa construção.
O Python também trata muito de evitar construções que causam erros e os ++
operadores são conhecidos por serem fontes ricas de defeitos. Esses dois motivos são suficientes para não ter esses operadores em Python.
A decisão de que o Python usa indentação para marcar blocos em vez de meios sintáticos, como alguma forma de bracketing de início / fim ou marcação final obrigatória, baseia-se amplamente nas mesmas considerações.
Por exemplo, dê uma olhada na discussão sobre a introdução de um operador condicional (em C cond ? resultif : resultelse
:) no Python em 2005. Leia pelo menos a primeira mensagem e a mensagem de decisão dessa discussão (que tinha vários precursores no mesmo tópico anteriormente).
Curiosidades: O PEP freqüentemente mencionado nele é o "Python Extension Proposal" PEP 308 . LC significa compreensão de lista , GE significa expressão de gerador (e não se preocupe se isso o confunde, eles não são um dos poucos pontos complicados de Python).
Meu entendimento sobre por que python não possui ++
operador é o seguinte: Quando você escreve isso em python, a=b=c=1
você obtém três variáveis (rótulos) apontando para o mesmo objeto (cujo valor é 1). Você pode verificar isso usando a função id, que retornará um endereço de memória do objeto:
In [19]: id(a)
Out[19]: 34019256
In [20]: id(b)
Out[20]: 34019256
In [21]: id(c)
Out[21]: 34019256
Todas as três variáveis (rótulos) apontam para o mesmo objeto. Agora incremente uma variável e veja como isso afeta os endereços de memória:
In [22] a = a + 1
In [23]: id(a)
Out[23]: 34019232
In [24]: id(b)
Out[24]: 34019256
In [25]: id(c)
Out[25]: 34019256
Você pode ver que a variável a
agora aponta para outro objeto como variáveis b
e c
. Porque você usou a = a + 1
, é explicitamente claro. Em outras palavras, você atribui completamente outro objeto ao rótulo a
. Imagine que você pode escrevê- a++
lo, sugerindo que você não atribuiu à variável a
novo objeto, mas o classificador incrementou o antigo. Todo esse material é IMHO para minimizar a confusão. Para uma melhor compreensão, veja como as variáveis python funcionam:
Python é chamada por valor ou chamada por referência? Nem.
O Python passa por valor ou por referência?
O Python passa por referência ou passa por valor?
Python: Como passo uma variável por referência?
Noções básicas sobre variáveis Python e gerenciamento de memória
Emulando o comportamento de passagem por valor em python
Foi apenas projetado dessa maneira. Os operadores de incremento e decremento são apenas atalhos para x = x + 1
. O Python normalmente adotou uma estratégia de design que reduz o número de meios alternativos de executar uma operação. A atribuição aumentada é a coisa mais próxima dos operadores de incremento / decremento no Python, e eles nem foram adicionados até o Python 2.0.
return a[i++]
com return a[i=i+1]
.
Eu sou muito novo em python, mas suspeito que o motivo seja a ênfase entre objetos mutáveis e imutáveis na linguagem. Agora, eu sei que x ++ pode ser facilmente interpretado como x = x + 1, mas parece que você está incrementando no local um objeto que pode ser imutável.
Apenas meu palpite / sentimento / palpite.
x++
está mais próximo do x += 1
que x = x + 1
, esses dois fazendo a diferença também em objetos mutáveis.
Primeiro, Python é indiretamente influenciado por C; ele é fortemente influenciado pelo ABC , que aparentemente não possui esses operadores , portanto não deve ser uma grande surpresa não encontrá-los no Python.
Em segundo lugar, como já foi dito, o incremento e o decréscimo são suportados +=
e -=
já.
Em terceiro lugar, suporte completo para um ++
e--
conjunto de operadores normalmente inclui o suporte das versões de prefixo e postfix deles. Em C e C ++, isso pode levar a todos os tipos de construções "adoráveis" que parecem (para mim) contrariar o espírito de simplicidade e franqueza que o Python adota.
Por exemplo, enquanto a instrução C while(*t++ = *s++);
pode parecer simples e elegante para um programador experiente, para alguém aprendendo, é tudo menos simples. Coloque uma mistura de incrementos e decrementos de prefixo e postfix, e até muitos profissionais terão que parar e pensar um pouco.
Eu acredito que deriva do credo Python de que "explícito é melhor que implícito".
Isso pode ser porque o @GlennMaynard está encarando o problema como em comparação com outras linguagens, mas no Python, você faz as coisas da maneira python. Não é uma pergunta do "por quê". Está lá e você pode fazer as coisas com o mesmo efeito x+=
. No Zen de Python , é apresentado: "deve haver apenas uma maneira de resolver um problema". Várias opções são ótimas em arte (liberdade de expressão), mas péssimas em engenharia.
A ++
classe de operadores são expressões com efeitos colaterais. Isso geralmente não é encontrado no Python.
Pela mesma razão, uma atribuição não é uma expressão em Python, impedindo o if (a = f(...)) { /* using a here */ }
idioma comum .
Por fim, suspeito que o operador não seja muito consistente com a semântica de referência de Pythons. Lembre-se, o Python não possui variáveis (ou ponteiros) com a semântica conhecida em C / C ++.
f(a)
onde a
está uma lista, algum objeto imutável.
Talvez uma pergunta melhor seria perguntar por que esses operadores existem em C. A K&R chama os operadores de incremento e decremento de "incomuns" (Seção 2.8, página 46). A introdução os chama de 'mais concisos e frequentemente mais eficientes'. Suspeito que o fato de que essas operações sempre ocorram na manipulação de ponteiros também tenha contribuído para sua introdução. No Python, provavelmente foi decidido que não fazia sentido tentar otimizar incrementos (na verdade, eu apenas fiz um teste em C, e parece que o assembly gerado pelo gcc usa addl em vez de incl nos dois casos) e não há ponteiro aritmético; então seria apenas mais uma maneira de fazer isso e sabemos que o Python detesta isso.
como eu entendi para que você não pense que o valor na memória é alterado. em c quando você faz x ++, o valor de x na memória é alterado. mas em python todos os números são imutáveis, portanto, o endereço que x apontou como ainda tem x não x + 1. quando você escreve x ++, você pensa que x muda o que realmente acontece é que x referência é alterada para um local na memória em que x + 1 é armazenado ou recria esse local se não existir.
++
e diferente += 1
?
Para concluir as boas respostas nessa página:
Vamos supor que decidimos fazer isso, prefixo ( ++i
) que quebraria os operadores + e - unários.
Hoje, prefixar ++
ou --
não faz nada, porque habilita o operador unário mais duas vezes (não faz nada) ou unário menos duas vezes (duas vezes: se cancela)
>>> i=12
>>> ++i
12
>>> --i
12
Então isso potencialmente quebraria essa lógica.
Outras respostas descreveram por que não é necessário para iteradores, mas às vezes é útil ao atribuir para aumentar uma variável em linha, você pode obter o mesmo efeito usando tuplas e várias atribuições:
b = ++a
torna-se:
a,b = (a+1,)*2
e b = a++
se torna:
a,b = a+1, a
Python 3.8 introduz o :=
operador de atribuição , permitindo-nos alcançar foo(++a)
com
foo(a:=a+1)
foo(a++)
ainda é indescritível.
Eu acho que isso se relaciona com os conceitos de mutabilidade e imutabilidade de objetos. 2,3,4,5 são imutáveis em python. Consulte a imagem abaixo. 2 corrigiu o ID até esse processo python.
x ++ significaria essencialmente um incremento no local como C. Em C, x ++ executa incrementos no local. Portanto, x = 3 e x ++ aumentariam 3 na memória para 4, ao contrário do python em que 3 ainda existiriam na memória.
Assim, em python, você não precisa recriar um valor na memória. Isso pode levar a otimizações de desempenho.
Esta é uma resposta baseada em palpites.
Eu sei que esse é um encadeamento antigo, mas o caso de uso mais comum do ++ i não é abordado, sendo a indexação manual definida quando não há índices fornecidos. Esta situação é a razão pela qual o python fornece enumerate ()
Exemplo: em qualquer idioma, quando você usa uma construção como foreach para iterar um conjunto - pelo exemplo, diremos até que é um conjunto não ordenado e você precisa de um índice exclusivo para que tudo possa diferenciá-los, digamos
i = 0
stuff = {'a': 'b', 'c': 'd', 'e': 'f'}
uniquestuff = {}
for key, val in stuff.items() :
uniquestuff[key] = '{0}{1}'.format(val, i)
i += 1
Em casos como esse, o python fornece um método enumerado, por exemplo
for i, (key, val) in enumerate(stuff.items()) :