Zachowanie operatorów increment i decrement w Pythonie
Zauważyłem, że operator pre-increment / decrement może być zastosowany na zmiennej (np. ++count
). Kompiluje, ale w rzeczywistości nie zmienia wartości zmiennej!
Jakie jest zachowanie operatorów pre-increment/decrement ( ++ / -- ) w Pythonie?
Dlaczego Python różni się od zachowania tych operatorów widzianych w C / C++?
6 answers
++
nie jest operatorem. Jest to dwa operatory +
. Operator +
jest operatoremtożsamości , który nic nie robi. (Wyjaśnienie: operatory +
i -
jednoargumentowe działają tylko na liczbach, ale zakładam, że nie spodziewałbyś się, że hipotetyczny operator ++
będzie pracował na łańcuchach.)
++count
Parsuje jako
+(+count)
Co tłumaczy się na
count
Musisz użyć nieco dłuższego operatora +=
, aby zrobić to, co chcesz zrobić:
count += 1
I podejrzewam, że operatory ++
i --
zostały pominięte dla spójności i prostoty. Nie znam dokładnego argumentu Guido van Rossum, ale mogę sobie wyobrazić kilka argumentów: {]}
- prostsze parsowanie. Technicznie, parsowanie
++count
jest niejednoznaczne, gdyż może być+
,+
,count
(dwa uniary+
operatory) tak łatwo, jak to możliwe++
,count
(jeden operator unary++
). Nie jest to znacząca wieloznaczność składniowa, ale istnieje. - język.
++
jest niczym więcej niż synonimem+= 1
. Był to skrót wymyślony, ponieważ kompilatory C były głupie i nie wiedziały, jak zoptymalizowaća += 1
do instrukcjiinc
, którą posiada większość komputerów. W dzisiejszych czasach optymalizacji kompilatorów i języków interpretowanych bajtowo, dodawanie operatorów do języka, aby umożliwić programistom optymalizację kodu, jest zwykle mile widziane, szczególnie w języku takim jak Python, który został zaprojektowany tak, aby był spójny i czytelny. - skutki uboczne. Jednym z częstych błędów początkujących w językach z operatorami
++
jest mieszanie różnic (zarówno w pierwszeństwie, jak i w wartości zwrotnej) między operatorami pre - i post-increment/decrement, a Python lubi eliminować języki "gotcha"-s. problemy z pierwszeństwem z pre-/post-increment w C są dość Owłosione i niesamowicie łatwe do namieszania.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-24 15:00:26
Gdy chcesz zwiększyć lub zmniejszyć, Zwykle chcesz to zrobić na liczbie całkowitej. Tak:
b++
Ale w Pythonie liczby całkowite są niezmienne. Nie możesz ich zmienić. Dzieje się tak dlatego, że obiekty integer mogą być używane pod kilkoma nazwami. Spróbuj tego:
>>> b = 5
>>> a = 5
>>> id(a)
162334512
>>> id(b)
162334512
>>> a is b
True
A i B powyżej to w rzeczywistości ten sam obiekt. Jeśli zwiększysz a, zwiększysz również b. to nie jest to, czego chcesz. Więc musisz zmienić przydział. Tak:
b = b + 1
Lub prostsze:
b += 1
, który zmieni b
na b+1
. Nie jest to operator inkrementacji, ponieważ nie inkrementuje b
, lecz przypisuje go.
W skrócie: Python zachowuje się tutaj inaczej, ponieważ nie jest to C i nie jest niskopoziomowym opakowaniem wokół kodu maszynowego, ale dynamicznym językiem wysokiego poziomu, w którym przyrosty nie mają sensu, a także nie są tak potrzebne jak w C, gdzie używasz ich za każdym razem, gdy masz pętlę, na przykład.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-09 09:40:54
Podczas gdy pozostałe odpowiedzi są poprawne w takim stopniu, w jakim pokazują to, co zwykłe +
zwykle robi (tzn. pozostawiają liczbę taką, jaką jest, jeśli jest jedna), są niekompletne w takim stopniu, w jakim nie wyjaśniają, co się dzieje.
Aby być dokładnym, +x
ocenia na x.__pos__()
i ++x
na x.__pos__().__pos__()
.
Wyobrażam sobie bardzo dziwną strukturę klasową (dzieci, nie róbcie tego w domu!) Tak:
class ValueKeeper(object):
def __init__(self, value): self.value = value
def __str__(self): return str(self.value)
class A(ValueKeeper):
def __pos__(self):
print 'called A.__pos__'
return B(self.value - 3)
class B(ValueKeeper):
def __pos__(self):
print 'called B.__pos__'
return A(self.value + 19)
x = A(430)
print x, type(x)
print +x, type(+x)
print ++x, type(++x)
print +++x, type(+++x)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-26 14:59:33
Python nie ma tych operatorów, ale jeśli naprawdę ich potrzebujesz, możesz napisać funkcję o tej samej funkcjonalności.
def PreIncrement(name, local={}):
#Equivalent to ++name
if name in local:
local[name]+=1
return local[name]
globals()[name]+=1
return globals()[name]
def PostIncrement(name, local={}):
#Equivalent to name++
if name in local:
local[name]+=1
return local[name]-1
globals()[name]+=1
return globals()[name]-1
Użycie:
x = 1
y = PreIncrement('x') #y and x are both 2
a = 1
b = PostIncrement('a') #b is 1 and a is 2
Wewnątrz funkcji musisz dodać locals () jako drugi argument, jeśli chcesz zmienić zmienną lokalną, w przeciwnym razie spróbuje zmienić globalną.
x = 1
def test():
x = 10
y = PreIncrement('x') #y will be 2, local x will be still 10 and global x will be changed to 2
z = PreIncrement('x', locals()) #z will be 11, local x will be 11 and global x will be unaltered
test()
Również z tych funkcji można zrobić:
x = 1
print(PreIncrement('x')) #print(x+=1) is illegal!
Ale moim zdaniem następujące podejście jest znacznie jaśniejsze:
x = 1
x+=1
print(x)
Decrement operatory:
def PreDecrement(name, local={}):
#Equivalent to --name
if name in local:
local[name]-=1
return local[name]
globals()[name]-=1
return globals()[name]
def PostDecrement(name, local={}):
#Equivalent to name--
if name in local:
local[name]-=1
return local[name]+1
globals()[name]-=1
return globals()[name]+1
Użyłem tych funkcji w moim module tłumaczącym javascript na python.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-05 15:37:15
W Pythonie rozróżnienie między wyrażeniami i wyrażeniami jest sztywne egzekwowane, w przeciwieństwie do języków takich jak Common Lisp, Scheme czy Ruby.
Więc wprowadzając takie operatory, złamałbyś podział wyrażenia/instrukcji.
Z tego samego powodu nie możesz napisać
if x = 0:
y = 1
Jak można w niektórych innych językach, gdzie takie rozróżnienie nie jest zachowane.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-25 13:47:23
Tak, przegapiłem ++ i -- funkcjonalność również. Kilka milionów linijek kodu c zaszczepiło takie myślenie w mojej starej głowie i zamiast z tym walczyć... Oto klasa i, która implementuje:
pre- and post-increment, pre- and post-decrement, addition,
subtraction, multiplication, division, results assignable
as integer, printable, settable.
Oto jest:
class counter(object):
def __init__(self,v=0):
self.set(v)
def preinc(self):
self.v += 1
return self.v
def predec(self):
self.v -= 1
return self.v
def postinc(self):
self.v += 1
return self.v - 1
def postdec(self):
self.v -= 1
return self.v + 1
def __add__(self,addend):
return self.v + addend
def __sub__(self,subtrahend):
return self.v - subtrahend
def __mul__(self,multiplier):
return self.v * multiplier
def __div__(self,divisor):
return self.v / divisor
def __getitem__(self):
return self.v
def __str__(self):
return str(self.v)
def set(self,v):
if type(v) != int:
v = 0
self.v = v
Możesz użyć tego tak:
c = counter() # defaults to zero
for listItem in myList: # imaginary task
doSomething(c.postinc(),listItem) # passes c, but becomes c+1
...już mając c, możesz to zrobić...
c.set(11)
while c.predec() > 0:
print c
....albo po prostu...
d = counter(11)
while d.predec() > 0:
print d
...oraz dla (re-)przypisania do liczby całkowitej...
c = counter(100)
d = c + 223 # assignment as integer
c = c + 223 # re-assignment as integer
print type(c),c # <type 'int'> 323
...podczas gdy to utrzyma c jako licznik typu:
c = counter(100)
c.set(c + 223)
print type(c),c # <class '__main__.counter'> 323
EDIT:
I jeszcze ten kawałek nieoczekiwanego (i całkowicie niechcianego) zachowania ,
c = counter(42)
s = '%s: %d' % ('Expecting 42',c) # but getting non-numeric exception
print s
...ponieważ wewnątrz tej krotki, getitem () nie jest tym, co jest używane, zamiast tego odwołanie do obiektu jest przekazywane do funkcji formatującej. Westchnienie. Więc:
c = counter(42)
s = '%s: %d' % ('Expecting 42',c.v) # and getting 42.
print s
...lub, bardziej gadatliwie i wyraźnie, to, co naprawdę chcieliśmy się wydarzyć, jest jednak przeciwstawiane w rzeczywistej formie gadatliwości (use c.v
zamiast tego)...
c = counter(42)
s = '%s: %d' % ('Expecting 42',c.__getitem__()) # and getting 42.
print s
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-19 21:33:40