"operator" tamsayılarla gözlənilməz şəkildə davranır

Pythonda niyə gözlənilməz bir davranış var?

 >>> a = 256 >>> b = 256 >>> a is b True # This is an expected result >>> a = 257 >>> b = 257 >>> a is b False # What happened here? Why is this False? >>> 257 is 257 True # Yet the literal numbers compare properly 

Python 2.5.2 istifadə edirəm. Python'un bir neçə müxtəlif versiyasını sınamaqla Python 2.3.3 yuxarıdakı davranışı 99 ilə 100 arasında göstərir.

Üstəliklərə əsasən Pythonun "kiçik" tamsayıların böyük tam ədədlərdən fərqli olaraq saxlandığı və operatorun fərqləndirə biləcəyi məcburi şəkildə tətbiq oluna bilər. Niyə soyuducu hərəkəti axır? İki təsadüfən obyektləri müqayisə etmək üçün ən yaxşı yol nədir, əgər onlar ədəd olub-olmadığını əvvəlcədən bilmirlərsə, eyni olub-olmadığını görmək üçün nədir?

416
20 нояб. Greg Hewgill tərəfindən təyin olunan 20 noyabr. 2008-11-20 21:21 '08 saat 09:21 'da 2008-11-20 21:21
@ 11 cavab

Buna baxın:

 >>> a = 256 >>> b = 256 >>> id(a) 9987148 >>> id(b) 9987148 >>> a = 257 >>> b = 257 >>> id(a) 11662816 >>> id(b) 11662828 

EDIT: Python 2 sənədlərində, "Plain Integer Objects" ( Python 3 üçün eyni) da tapdım:

Mövcud tətbiq, bu sıra içərisində bir int yaratdığınız zaman, bütün obyektlərin bütün sayıları üçün -5-dən 256-a qədər tam ədədlər sətrini saxlayır və yalnız mövcud bir obyektə müraciət verir. Beləliklə, bu dəyərin dəyişdirilməsi mümkündür. Bu halda Pythonun davranışından şübhələnirəm: -)

323
20 нояб. cavab Cybis 20 noyabrda verilir. 2008-11-20 21:30 '08 saat 21:30 'da 2008-11-20 21:30

Python "operator" tamsayılarla gözlənilməz şəkildə davranır?

Qısacası mənə vurğulamaq istəyirəm: istifadə etməyin, tamsayıları müqayisə etməkdir.

Bu, gözlənilməlidir davranış deyil.

Bunun əvəzinə ==!= bərabərlik və bərabərsizliyi müqayisə etmək üçün istifadə edin. Məsələn:

 >>> a = 1000 >>> a == 1000 # Test integers like this, True >>> a != 5000 # or this! True >>> a is 1000 # Don't do this! - Don't use `is` to test integers!! False 

Təsvir

Bunu bilmək üçün aşağıdakıları bilmək lazımdır.

Birincisi, nədir? Bu bir müqayisə operatorudur. Sənəddən:

Bir obyektin şəxsiyyətini doğrulayan və operator is not : x və y yalnız eyni xətt olduğunda və x x is y true. x is not y həqiqətin tərsini x is not y .

Beləliklə, aşağıdakı ekvivalentlər.

 >>> a is b >>> id(a) == id(b) 

Sənədlərdə:

id "id" obyektini qaytarın. Bu, bu obyektin ömrü boyunca unikal və davamlı olmağı təmin edən bir tamsayıdır (və ya uzun tamsayıdır). Qeyri-çakışan ömürləri olan iki obyekt eyni id() dəyərinə malik ola bilər.

