Por que não existem operadores ++ e - em Python?


Respostas:


443

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.


98
Muitas vezes, é útil usar algo como array [i ++], que não é feito com arrumação + = / - =.
Turner Hayes

102
@ thayes: Esse não é um padrão comum em Python.
Glenn Maynard

9
@thayes Desde que será dentro de um loop, assim como você pode varrer idiretamente - se você realmente precisa dele e não pode simplesmente por exemplo, usoarray.append()
Tobias KIENZLER

31
Eu vejo a preocupação muito maior sendo legibilidade e previsibilidade. Para trás em meus dias C, vi mais do que erros suficientes decorrentes de mal-entendidos sobre a distinção entre i++e ++i...
Charles Duffy

5
Além de justificar o pós-fato: em um projeto em que trabalho, encontrei (mais do que qualquer pessoa deveria na vida) uma quantidade razoável de código C ++ que sofre de problemas ++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.
Brian Vandenberg

84

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 *++pe *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.


4
Javascript possui ++. Eu não acho que seja um "truque para transmitir intenções ao montador". Além disso, o Python possui bytecode. Então eu acho que o motivo é outra coisa.
Nathan Davis

13
Esse negócio de "fornecer dicas para o compilador" é realmente um mito. Francamente, é uma adição tola a qualquer idioma e viola os dois seguintes preceitos: 1. Você não codifica para o computador ler, codifica para outro engenheiro ler. E 2. Você não codifica para um engenheiro competente ler, você codifica para um engenheiro competente ler enquanto estiver exausto às 3 da manhã e consumido cafeína.

3
@ tgm1024 Para ser justo, ao codificar um teletipo half-duplex de 10 a 30 caracteres por segundo, você codifica para poder digitá-lo antes da próxima semana.
msw

4
@ tgm1024 O Unix e C viram a maior parte de seu desenvolvimento inicial nos PDP-11, que usavam teletipos incrivelmente lentos para a comunicação do usuário. Enquanto você está certo de que hoje a codificação da máquina é basicamente boba, naquela época era a interface Homem / Máquina que era o gargalo. É difícil imaginar trabalhar tão devagar se você nunca precisou.
msw

65

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.


10
one--é zero?
111313 Andre Holzner

25
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.
Victor K

14
@EralpB Se você excluir + =, não poderá fazer coisas como x + = 10. + = é um caso mais geral de ++
Rory

8
Além disso: "Explícito é melhor que implícito".
12/0214

2
Definitivamente não é o mesmo, porque x + = 1 NÃO é uma expressão - é uma afirmação - e não é avaliada em nada. Você não pode fazer coisas como: 'row [col ++] = a; linha [col ++] = b '. Sem mencionar o material pré-inc e pós-inc que o c ++ possui.
Uri

38

É 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:

  • Ele combina declarações e expressões, o que não é uma boa prática. Consulte http://norvig.com/python-iaq.html
  • Geralmente, incentiva as pessoas a escreverem códigos menos legíveis
  • Complexidade extra na implementação da linguagem, desnecessária no Python, como já mencionado

12
Ainda bem que alguém finalmente mencionou o aspecto da afirmação vs expressão. Em C, a atribuição é uma expressão e, portanto, o operador ++. No Python, a atribuição é uma declaração; portanto, se tivesse um ++, provavelmente também seria uma declaração de atribuição (e ainda menos útil ou necessária).
martineau

Concordado - se fossem declarações, então, no mínimo, seria absolutamente sem sentido falar sobre a diferença entre pós e pré-operadores.
Crowman 17/07/2013

17

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.


ints também são imutáveis ​​em C. Se você não acha, tente fazer com que seu compilador C gere código para 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!
Lutz Prechelt

10
Direita. 42 é uma constante literal . As constantes são (ou pelo menos deveriam ser) imutáveis. Isso não significa que Cs intem geral são imutáveis. Um intem 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 inte alterar o referente dessa referência. Essa alteração é visível em todas as referências (incluindo a intvariável original ) a esse local. O mesmo não se aplica a um objeto inteiro Python.
Nathan Davis

x + = 1 não acaba se tornando inc mem. Python executa uma chamada de função para adicionar 1 a uma variável; é patético.
PalaDolphin 23/02

12

Clareza!

Python tem muito a ver com clareza e é provável que nenhum programador adivinhe corretamente o significado, a --amenos 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).


10

Meu entendimento sobre por que python não possui ++operador é o seguinte: Quando você escreve isso em python, a=b=c=1você 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 aagora aponta para outro objeto como variáveis be 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 anovo 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:

No Python, por que uma função pode modificar alguns argumentos como percebidos pelo chamador, mas não outros?

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

Chamada de funções Python por referência

Código Como um Pythonista: Python Idiomatic


9

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.


3
Sim companheiro, como, você poderia substituir return a[i++]com return a[i=i+1].
Luís de Sousa

7

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.


Nesse aspecto, x++está mais próximo do x += 1que x = x + 1, esses dois fazendo a diferença também em objetos mutáveis.
glglgl

4

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.


3

Eu acredito que deriva do credo Python de que "explícito é melhor que implícito".


Bem, você não escreve explicitamente instruções "begin" e "end" em Python, certo? Mesmo que eu concorde com a afirmação, acho que há limites para isso. Embora possamos argumentar sobre essas fronteiras, acho que todos podemos concordar, que existe uma linha que é impraticável de ultrapassar. E como existem tantas opiniões e justificativas sobre essa decisão, não acho que tenha sido uma escolha clara. Pelo menos, eu não posso encontrar uma fonte, onde é declarado explicitamente
Hasan Ammori

3

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.


2

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 ++.


1
nada impede de chamar uma função com efeito colateral na compreensão de teste / expressão / lista: f(a)onde aestá uma lista, algum objeto imutável.
Jean-François Fabre

1

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.


1

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.


1
Então, o que faz isso ++e diferente += 1?
120014

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.


1

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.


2
: = atribuição é uma vergonha
nehem

0

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.

ID de constantes e variáveis

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.


0

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()) :
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.