Python'dakı artım və azalma operatorlarının davranışı

Hesab edirəm ki, bir dəyişən (məsələn, ++count ) üçün əvvəlcədən artım / dekal operator istifadə edilə bilər. Bu tərtib edir, lakin həqiqətən dəyişən dəyərini dəyişmir!

Python-da əvvəlcədən artım / decment (++ / -) operatorlarının davranışı nədir?

Python, C / C ++ 'da görülən bu operatorların davranışlarından nə üçün ayrılıb?

654
28 сент. Ashwin Nanjappa tərəfindən təyin olunan Sep 28 2009-09-28 10:33 '09 saat 10:33 'da 2009-09-28 10:33
@ 7 cavab

++ operator deyil. Bunlar iki + operatordur. + Operator heç bir şey etməyən eyni operatordur. (Şərh: Unary operatorlar +- yalnız nömrələrlə işləyirlər, amma hipotetik ++ operatorunun strings ilə işləməyini gözləmirsiniz.)

 ++count 

Necə ayrılır

 +(+count) 

Nə çevrilir?

 count 

Istədiyiniz şeyləri yerinə yetirmək üçün bir az += operator istifadə etməlisiniz:

 count += 1 

Mən ++ və operatorların tutarlılıq və sadəlik üçün atıldığını şübhə edirəm. Guido van Rossumun həll üçün verdiyi dəqiq arqumentləri bilmirəm, amma bir neçə mübahisəni təqdim edə bilərəm:

  • Sökmək daha asan. Texniki cəhətdən təhlil ++count qeyri-müəyyəndir, çünki + , + ( + unary operator ++ ) kimi asanlıqla count (iki unary operator ++ ). Bu əhəmiyyətli bir sintaktik qeyri-müəyyənlik deyil, ancaq mövcuddur.
  • Sadələşdirilmiş dil. ++ , += 1 üçün sinonimdən daha çox şeydir. C icraçıları axmaq idi və a += 1 çox kompüter üçün inc təlimatında a += 1 optimallaşdırmağı bilmirdilər. Derivorların optimallaşdırılması və interpretasiya edilmiş bayt kodlarının dilləri gündəmdə, programcıların kodlarını optimallaşdırmağa imkan verən bir dilin operatorlara əlavə olunması, xüsusilə, tutarlı və oxunaqlı olmaq üçün nəzərdə tutulan Python kimi bir dildə qəbul edilmir.
  • Çaşqın yan təsirləri. ++ operatorlarla dillərdə olan yeniliklərin ümumi səhvlərindən biri əvvəlcədən və sonradan artım / azalma operatorları arasındakı fərqləri (həm prioritetlər, həm də qaytarma dəyərləri) qarışdırmaqdır və Python dilin "səhvlərini" istisna edir. C-ə qədər əvvəlcədən / artımdan əvvəlki problemlər olduqca tüylü və çaşqın vəziyyətdədir.
853
28 сент. Sep 28-də Chris Lutz tərəfindən verilmiş cavab 2009-09-28 10:39 '09 da 10:39 'da 2009-09-28 10:39

Artırmaq və ya azaltmaq istəyirsinizsə, bunu bir tamsayı ilə etmək istəyirlər. Məsələn:

 b++ 

Amma Pythonda tamsayılar dəyişməzdir . Yəni, onları dəyişdirə bilməzsiniz. Bu, bütün obyektlərin bir neçə ad altında istifadə oluna bilməsi ilə bağlıdır. Aşağıdakıları cəhd edin:

 >>> b = 5 >>> a = 5 >>> id(a) 162334512 >>> id(b) 162334512 >>> a is b True 

a və b yuxarıda həqiqətən eyni obyektdir. A dəyərini artırdığınız təqdirdə də b artacaqsınız. Bu istədiyiniz nə deyil. Buna görə də yenidən təyin etməlisiniz. Burada:

border=0
 b = b + 1 

Və ya daha asan:

 b += 1 

Bu, b+1 1'e b təyin olunur. Bu artım operator deyil, çünki b artmaz, onu yenidən təyin edir.

Qısacası: Python burada fərqli davranır, çünki bu C deyildir və maşın kodunun ətrafında aşağı səviyyəli bir sarğı deyil, lakin artımların mantıksız olmadığı dinamik yüksək səviyyəli dildir və istifadə etdiyiniz C məsələn, hər dövründə bir dövrü var.

351
28 сент. Lennart Regebro tərəfindən verilmiş cavab Sep 28 2009-09-28 12:05 '09 saat 12:05 'da 2009-09-28 12:05

Cavabın qalan hissəsi düzgündür, çünki onlar adətən yalnız nə etdiyini göstərirlər (yəni nömrəni olduğu kimi tərk edin, əgər varsa), baş verənləri izah etmədikləri kimi, tamamlanmamışdır.

x.__pos__() +x x.__pos__()++x x.__pos__().__pos__() .

Çox qəribə bir sinif quruluşunu təsəvvür edə bilərəm (uşaqlar, bunu evdə etməyin!) Bu kimi:

 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) 
47
26 июня '12 в 17:59 2012-06-26 17:59 cavab 26 iyun 2012 -ci il saat 17: 59 -da verilir

Pythonda bu operatorlar yoxdur, ancaq həqiqətən onlara ehtiyac varsa, eyni funksiyalı funksiyanı yaza bilərsiniz.

 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 

İstifadə edin:

 x = 1 y = PreIncrement('x') #y and x are both 2 a = 1 b = PostIncrement('a') #b is 1 and a is 2 