Qeyd edək ki CPython'ta obyektin ID'si (Python'un referans tətbiqi) bir yaddaş yeri olduğu bir tətbiq təzahürüdür. Pythonun digər tətbiqləri (məsələn, Jython və ya IronPython) id üçün fərqli bir tətbiq ola bilər.

Belə bir nümunə nədir? PEP8 təsvir edir :

Həyatın tək bir növü ilə müqayisə edilməməsi heç vaxt həmişə bərabərlik operatorları tərəfindən icra edilməmişdir və ya istifadə edilməməlidir.

Sual

Aşağıdakı sual soruşursunuz və soruşursunuz (kodla):

Pythonda niyə gözlənilməz bir davranış var?

 >>> a = 256 >>> b = 256 >>> a is b True # This is an expected result 
border=0

Bu gözlənilən nəticə deyil. Niyə bu gözlənilən idi? Bu da, ab tərəfindən göstərilən 256 qiymətləndirilən tamsayılar bir tamsanın eyni nümunəsidir. Integers Python-da sabitlənmişdir, buna görə dəyişə bilmirlər. Bu hər hansı bir kodu təsir etməməlidir. Bu gözlənilmir. Bu yalnız bir tətbiq təfərrüatıdır.

Amma bəlkə də şad olmalıyıq ki, yaddaşda hər bir nümunə hər dəfə dəyərin 256 olduğunu göstərdiyimiz zaman olmayacaq.

 >>> a = 257 >>> b = 257 >>> a is b False # What happened here? Why is this False? 

Göründüyü kimi, indi yaddaşda 257 ədəd olan iki ədəd tam ədəd var. Tamsanlar dəyişməz olduğundan, yaddaşını götürür. Ümid edirik ki, çox səy sərf etməyəcəyik. Yəqin ki, yox. Ancaq bu davranışa zəmanət verilmir.

 >>> 257 is 257 True # Yet the literal numbers compare properly 

Bəli, Pythonun xüsusi həyata keçirilməsi ağıllı olmağa çalışır və lazım deyilsə yaddaşda həddindən artıq dəyərli tamsayılar yarada bilməz. CPython olan Python'un referans tətbiqini istifadə etdiyinizinizi göstərirsiniz. CPython üçün yaxşıdır.

Yəqin ki, CPython bütövlükdə bunu edə bilər, əgər ucuz olarsa (bir axtarışa layiq olduğundan), bəlkə də başqa bir tətbiq ola bilər.

Lakin kodun təsirinə gəldikdə, bir tamsayı tam sayının xüsusi bir nümunəsi olub-olmadığı barədə düşünmürsən. Yalnız bu instansiyanın dəyərinin nə olduğuna diqqət yetirməli və adi müqayisə operatorlarını istifadə edərsiniz, yəni. == .

Nə edir?

iki obyektin idinin eyni olduğunu sübut edir. CPython'da, id yaddaşda bir yerdir, lakin başqa bir tətbiqdə başqa bir nadir identifikasiya nömrəsi ola bilər. Bunu kodu ilə yenidən düzəltmək üçün:

 >>> a is b 

ilə uyğunlaşır

 >>> id(a) == id(b) 

Niyə istifadə etmək istəyirik?

Bu, çox uzun bir xətt dəyərinə bərabər olub olmadığını yoxlamaq, məsələn, çox sürətli bir çek ola bilər. Lakin bu, obyektin yeganəliyinə aiddir, buna görə də biz məhdud nümunələrə sahibik. Əslində, əsasən, onu tək-tək (yalnız bir yerdə yaddaşda saxlayan tək nümunə) olan None yoxlamaq üçün istifadə etmək istəyirik. Onları birləşdirmək üçün potensial varsa, digər testlər yarada bilərik ki, biz test edə bilərik, lakin nisbətən nadirdir. Məsələn nümunədir (Python 2 və 3-də işləyəcək), məsələn

 SENTINEL_SINGLETON = object() # this will only be created one time. def foo(keyword_argument=None): if keyword_argument is None: print('no argument given to foo') bar() bar(keyword_argument) bar('baz') def bar(keyword_argument=SENTINEL_SINGLETON): # SENTINEL_SINGLETON tells us if we were not passed anything # as None is a legitimate potential argument we could get. if keyword_argument is SENTINEL_SINGLETON: print('no argument given to bar') else: print('argument to bar: {0}'.format(keyword_argument)) foo() 

Nə yazır?

 no argument given to foo no argument given to bar argument to bar: None argument to bar: baz 

Beləliklə, biz görürük və göndəricinin, bar arqumentsiz çağırıldığı və heç bir zaman çağrılmadığı zaman ayırd edə bilərik. Bunlar üçün əsas məqsədlər - tamsayıların, strings, tuples və ya digər şeylərin bərabərliyini yoxlamaq üçün istifadə etməyin.

76
04 марта '15 в 23:20 2015-03-04 23:20 cavab 04 mart '15 'də saat 23:20 ' də Aaron Hall tərəfindən verildi

Bu, 2 şeyin bərabər və ya eyni obyekt olduğunu yoxlamaq istəməyinizə bağlıdır.

yalnız bərabər deyil, eyni cisimdirsə çekləri yox edir. Kiçik ints yer səmərəliliyini təmin etmək üçün eyni yaddaş yerini göstərə bilər.

 In [29]: a = 3 In [30]: b = 3 In [31]: id(a) Out[31]: 500729144 In [32]: id(b) Out[32]: 500729144 

Təsadüfi obyektlərin bərabərliyini müqayisə etmək üçün == istifadə etməlisiniz. __eq____ne__ xüsusiyyətləri ilə təyin edə bilərsiniz.

55
20 нояб. JimB 20 noyabrda cavablandırdı. 2008-11-20 21:36 '08 at 21:36 pm 2008-11-20 21:36

Mənbə faylını intobject.c yoxlaya bilərsiniz , Python səmərəliliyi üçün kiçik tamsayıları önə çəkir . Hər bir kiçik bir tamsayıya bir keçid yaratdığınızda, yeni obyekt deyil, önlənmiş kiçik tamsayıya müraciət edirsiniz. 257 kiçik bir tamsayı deyildir, buna görə başqa bir obyekt hesablanır.

== istifadə etmək daha yaxşıdır.

36
20 нояб. Cavab 20 noyabr tarixində Angel tərəfindən verilir. 2008-11-20 22:50 '08 saat 22:50 'da 2008-11-20 22:50

Mən gecikdim, amma cavabınızla bir qaynaq lazımdırmı? *

CPython haqqında yaxşı bir şey, həqiqətən bunun qaynağını görə biləcəyiniz. Mən azadlığa buraxılacaq bağlantıları 3.5 ; uyğun 2.x tapma çox əhəmiyyətsizdir.

PyLong_FromLong(long v) yeni int obyektinin yaradılmasını idarə edən C-API funksiyası. Bu xüsusiyyət üçün təsvir:

Mövcud tətbiq, bu sıra içərisində bir int yaratdığınız zaman -5 ilə 256 arasında olan bütün tamsayılar üçün tam obyektlərin bir sıra saxlayır, əslində sadəcə mövcud bir obyektə istinad verirsiniz. Buna görə dəyərin dəyişdirilməsi mümkündür. 1. Bu vəziyyətdə Pythonun davranışının təsbit edilmədiyini şübhə edirəm: -)

Mən səni tanıyıram, amma bunu görürəm və düşünürəm: bu array taparıq!

CPython tətbiq C kodu ilə işləmədiyiniz halda, hamısı mütəşəkkil və oxunaqlı olmalıdır. Bizim vəziyyətimiz üçün qaynaq dizinlərinin əsas qovluğunun Objects/ alt qovluğuna baxmaq lazımdır.

PyLong_FromLong long obyektlərlə məşğul olur, ona görə long baxmaq lazımdır ki, nəticəyə gəlmək asandır. İçə baxdığınız şeylər xaotik olduğunu düşünə bilərsiniz; Onlar var, amma qorxmuruq, biz line 230 nömrəli qorxu axtaran funksiyanı gözləyirik. Bu kiçik bir funksiyadır, buna görə əsas quruluş (reklamlardan başqa) asanlıqla buraya daxil edilir:

 PyObject * PyLong_FromLong(long ival) { // omitting declarations CHECK_SMALL_INT(ival); if (ival < 0) {  abs_ival = 0U-(unsigned long)ival; sign = -1; } else { abs_ival = (unsigned long)ival; }  if (!(abs_ival >> PyLong_SHIFT)) { v = _PyLong_New(1); if (v) { Py_SIZE(v) = sign; v->ob_digit[0] = Py_SAFE_DOWNCAST( abs_ival, unsigned long, digit); } return (PyObject*)v; } 

İndi biz C master-code-haxxorz deyilik, amma biz də axmaq deyil, onu görə bilərik ki CHECK_SMALL_INT(ival); hər şey bizə cazibədar görünür; biz başa düşə bilərik ki, bu, bununla bağlıdır. Məni yoxlayalım:

 #define CHECK_SMALL_INT(ival) \ do if (-NSMALLNEGINTS <= ival  ival < NSMALLPOSINTS) { \ return get_small_int((sdigit)ival); \ } while(0) 

Beləliklə, bu, ival dəyəri get_small_int uyğun gəlsə, ival funksiyasını çağıran get_small_int :

 if (-NSMALLNEGINTS <= ival  ival < NSMALLPOSINTS) 

NSMALLNEGINTSNSMALLPOSINTS nədir? Makroları tahmin etsəniz, heç bir şey əldə etmirsiniz, çünki bu çətin bir sual deyildi. Hər halda, burada :

 #ifndef NSMALLPOSINTS #define NSMALLPOSINTS 257 #endif #ifndef NSMALLNEGINTS #define NSMALLNEGINTS 5 #endif 

Beləliklə, vəziyyətimiz if (-5 <= ival ival < 257) get_small_int olur.

get_small_int - ə get_small_int heç bir get_small_int , lakin bütün şöhrətimizə ( baxmayaraq ki , bu bədənə baxırıq, çünki bunlar maraqlı şeylərdir) baxırıq:

 PyObject *v; assert(-NSMALLNEGINTS <= ival  ival < NSMALLPOSINTS); v = (PyObject *) + NSMALLNEGINTS]; Py_INCREF(v); 