Bu funksiyanı içərisində yerli dəyişən dəyişdirmək istəyirsinizsə ikinci bir arqument kimi yerli (yerli) əlavə etməliyəm, əks halda bu, qlobal dəyişdirmək üçün çalışacaq.

 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() 

Siz həmçinin:

 x = 1 print(PreIncrement('x')) #print(x+=1) is illegal! 

Lakin, mənim fikrimcə, aşağıdakı yanaşma daha aydındır:

 x = 1 x+=1 print(x) 

Azaltma operatorları:

 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 

Bu funksiyaları, javascripti python'a çevirərək, modulumda istifadə etdim.

9
05 окт. Piotr Dabkowski tərəfindən verilmiş cavab Oct 05 2014-10-05 18:37 '14 saat 18:37 'də 2014-10-05 18:37

Python'da ifadələr və iddialar arasındakı fərq Common Lisp, Scheme və ya Rubin kimi dillərdən fərqli olaraq sərtdir.

Vikipediya

Beləliklə, bu cür operatorləri daxil etməklə, ifadəni / operator bölməsini ayırırsınız.

Eyni səbəbdən yaza bilməzsiniz

 if x = 0: y = 1 

bu fərqin davam etmədiyi bəzi dillərdə olduğu kimi.

8
16 дек. Cavab Vitalii Fedorenko 16 dekabrda verilir. 2011-12-16 19:33 '11 'da 19:33' da 2011-12-16 19:33

Bəli ++ və funksiyasını qaçırdım. Bir neçə milyon satır c kodu mənim köhnə başımda belə düşüncəyə kök salmışdır və bunun əvəzinə mübarizə aparmaqdadır ... İşdə bədbəxt edən bir sinif var:

 pre- and post-increment, pre- and post-decrement, addition, subtraction, multiplication, division, results assignable as integer, printable, settable. 

Burada:

 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 

Bunu aşağıdakı kimi istifadə edə bilərsiniz:

 c = counter() # defaults to zero for listItem in myList: # imaginary task doSomething(c.postinc(),listItem) # passes c, but becomes c+1 

... onsuz da c, bunu edə bilərsiniz ...

 c.set(11) while c.predec() > 0: print c 

.... ya da yalnız ...

 d = counter(11) while d.predec() > 0: print d 

... və tam reallaşdırma (yenidən) üçün ...

 c = counter(100) d = c + 223 # assignment as integer c = c + 223 # re-assignment as integer print type(c),c # <type 'int'> 323 

... c cədvəlinin sayını dəstəkləyəcəyi müddətcə:

 c = counter(100) c.set(c + 223) print type(c),c # <class '__main__.counter'> 323 

EDIT:

Və burada bir az gözlənilməz (və tamamilə arzuolunmaz) davranış ,

 c = counter(42) s = '%s: %d' % ('Expecting 42',c) # but getting non-numeric exception print s 

... çünki bu tuple içərisində getitem () istifadə edilmir, bunun əvəzinə obyekt istinadları formatlama funksiyasına ötürülür. Sigh Beləliklə:

 c = counter(42) s = '%s: %d' % ('Expecting 42',cv) # and getting 42. print s 

... ya da daha ətraflı və açıq şəkildə, biz həqiqətən baş vermək istəmədik, baxmayaraq ki, əksinə, əksinə, cazibə ilə (əksinə, cv istifadə edin) əks olunmalıdır ...

 c = counter(42) s = '%s: %d' % ('Expecting 42',c.__getitem__()) # and getting 42. print s 
4
19 мая '15 в 23:40 2015-05-19 23:40 Cavab fyngyrz 19 may, 23 saat 23: 37-da verilir

Tl; DR

Python unary increment / azaldılması operatorları yoxdur ( -- / ++ ). Bunun əvəzinə dəyərini artırmaq üçün istifadə edin

 a += 1 

Daha çox məlumat və səhvlər

Lakin burada diqqətli olun. Cdən gəlsəniz, Python da bu belə deyil. Python, C'de olduğu mənasında dəyişən deyil, Python adları və obyektlərini istifadə edir və Python-da int dəyişməzdir.

buna görə deyək

 a = 1 

Python'da bu aşağıdakıları nəzərdə tutur: 1 int dəyəri bir int obyekti yaratmaq və adını buna bağlamaq. Nesne int bir nümunəsidir və dəyəri 1 ilə təyin olunur. Adı və onun aid olduğu obyekt fərqlidir.

İndi nə etdiyinizi söyləək

 a += 1 

int dəyişməz olduğundan aşağıdakılar olur:

  1. obyekti tapmaq, a istinad edir (bu id 0x559239eeb380 ilə int )
  2. obyektin 0x559239eeb380 (bu 1 )
  3. bu dəyərə 1 əlavə edin (1 + 1 = 2)
  4. 2 dəyərində yeni bir int obyekti yaratmaq (obyektin identifikatoru 0x559239eeb3a0 )
  5. bu yeni obyektə ad verin
  6. İndi obyektə a 0x559239eeb3a0 istinad deyil və mənbə obyekti ( 0x559239eeb380 ) artıq a adı ilə istinad edilmir. Mənbə obyektinə aid digər adlar yoxdursa, daha sonra zibil toplanması olacaq.

Özünüzü sınayın:

 a = 1 print(hex(id(a))) a += 1 print(hex(id(a))) 
0
18 янв. Cavab verilir RBF06 18 yanvar. 2019-01-18 19:31 '19 saat 07:31 'də 2019-01-18 19:31