Bəli, PyObject elan PyObject , əvvəlki şərt yerinə yetirildiyini və tapşırığını yerinə yetirdiyini PyObject :

 v = (PyObject *) + NSMALLNEGINTS]; 

small_ints çox oxşardır .. və bu! Yalnız lənətüllə sənədləri oxuyuruq və hamımız bilirik! :

  static PyLongObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS]; 

Yəni bu bizim sevgilimizdir. [NSMALLNEGINTS, NSMALLPOSINTS) yeni bir int yaratmaq istədiyiniz zaman [NSMALLNEGINTS, NSMALLPOSINTS) , əvvəlcədən ayrılmış olan mövcud bir obyektə referansı qaytarırsınız.

Bağlantı eyni obyektə aid olduğundan, birbaşa id() verilməsi və ya identifikasiyası ilə bağlıdırsa, eyni şeyi geri qaytaracaqdır.

Ancaq onlar fərq edildikdə

_PyLong_Init başlatma zamanı Python üçün xoşbəxtliklə for loop daxil olacaq, sizin üçün bunu:

 for (ival = -NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++, v++) { // Look me up! } 

Ümid edirəm ki, mənim şərhlərim səni indi C (könüllü olaraq nəzərdə tutulmuşdu) etdi.


Amma 257 - 257? Nədir?

Bunu izah etmək daha asandır və mən artıq bunu etməyə çalışdım ; Python bu interaktiv ifadəni yerinə yetirəcəkdir:

 >>> 257 is 257 

bir blok olaraq. Bu ifadəni tərtib edərkən, CPython iki eşleşen PyLongObject təmsil edən eyni PyLongObject istifadə edəcək. Bunu özünüz tərtib etsəniz və onun məzmununu öyrənsəniz görürsünüz:

 >>> codeObj = compile("257 is 257", "blah!", "exec") >>> codeObj.co_consts (257, None) 

CPython əməliyyat yerinə yetirdikdə; indi yalnız eyni obyekti yükləyəcək:

 >>> import dis >>> dis.dis(codeObj) 1 0 LOAD_CONST 0 (257) # dis 3 LOAD_CONST 0 (257) # dis again 6 COMPARE_OP 8 (is) 

Beləliklə is True dönəcəkdir.


* - Ən çox izləyici bir şəkildə bunu izah etməyə çalışacağam, əksəriyyəti onu təqib edə bilər.

33
23 янв. Cavab Jim Fasarakis Hilliard tərəfindən 23 yanvar tarixində verilir. 2016-01-23 16:26 '16 saat 16:26 'da 2016-01-23 16:26

Hesab edirəm ki, hipotezlər düzgündür. id ilə obyektin id (obyektin təyin edilməsi):

 In [1]: id(255) Out[1]: 146349024 In [2]: id(255) Out[2]: 146349024 In [3]: id(257) Out[3]: 146802752 In [4]: id(257) Out[4]: 148993740 In [5]: a=255 In [6]: b=255 In [7]: c=257 In [8]: d=257 In [9]: id(a), id(b), id(c), id(d) Out[9]: (146349024, 146349024, 146783024, 146804020) 

Göründüyü kimi <= 255 ədədləri litals kimi nəzərdən keçirilir və yuxarıdakıların hamısı fərqlidir!

18
20 нояб. cavab Amit 20 noyabrda verilir . 2008-11-20 21:29 '08 at 21:29 pm 2008-11-20 21:29

İnt, strings və ya tarix kimi dəyişkən dəyərlər obyektləri üçün obyektin müəyyən edilməsi xüsusilə faydalı deyil. Eşitlik haqqında düşünmək daha yaxşıdır. Təsnifat əslində dəyər obyektlərinin tətbiqinin detallarıdır - onlar dəyişməz olduğundan, eyni obyekt və ya bir neçə obyektə birdən çox müraciət etmək arasında effektiv fərq yoxdur.

12
21 нояб. Cavab babbageclunk 21 noyabrda verilir. 2008-11-21 04:58 '08 at 04:58 2008-11-21 04:58

şəxsiyyət bərabərliyi operatorudur ( id(a) == id(b) ); sadəcə iki bərabər ədəd mütləq eyni obyekt deyildir. Performans səbəbləri ilə, bəzi kiçik tamsayılar memoized olunur , beləliklə, onlar eyni olmağa meylli olacaqlar (bu mümkün olmur , çünki bu mümkündür).

Digər tərəfdən PHP operatoru === Paulo Freitasın şərhinə görə, bərabərlik yoxlaması və növü: x == y and type(x) == type(y) kimi təsvir olunur, bu ümumi ədədlər üçün kifayətdir, lakin fərqlənir __eq__ absurd şəkildə müəyyən edən __eq__ :

 class Unequal: def __eq__(self, other): return False 

PHP, "daxili" siniflər üçün eyni şəkildə icazə verir (PHP-də deyil, C səviyyəsində tətbiq etmək deməkdir). Bir qədər az absürd bir nömrə kimi istifadə edilən hər zaman fərqli məna olan bir timer obyekti ola bilər. Və bu səbəbdən Visual Basic Now time.time() , bu, time.time() .

Greg Hugill (OP) bir izahlı şərh etdi: "Mənim məqam obyektin şəxsiyyətini müqayisə etməkdir, dəyərin bərabərliyini müqayisə etməkdir, obyektin şəxsiyyətini və dəyərin bərabərliyini nəzərə almaq istədiyim nömrələr istisna olmaqla."

Bu, bir daha cavab olacaqdır, çünki biz şeyi ədəd kimi təsnif etməliyik və ya == və ya ilə müqayisə edək. CPython , PyNumber_Check daxil olmaqla protokol nömrəsini müəyyən edir , lakin Python-dan özü mövcud deyil.

Biz isinstance otaqların isinstance ilə isinstance , lakin bu, qaçılmazdır. Tip modulunda StringTypes siyahısı var, lakin NumberTypes deyil. Python 2.6-dan bəri, rəqəmli rəqəmli siniflər əsas numbers.Number sahibdirlər. numbers.Number sinfi, lakin eyni problem var:

 import numpy, numbers assert not issubclass(numpy.int16,numbers.Number) assert issubclass(int,numbers.Number) 

Yeri gəlmişkən, NumPy az sayda ayrı nüsxə yaradır.

Mən, həqiqətən, sualın bu versiyasının cavabını bilmirəm. Mən hesab edirəm ki, nəzəri cəhətdən PyNumber_Check-i çağırmaq üçün PyNumber_Check istifadə edə bilərsiniz, amma bu funksiya müzakirə olundu və əlbəttə ki, portativ deyil. İndi biz sınadığımız şey haqqında daha az xüsusi olmalıdır.

Nəhayət, bu problem Pythonun əvvəlcə əsaslı bir növüdür, məsələn, number? sxemi number? , və ya Haskell tipində sinif Num . obyektin identifikasiyasını yox, dəyərin bərabərliyini yox edir. PHP də rəngarəng bir tarixə sahibdir, burada === yalnız PHP5-də deyil, PHP4-də olmayan obyektlər üçün is kimi görünür. Bunlar dilləri (birinin versiyasını da daxil olmaqla) arasında hərəkət edən artan ağrıdır.

8
20 марта '13 в 14:20 2013-03-20 14:20 Cavab Yann Vernier tərəfindən 20 Mart 2013 tarixində saat 14: 20-də verilir

Bu da strings ilə olur:

 >>> s = b = 'somestr' >>> s == b, s is b, id(s), id(b) (True, True, 4555519392, 4555519392) 

İndi hər şey gözəl görünür.

 >>> s = 'somestr' >>> b = 'somestr' >>> s == b, s is b, id(s), id(b) (True, True, 4555519392, 4555519392) 

Bu da gözlənilir.

 >>> s1 = b1 = 'somestrdaasd ad ad asd as dasddsg,dlfg ,;dflg, dfg a' >>> s1 == b1, s1 is b1, id(s1), id(b1) (True, True, 4555308080, 4555308080) >>> s1 = 'somestrdaasd ad ad asd as dasddsg,dlfg ,;dflg, dfg a' >>> b1 = 'somestrdaasd ad ad asd as dasddsg,dlfg ,;dflg, dfg a' >>> s1 == b1, s1 is b1, id(s1), id(b1) (True, False, 4555308176, 4555308272) 

İndi gözlənilməzdir.

4
14 окт. Cavab sobolevn 14 oct verilir . 2015-10-14 18:53 '15 at 18:53 'də, 2015-10-14 18:53

Buraya baxın

Mövcud tətbiq, bu sıra içərisində bir int yaratdığınız zaman -5 ilə 256 arasında olan bütün tamsayılar üçün tam obyektlərin bir sıra saxlayır, sadəcə mövcud bir obyektə istinad verirsiniz.

3
18 февр. 18 fevral tarixində user5319825 tərəfindən verilmiş cavab 2016-02-18 15:46 '16 'da 15:46' də 2016-02-18 15:46 'da

Mövcud cavabların heç birində qeyd olunmayan başqa bir problem var. Python hər iki dəyişməz dəyərləri birləşdirməyə icazə verilir və əvvəllər yaradılmış kiçik dəyərlərin dəyərləri bunun baş verə biləcəyi yeganə yol deyildir. Pythonun tətbiqi bunu heç vaxt təmin etmir, ancaq bunlar yalnız kiçik olanlardan daha çoxdur.


Birincisi, boş tuple , strbytes kimi bəzi əvvəlcədən yaradılmış dəyərlər, həmçinin bəzi qısa strings (CPython 3.6-da, 256 Latin-1 tək karakter simvolu var) var. Məsələn:

 >>> a = () >>> b = () >>> a is b True 

Ancaq eyni zamanda təqdim edilməmiş dəyərlər eyni ola bilər. Aşağıdakı nümunələri nəzərdən keçirin:

 >>> c = 257 >>> d = 257 >>> c is d False >>> e, f = 258, 258 >>> e is f True 

Və bu, int dəyərləri ilə məhdudlaşmır:

 >>> g, h = 42.23e100, 42.23e100 >>> g is h True 

Aydındır ki, CPython 42.23e100 üçün əvvəlcədən yaradılmış bir float dəyəri ilə 42.23e100 . Beləliklə burada nə baş verir?

CPython kompilyatoru, int , float , str , bytes kimi bir sıra tanınmış dəyişkən növlərin daimi birləşmələrini birləşmə vahidində birləşdirəcəkdir. Bir modul üçün, bütün modul bir tərtibat vahidi, lakin interaktiv tərcüməçidə hər bir fərziyyə ayrı bir tərtib qurğudır. cd ayrı hesabatlarda müəyyən edildiyindən onların dəyərləri birləşdirilməyib. ef eyni bəyanatda müəyyən edildiyindən onların dəyərləri birləşdirilir.


Baytın sökülməsi ilə nə baş verdiyini görə bilərsiniz. e, f = 128, 128 yerinə yetirən bir funksiyanı təsvir etməyə çalışın və sonra dis.dis və bir sabit dəyəri (128, 128)

 >>> def f(): i, j = 258, 258 >>> dis.dis(f) 1 0 LOAD_CONST 2 ((128, 128)) 2 UNPACK_SEQUENCE 2 4 STORE_FAST 0 (i) 6 STORE_FAST 1 (j) 8 LOAD_CONST 0 (None) 10 RETURN_VALUE >>> f.__code__.co_consts (None, 128, (128, 128)) >>> id(f.__code__.co_consts[1], f.__code__.co_consts[2][0], f.__code__.co_consts[2][1]) 4305296480, 4305296480, 4305296480 

Kompilyatorun 128 kodunu sabit olaraq saxladığını 128 , bəlkə, byte kodu istifadə etmirsə, CPython kompilyatorunun optimallaşdırılmasının az olduğu barədə bir fikir verir. Bu (boş olmayan) cütlüklər həqiqətən birləşməməsi deməkdir:

 >>> k, l = (1, 2), (1, 2) >>> k is l False 

Funksiyaya qoyun, onu buraxın və co_consts - eyni 12 olan (1, 2) cüt var, eyni ((1, 2), (1, 2)) iki fərqli eynidir.


CPython'un yerinə yetirdiyi başqa bir optimallaşdırma var: string interning. Kompilyator sabitini əyilməkdən fərqli olaraq, bu, mənbə qaynaqları ilə məhdudlaşmır:

 >>> m = 'abc' >>> n = 'abc' >>> m is n True 

Digər tərəfdən, "ascii compact", "compact" və ya "legacy ready" lərin daxili saxlama xətti və bir çox hallarda yalnız "ascii kompakt" tipi ilə məhdudlaşır.


Hər halda, dəyərlərin olması üçün tətbiq olunan qaydalar tətbiq olunmadan həyata keçirilə bilər, ya da eyni tətbiqin versiyaları ilə, hətta eyni kodun işləkləri arasında, həmin eyni nüsxədə eyni ola bilər eyni tətbiq

Bəzi Python əyləncə üçün qaydaları araşdırmağa dəyər ola bilər. Ancaq kodunuzda bunlara güvənməliyik. Yalnız etibarlı qayda:

  • Не пишите код, который предполагает наличие двух равных, но отдельно созданных неизменяемых значений.
  • Не пишите код, который предполагает наличие двух равных, но отдельно созданных неизменяемых значений.

Или, другими словами, только использование is для проверки документально одиночек (например, None ), или которые только созданы в одном месте в коде (как _sentinel = object() идиомы).

2
ответ дан abarnert 25 марта '18 в 6:48 2018-03-25 06:48

Другие вопросы по меткам или Задайте вопрос