"হয়" অপারেটরটি পূর্ণসংখ্যার সাথে অপ্রত্যাশিতভাবে আচরণ করে


509

পাইথনে নিম্নলিখিতগুলি অপ্রত্যাশিতভাবে আচরণ করে কেন?

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

আমি পাইথন 2.5.5 ব্যবহার করছি। পাইথনের কয়েকটি ভিন্ন সংস্করণ চেষ্টা করে দেখা যাচ্ছে যে পাইথন ২.৩.৩ 99 এবং 100 এর মধ্যে উপরের আচরণটি দেখায়।

উপরের ভিত্তিতে, আমি অনুমান করতে পারি যে পাইথন অভ্যন্তরীণভাবে প্রয়োগ করা হয়েছে যে "ছোট" পূর্ণসংখ্যা বড় সংখ্যার চেয়ে আলাদা উপায়ে সংরক্ষণ করা হয় এবং isঅপারেটর পার্থক্যটি বলতে পারে। ফুটো বিমূর্ততা কেন? দু'টি স্বেচ্ছাচারী বস্তুর তুলনা করার আরও ভাল উপায় কী, যখন আমি আগাম জানি না যে তারা সংখ্যা কিনা না সেগুলি একই হয় কিনা?


1
এখানে একবার দেখুন > বর্তমান বাস্তবায়ন সমস্ত>> -5 এবং 256 এর মধ্যে পূর্ণসংখ্যার অবজেক্টের একটি অ্যারে রাখে, আপনি যখন এই পরিসীমাটিতে কোনও int তৈরি করেন আপনি> বাস্তবে কেবল বিদ্যমান অবজেক্টের একটি রেফারেন্স ফিরে পান।
ব্যবহারকারী5319825

2
এটি একটি সিপথন-নির্দিষ্ট বাস্তবায়ন বিশদ এবং একটি
অপরিজ্ঞাত

উত্তর:


392

এক নজর দেখে নাও:

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

পাইথন 2 ডকুমেন্টেশনে আমি যা পেয়েছি তা এখানে, "সমতল পূর্ণসংখ্যার বিষয়গুলি" ( পাইথন 3 এর ক্ষেত্রে এটি একই ):

বর্তমান বাস্তবায়ন -5 এবং 256 এর মধ্যে সমস্ত পূর্ণসংখ্যার জন্য পূর্ণসংখ্যার অবজেক্টগুলির একটি অ্যারে রাখে, আপনি যখন এই পরিসীমাটিতে কোনও int তৈরি করেন আপনি বাস্তবে কেবল বিদ্যমান অবজেক্টের একটি রেফারেন্স ফিরে পাবেন। সুতরাং 1 টির মান পরিবর্তন করা উচিত I আমি সন্দেহ করি যে ক্ষেত্রে পাইথনের আচরণ অপরিজ্ঞাত। :-)


46
কেউ কি জানেন যে এই পরিসীমাটি (-5, 256) কীভাবে বেছে নেওয়া হয়েছিল? এটি যদি (0, 255) বা এমনকি (-255, 255) হত তবে আমি খুব অবাক হব না, তবে 265 সংখ্যার -5 থেকে শুরু করে বিস্ময়করভাবে নির্বিচারে মনে হচ্ছে।
উড্রো বারলো

6
@ উড্রোবার্লো: আমি মনে করি সাধারণ-নেতিবাচক স্থানধারীদের ক্যাপচার করার জন্য -5 হ'ল এক তাত্পর্যপূর্ণ। 0..255 একক বাইট মানগুলির অ্যারেগুলিকে কভার করে। এটি 256 এটি রহস্যজনক, তবে আমার ধারণা (এটি) বাইটে / থেকে পূর্ণসংখ্যাগুলি একত্র করার জন্য dis
ডেভিস হেরিং 27'18

3
আমি যেটি বুঝি সেগুলি থেকে একাধিক প্রকল্পের (এবং একাধিক ভাষা) জুড়ে সাধারণভাবে ব্যবহৃত মানগুলি দেখে বেছে নেওয়া হয়েছিল।
টনি সাফলক 66

9
Reddit.com/r/Python/comments/18leav/… অনুসারে , ব্যাপ্তিটি [-5,100] ব্যবহৃত হত। বাইট মানগুলির সম্পূর্ণ পরিসীমা অন্তর্ভুক্ত করার জন্য এটি বাড়ানো হয়েছিল - 256, কারণ সম্ভবত এটি একটি সাধারণ সংখ্যা।
mwfearnley

2
@ আশওয়ানি আপনার মন্তব্যের ঠিক পরে মন্তব্যগুলি পড়ার চেষ্টা করুন, আপনার দু'বছর আগে পোস্ট করেছেন এবং আপনি আপনার প্রশ্নের উত্তর খুঁজে পাবেন।
জেবিজি

116

পাইথনের "ইজ" অপারেটরটি সংখ্যার সাথে অপ্রত্যাশিতভাবে আচরণ করে?

সংক্ষেপে - আমাকে জোর দেওয়া যাক: পূর্ণসংখ্যার তুলনা করতে ব্যবহার করবেন না is

এটি এমন আচরণ নয় যা সম্পর্কে আপনার কোনও প্রত্যাশা থাকা উচিত।

পরিবর্তে, যথাক্রমে সাম্য এবং বৈষম্যের জন্য ব্যবহার করুন ==এবং !=তুলনা করুন। উদাহরণ স্বরূপ:

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

ব্যাখ্যা

এটি জানতে, আপনাকে নিম্নলিখিতগুলি জানতে হবে।

প্রথম, কি করে is? এটি তুলনা অপারেটর is ডকুমেন্টেশন থেকে :

অবজেক্ট সনাক্তকরণের জন্য অপারেটর isএবং is notপরীক্ষা: x is yসত্য যদি x এবং y একই বস্তু হয় true x is not yবিপরীত সত্যের মান দেয়।

এবং সুতরাং নীচের সমতুল্য।

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

ডকুমেন্টেশন থেকে :

id কোনও বস্তুর "পরিচয়" ফিরিয়ে দিন। এটি একটি পূর্ণসংখ্যা (বা দীর্ঘ পূর্ণসংখ্যা) যা তার জীবদ্দশায় এই বিষয়টির জন্য অনন্য এবং ধ্রুবক হওয়ার গ্যারান্টিযুক্ত। না-ওভারল্যাপিং লাইফটাইমযুক্ত দুটি বস্তুর একই id()মান থাকতে পারে ।

নোট করুন যে সিপিথনের কোনও বস্তুর আইডি (পাইথনের রেফারেন্স বাস্তবায়ন) মেমরির অবস্থানটি একটি বাস্তবায়ন বিশদ। পাইথনের অন্যান্য বাস্তবায়ন (যেমন জাইথন ​​বা আয়রন পাইথন) এর জন্য সহজেই আলাদা প্রয়োগ হতে পারেid

তাহলে ব্যবহারের ক্ষেত্রে isকী? পিইপি 8 বর্ণনা করে :

সিঙ্গেলনের মতো তুলনা Noneসর্বদা isবা is notসমতা অপারেটরগুলির সাথে করা উচিত ।

প্রশ্নটি

আপনি নিম্নলিখিত প্রশ্নটি জিজ্ঞাসা করুন এবং বলুন (কোড সহ):

পাইথনে নিম্নলিখিতগুলি অপ্রত্যাশিতভাবে আচরণ করে কেন?

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

এটা না একটি প্রত্যাশিত ফলাফল। কেন এটি আশা করা হয়? এটা শুধুমাত্র এর মানে হল যে পূর্ণসংখ্যার এ মূল্যবান 256উভয় দ্বারা সমর্থিত aএবং bপূর্ণসংখ্যা একই উদাহরণস্বরূপ হয়। পাইথনে পূর্ণসংখ্যা পরিবর্তনযোগ্য, সুতরাং তারা পরিবর্তন করতে পারে না। এটি কোনও কোডে প্রভাব ফেলবে না। এটা আশা করা উচিত নয়। এটি নিছক বাস্তবায়নের বিশদ।

তবে সম্ভবত আমাদের আনন্দিত হওয়া উচিত যে প্রতিবারের মূল্য 256 এর সমান বললে মেমরিতে কোনও নতুন আলাদা নজির নেই।

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

দেখে মনে হচ্ছে আমাদের কাছে এখন 257মেমরির মান সহ পূর্ণসংখ্যার দুটি পৃথক দৃষ্টান্ত রয়েছে । পূর্ণসংখ্যা যেহেতু পরিবর্তনযোগ্য, তাই এটি স্মৃতিশক্তি অপচয় করে। আসুন আশা করি আমরা এর প্রচুর অপচয় করছি না। আমরা সম্ভবত না। তবে এই আচরণের গ্যারান্টি নেই।

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

ঠিক আছে, দেখে মনে হচ্ছে আপনার পাইথনের বিশেষ প্রয়োগটি স্মার্ট হওয়ার চেষ্টা করছে এবং স্মরণে অপ্রয়োজনীয় মূল্যবান পূর্ণসংখ্যা তৈরি না করে যদি না হয় not আপনি পাইথন, যা সিপিথন, এর পৃথক বাস্তবায়ন ব্যবহার করছেন বলে মনে হচ্ছে। সিপিথনের পক্ষে ভালো।

এটি আরও ভাল হতে পারে সিপিথন বিশ্বব্যাপী এটি করতে পারত, যদি এটি এতটা সস্তাভাবে করতে পারে (যেমন দেখার জন্য ব্যয় হবে), অন্য কোনও বাস্তবায়ন হতে পারে।

কোডে প্রভাব হিসাবে, কোনও পূর্ণসংখ্যার কোনও পূর্ণসংখ্যার কোনও নির্দিষ্ট উদাহরণ হলে আপনার যত্ন নেওয়া উচিত নয়। আপনার কেবলমাত্র সেই উদাহরণটির মূল্য কী তা যত্নশীল হওয়া উচিত এবং আপনি তার জন্য সাধারণ তুলনা অপারেটরগুলি ব্যবহার করবেন==

কি is করে

isচেক যে idদুটি বস্তুর একই। সিপিথনে, এটি idমেমরির অবস্থান, তবে এটি অন্য বাস্তবায়নে কিছু অনন্যভাবে চিহ্নিতকরণ নম্বর হতে পারে। কোড সহ এটি পুনরায় চালু করতে:

>>> a is b

হিসাবে একই

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

কেন আমরা isতখন ব্যবহার করতে চাই ?

এটি বলার তুলনায় এটি খুব দ্রুত চেক হতে পারে, দুটি খুব দীর্ঘ স্ট্রিংয়ের মান সমান কিনা তা পরীক্ষা করা। তবে যেহেতু এটি বস্তুর স্বতন্ত্রতার জন্য প্রযোজ্য, সুতরাং আমাদের এটির জন্য সীমিত ব্যবহারের কেস রয়েছে। প্রকৃতপক্ষে, আমরা এটি বেশিরভাগের জন্য যাচাই করার জন্য এটি ব্যবহার করতে চাই None, যা একটি সিঙ্গলটন (স্মৃতিতে এক জায়গায় বিদ্যমান একমাত্র উদাহরণ)। আমরা অন্যান্য সিলেটলেটগুলি তৈরি করতে পারি যদি তাদের সংক্রামিত হওয়ার সম্ভাবনা থাকে তবে আমরা এটি যাচাই করতে পারি is, তবে এগুলি তুলনামূলকভাবে বিরল। এখানে উদাহরণ (পাইথন 2 এবং 3 এ কাজ করবে) উদাহরণস্বরূপ

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

কোন মুদ্রণ:

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

তাই আমরা দেখতে, সঙ্গে isএকটি প্রহরী, আমরা যখন মধ্যে পার্থক্য করতে সক্ষম হয় barকোন যুক্তি দিয়ে বলা হয় এবং এটির সাথে বলা হয় যখন None। এটি প্রাথমিক ব্যবহারের ক্ষেত্রে is- এটি পূর্ণসংখ্যা, স্ট্রিং, টিপলস বা এ জাতীয় অন্যান্য জিনিসের সমতার জন্য পরীক্ষা করার জন্য এটি ব্যবহার করবেন না


"এটি প্রাথমিক ব্যবহারের ক্ষেত্রে is- এটি পূর্ণসংখ্যা, স্ট্রিং, টিপলস বা এ জাতীয় অন্যান্য জিনিসের সমতার জন্য পরীক্ষা করার জন্য এটি ব্যবহার করবেন না।" তবে আমি একটি সাধারণ রাষ্ট্রযন্ত্রকে আমার শ্রেণিতে সংহত করার চেষ্টা করছি এবং যেহেতু রাজ্যগুলি অস্বচ্ছ মান যার একমাত্র পর্যবেক্ষণযোগ্য সম্পত্তি হ'ল অভিন্ন বা পৃথক হওয়ার কারণে তাদের তুলনা করা একেবারেই স্বাভাবিক বলে মনে হয় is। আমি অভ্যন্তরীণ স্ট্রিংগুলিকে রাজ্য হিসাবে ব্যবহার করার পরিকল্পনা করছি। আমি সরল পূর্ণসংখ্যার পছন্দ করতাম, তবে দুর্ভাগ্যক্রমে পাইথন আন্তঃসংখ্যকে ইন্টার্ন করতে পারে না ( 0 is 0এটি বাস্তবায়নের বিশদ)।
আলেক্সি

@ অ্যালেক্সার মতো মনে হচ্ছে আপনার এনাম দরকার? stackoverflow.com/questions/37601644/...
হারুন হলের

সম্ভবত, ধন্যবাদ, তাদের সম্পর্কে জানতাম না। আপনার আইএমওর উত্তর দেওয়ার জন্য এটি উপযুক্ত সংযোজন হতে পারে।
আলেক্সি

আপনার উত্তরে সেন্ডিনেলের মতো অনেকগুলি বোবা জিনিস ব্যবহার করা আরও হালকা ওজনের সমাধান হতে পারে ...
আলেক্সি

অ্যালেক্সি এনামগুলি পাইথন 3 স্ট্যান্ডার্ড লাইব্রেরিতে রয়েছে এবং এটি সম্ভবত আপনার কোডটি খালি সেন্ডিনেলের চেয়ে কিছুটা অর্থবহ হতে উত্সাহিত করবে।
হারুন হলের

60

এটি নির্ভর করে যে আপনি 2 টি জিনিস সমান বা একই অবজেক্টের সন্ধান করছেন কিনা তা নির্ভর করে।

isতারা সমান নয়, একই বস্তু কিনা তা পরীক্ষা করে দেখুন। ছোট ints সম্ভবত স্থান দক্ষতার জন্য একই মেমরি অবস্থান নির্দেশ করে

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

==স্বেচ্ছাচারিত বস্তুর সমতার তুলনা করতে আপনার ব্যবহার করা উচিত । আপনি __eq__এবং __ne__বৈশিষ্ট্যগুলির সাথে আচরণটি নির্দিষ্ট করতে পারেন ।


ওপি যেমন জিজ্ঞাসা করেছিল ঠিক কীভাবে স্বেচ্ছাচারিত বস্তুর তুলনা করতে পারে তা বোঝানোর জন্য থাম্বস আপ!
Joooeey

54

আমি দেরী করছি কিন্তু, আপনি কি আপনার উত্তর দিয়ে কিছু উত্স চান? আমি চেষ্টা করব এবং এটি একটি প্রাথমিক উপায়ে শব্দ করব যাতে আরও লোকেরা অনুসরণ করতে পারে।


সিপিথন সম্পর্কে একটি ভাল বিষয় হ'ল আপনি এটির জন্য উত্সটি দেখতে পাচ্ছেন। আমি 3.5 রিলিজের জন্য লিঙ্কগুলি ব্যবহার করতে যাচ্ছি , তবে সংশ্লিষ্ট 2.x এর সন্ধান করা তুচ্ছ।

CPython সালে সি-এপিআই ফাংশন যা হ্যান্ডলগুলি একটি নতুন তৈরি intঅবজেক্ট PyLong_FromLong(long v)। এই ফাংশনটির জন্য বিবরণটি হ'ল:

বর্তমান বাস্তবায়ন -5 এবং 256 এর মধ্যে সমস্ত পূর্ণসংখ্যার জন্য পূর্ণসংখ্যার অবজেক্টগুলির একটি অ্যারে রাখে, আপনি যখন এই পরিসীমাটিতে কোনও int তৈরি করেন আপনি বাস্তবে কেবল বিদ্যমান অবজেক্টের একটি রেফারেন্স ফিরে পাবেন । সুতরাং 1 টির মান পরিবর্তন করা উচিত I আমি সন্দেহ করি যে ক্ষেত্রে পাইথনের আচরণ অপরিজ্ঞাত। :-)

(আমার তির্যক)

আপনার সম্পর্কে জানেন না তবে আমি এটি দেখতে এবং মনে করি: আসুন সেই অ্যারেটি খুঁজে বার করুন!

আপনি সিপিথন সি কোড প্রয়োগকারী সি কোডের সাথে ঝাঁকুনি না থাকলে আপনার উচিত ; সবকিছু বেশ সুসংহত এবং পাঠযোগ্য। আমাদের ক্ষেত্রে, আমাদের মূল উত্স কোড ডিরেক্টরি গাছের Objectsউপ - ডিরেক্টরিতে সন্ধান করা উচিত

PyLong_FromLonglongঅবজেক্টগুলির সাথে ডিল করে যাতে আমাদের ভিতরে উঁকি দেওয়ার দরকার অনুমান করা শক্ত হওয়া উচিত নয় longobject.c। ভিতরে দেখার পরে আপনি ভাবতে পারেন বিষয়গুলি বিশৃঙ্খল; সেগুলি রয়েছে তবে ভয় পাবেন না, আমরা যে ফাংশনটি সন্ধান করছি তা 230 লাইনে শীতল হওয়া আমাদের এটি দেখার জন্য অপেক্ষা করছে। এটি একটি ছোট্ট ফাংশন তাই মূল শরীরটি (ঘোষণা বাদে) সহজেই এখানে আটকানো হয়:

PyObject *
PyLong_FromLong(long ival)
{
    // omitting declarations

    CHECK_SMALL_INT(ival);

    if (ival < 0) {
        /* negate: cant write this as abs_ival = -ival since that
           invokes undefined behaviour when ival is LONG_MIN */
        abs_ival = 0U-(unsigned long)ival;
        sign = -1;
    }
    else {
        abs_ival = (unsigned long)ival;
    }

    /* Fast path for single-digit ints */
    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; 
}

এখন, আমরা কোনও সি -মাস্টার-কোড-হ্যাক্সক্সোরজ নই তবে আমরা বোবাও নই, আমরা দেখতে পাচ্ছি যে CHECK_SMALL_INT(ival);আমাদের সকলকে প্রলোভনমূলকভাবে উঁকি দিচ্ছে ; এর সাথে কিছু করার আছে আমরা বুঝতে পারি। আসুন এটি পরীক্ষা করে দেখুন:

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

সুতরাং এটি ম্যাক্রো যা ফাংশনকে কল করে get_small_intযদি মানটি ivalশর্তটি পূরণ করে:

if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS)

তাই কি হয় NSMALLNEGINTSএবং NSMALLPOSINTS? ম্যাক্রো! তারা এখানে :

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

সুতরাং আমাদের অবস্থা if (-5 <= ival && ival < 257)কলget_small_int

এর আসুন এর get_small_intসমস্ত গৌরবটি দেখি (ভাল, আমরা কেবল তার শরীরের দিকে নজর দেব কারণ আকর্ষণীয় জিনিসগুলি এখানে):

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

ঠিক আছে, একটি ঘোষণা করুন PyObject, পূর্ববর্তী শর্তটি অ্যাসাইনমেন্টটি কার্যকর করে তা কার্যকর করুন:

v = (PyObject *)&small_ints[ival + NSMALLNEGINTS];

small_intsদেখতে অনেকটা অ্যারের মতো দেখতে আমরা অনুসন্ধান করেছিলাম, এবং এটি! আমরা কেবল অভিশাপের ডকুমেন্টেশনটি পড়তে পারতাম এবং আমরা সবই জানতাম! :

/* Small integers are preallocated in this array so that they
   can be shared.
   The integers that are preallocated are those in the range
   -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
*/
static PyLongObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS];

হ্যাঁ, এই আমাদের লোক। আপনি যখন intপরিসরে একটি নতুন তৈরি করতে চান[NSMALLNEGINTS, NSMALLPOSINTS) কেবল পূর্বনির্ধারিত অবস্থায় থাকা একটি ইতিমধ্যে বিদ্যমান অবজেক্টের একটি রেফারেন্স ফিরে পাবেন।

যেহেতু রেফারেন্সটি একই অবজেক্টকে বোঝায়, id()সরাসরি জারি করা বা সাথে পরিচয় চেক করাis এটির ঠিক একই জিনিসটি ফিরে আসবে।

তবে, এগুলো কখন বরাদ্দ করা হয় ??

_PyLong_Initপাইথনে ইনিশিয়েশন চলাকালীন খুশিতে একটি লুপের জন্য প্রবেশ করবে আপনার জন্য এটি করুন:

for (ival = -NSMALLNEGINTS; ival <  NSMALLPOSINTS; ival++, v++) {

লুপ বডি পড়তে উত্সটি দেখুন!

আমি আশা করি আমার ব্যাখ্যা আপনাকে স্পষ্টত সি জিনিস তৈরি করেছে (শাস্তি স্পষ্টভাবে উদ্দেশ্যযুক্ত)।


কিন্তু 257 is 257,? কি খবর?

এটি ব্যাখ্যা করা আসলে সহজ, এবং আমি ইতিমধ্যে এটি করার চেষ্টা করেছি ; পাইথন এই ইন্টারেক্টিভ স্টেটমেন্টটিকে একক ব্লক হিসাবে কার্যকর করবে এই কারণে এটি ঘটে:

>>> 257 is 257

এই বিবৃতিটির প্রশংসা করার সময়, সিপিথন দেখতে পাবে যে আপনার দুটি মিল রয়েছে ral PyLongObject প্রতিনিধিত্বকারী257 । আপনি নিজেই এই সংকলনটি করতে এবং এর বিষয়বস্তুগুলি পরীক্ষা করে দেখতে পারেন:

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

সিপিথন যখন অপারেশন করে, এটি এখন ঠিক একই জিনিসটি লোড করতে চলেছে:

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

তাই isফিরে আসবে True


37

যেমন আপনি সোর্স ফাইল inbject.c এ চেক করতে পারেন , পাইথন দক্ষতার জন্য ছোট ছোট পূর্ণসংখ্যাকে ক্যাশে করেআপনি যখনই একটি ছোট পূর্ণসংখ্যার জন্য একটি রেফারেন্স তৈরি করেন, আপনি ক্যাশেড ছোট পূর্ণসংখ্যাকে উল্লেখ করছেন, কোনও নতুন অবজেক্ট নয়। 257 একটি ছোট পূর্ণসংখ্যা নয়, সুতরাং এটি একটি পৃথক অবজেক্ট হিসাবে গণনা করা হয়।

==সেই উদ্দেশ্যে ব্যবহার করা ভাল ।


19

আমি মনে করি আপনার অনুমানগুলি সঠিক। id(বস্তুর পরিচয়) সহ পরীক্ষা :

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)

দেখা যাচ্ছে যে সংখ্যাগুলিকে <= 255আক্ষরিক হিসাবে বিবেচনা করা হয় এবং উপরের যে কোনও কিছুকে আলাদাভাবে বিবেচনা করা হয়!


1
কারণ -5 থেকে + 256 পর্যন্ত মানগুলি উপস্থাপনকারী অবজেক্টগুলি প্রারম্ভকালে তৈরি করা হয়েছিল - এবং তাই সেই মানটির সমস্ত ব্যবহার প্রাক-বিল্ট অবজেক্টে ব্যবহৃত হয়। এই ব্যাপ্তির বাইরের পূর্ণসংখ্যার প্রায় সমস্ত রেফারেন্স প্রতিটি সময় তাদের উল্লেখ করা হলে একটি নতুন অভ্যন্তরীণ বস্তু তৈরি করে। আমি মনে করি আক্ষরিক শব্দটির ব্যবহার বিভ্রান্তিকর - আক্ষরিকরূপে কোডের কোনও অংশে টাইপ করা কোনও মানকে আক্ষরিক অর্থে বোঝায় - সুতরাং উত্স কোডের সমস্ত সংখ্যাটি আক্ষরিক হয়।
টনি সাফলক 66

13

অন্তরঙ্গ, স্ট্রিং বা তারিখের সময়গুলির মতো অপরিবর্তনীয় মান সামগ্রীর জন্য, অবজেক্টের পরিচয় বিশেষভাবে কার্যকর নয়। সমতা সম্পর্কে ভাবা ভাল। পরিচয় হ'ল মূলত মান বস্তুগুলির জন্য একটি বাস্তবায়ন বিশদ - যেহেতু তারা পরিবর্তনযোগ্য, তাই একই বস্তু বা একাধিক বস্তুর একাধিক রেফ থাকার মধ্যে কোনও কার্যকর পার্থক্য নেই।


12

আবার একটি সমস্যা রয়েছে যা বিদ্যমান উত্তরের কোনওটিতেই নির্দেশিত নয়। পাইথনকে যে কোনও দুটি অপরিবর্তনীয় মানকে মার্জ করার অনুমতি দেওয়া হয়েছে এবং প্রাক-তৈরি ছোট ছোট মানগুলি কেবল এটিই ঘটতে পারে না। পাইথনের বাস্তবায়ন কখনই এটির জন্য গ্যারান্টিযুক্ত হয় না তবে তারা সকলেই এটি কেবলমাত্র ছোট্ট ints এর চেয়ে বেশি কিছু করে।


একটা কারণ হল, এমন খালি হিসাবে কিছু অন্যান্য প্রাক নির্মিত মূল্যবোধ, হয় tuple, strএবং bytes, এবং কিছু ছোট স্ট্রিং (CPython 3.6, এটা 256 একক-অক্ষর ল্যাটিন -1 স্ট্রিং এর)। উদাহরণ স্বরূপ:

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

এছাড়াও, এমনকি প্রাক-প্রাক-তৈরি করা মানগুলি অভিন্ন হতে পারে। এই উদাহরণগুলি বিবেচনা করুন:

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

এবং এটি intমানগুলির মধ্যে সীমাবদ্ধ নয় :

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

স্পষ্টতই, সিপিথন এর floatজন্য প্রাক-তৈরি মান নিয়ে আসে না 42.23e100। তো, এখানে কি চলছে?

CPython কম্পাইলার মত কিছু known-অপরিবর্তনীয় ধরনের ধ্রুবক মান একত্র করে দেবে int, float, str, bytes, একই সংকলন ইউনিটে। মডিউলটির জন্য, পুরো মডিউলটি একটি সংকলন ইউনিট, তবে ইন্টারেক্টিভ ইন্টারপ্রেটারে প্রতিটি বিবৃতি পৃথক সংকলন ইউনিট। যেহেতু cএবং dপৃথক বিবৃতিতে সংজ্ঞায়িত হয়েছে, তাদের মানগুলি একত্রিত হয় না। যেহেতু eএবং fএকই বিবৃতিতে সংজ্ঞায়িত হয়েছে, তাদের মানগুলি একত্রিত করা হয়েছে।


বাইটকোড বিচ্ছিন্ন করে আপনি কী দেখতে পাচ্ছেন। এমন একটি ক্রিয়াটি সংজ্ঞায়িত করার চেষ্টা করুন যা e, f = 128, 128তারপরে কল dis.disকরে এবং আপনি দেখতে পাবেন যে একক ধ্রুবক মান রয়েছে(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

আপনি খেয়াল করতে পারেন যে কম্পাইলারটি 128বাইটকোড দ্বারা বাস্তবে ব্যবহৃত না হলেও এটি একটি ধ্রুবক হিসাবে সঞ্চিত রয়েছে , যা আপনাকে সিপিথনের সংকলকটি কতটা অপ্টিমাইজেশন করে তা একটি ধারণা দেয়। যার অর্থ হ'ল (খালি নয়) টিপলগুলি আসলে মার্জ হয়ে শেষ করে না:

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

রাখুন যে একটা ফাংশন এ, disএটা এবং তাকান co_constsআছে একটি এর 1এবং 2দুই (1, 2)tuples একই ভাগ করতে বলেছে 1এবং 2কিন্তু অভিন্ন নয়, এবং একটি ((1, 2), (1, 2))tuple দুটি স্বতন্ত্র সমান tuples রয়েছে।


সিপিথনের আরও একটি অপটিমাইজেশন রয়েছে: স্ট্রিং ইন্টার্নিং। সংকলক ধ্রুবক ভাঁজ থেকে পৃথক, এটি উত্স কোড আক্ষরিক মধ্যে সীমাবদ্ধ নয়:

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

অন্যদিকে, এটি কেবল strটাইপ এবং অভ্যন্তরীণ স্টোরেজ ধরণের স্ট্রিংগুলিতে সীমাবদ্ধ "এসকিআই কমপ্যাক্ট", "কমপ্যাক্ট", বা "উত্তরাধিকার প্রস্তুত" এবং অনেক ক্ষেত্রে কেবল "এসকিআই কমপ্যাক্ট" অভ্যন্তরীণ হবে।


যে কোনও হারে, মানগুলি কী কী হতে হবে তার বিধিগুলি হতে পারে, বাস্তবায়নের ক্ষেত্রে এবং একই প্রয়োগের সংস্করণগুলির মধ্যে এবং একই প্রয়োগের একই অনুলিপিতে একই কোডের রানগুলির মধ্যেও আলাদা হতে পারে ।

এটি মজাদার জন্য একটি নির্দিষ্ট পাইথনের নিয়মগুলি শেখার পক্ষে মূল্যবান হতে পারে। তবে আপনার কোডে তাদের উপর নির্ভর করার মতো নয়। একমাত্র নিরাপদ নিয়ম:

  • কোডটি লিখবেন না যা দুটি সমান বলে ধরে নেয় তবে পৃথকভাবে তৈরি অপরিবর্তনীয় মানগুলি অভিন্ন (ব্যবহার করবেন না x is y, ব্যবহার করবেন না x == y)
  • কোডটি লিখবেন না যা দুটি সমান বলে ধরে নিয়েছে তবে পৃথকভাবে তৈরি অপরিবর্তনীয় মানগুলি পৃথক (ব্যবহার করবেন না x is not y, ব্যবহার করবেন না x != y)

অথবা, অন্য কথায়, কেবলমাত্র isনথিভুক্ত সিলেটলেটনের (যেমন None) পরীক্ষার জন্য ব্যবহার করুন বা যা কোডের এক জায়গায় ( _sentinel = object()আইডিয়মের মতো ) তৈরি করা হয়েছে।


কম ক্রিপ্টিক পরামর্শটি সহজ: x is yতুলনা, ব্যবহার করতে ব্যবহার করবেন না x == y। তেমনি ব্যবহার করবেন না x is not y, ব্যবহার করবেন নাx != y
স্মি

সুতরাং এই প্রশ্নটি খুঁজছেন , কেন a=257; b=257একটি এক লাইনে a is bসত্য
জো

8

is হয় পরিচয় সমতা অপারেটর (যেমন কাজ id(a) == id(b)); এটি ঠিক যে দুটি সমান সংখ্যা অগত্যা একই জিনিস নয়। পারফরম্যান্সের কারণে কিছু ছোট পূর্ণসংখ্যার স্মৃতিচারণ করা যায় যাতে তারা একই রকম থাকে (এটি অপরিবর্তনীয় হওয়ার কারণে এটি করা যেতে পারে)।

===অন্যদিকে পিএইচপি-র অপারেটরটিকে সাম্য ও পরীক্ষা করার ধরণ হিসাবে বর্ণনা করা হয়েছে: x == y and type(x) == type(y)পাওলো ফ্রেইটাসের মন্তব্য অনুসারে। এটি সাধারণ সংখ্যার পক্ষে যথেষ্ট, তবে একটি ক্লাসহীন পদ্ধতিতে isসংজ্ঞায়িত ক্লাসগুলির থেকে পৃথক __eq__:

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

পিএইচপি স্পষ্টতই "বিল্ট-ইন" ক্লাসগুলির জন্য একই জিনিসকে অনুমতি দেয় (যা আমি পিএইচপি-তে নয়, সি স্তরে বাস্তবায়িত হতে চাই)। কিছুটা কম অযৌক্তিক ব্যবহার টাইমার অবজেক্ট হতে পারে, যা প্রতিবার এটি একটি সংখ্যা হিসাবে ব্যবহৃত হয় তার আলাদা মান থাকে। বেশ কেন তুমি ভিসুয়াল বেসিক এর অনুকরণ চাই চাই Nowপরিবর্তে দেখাচ্ছে যে এটা একটা মূল্যায়ন সঙ্গে হয় time.time()আমি জানি না।

গ্রেগ হিউগিল (ওপি) একটি স্পষ্ট করে মন্তব্য করেছে "আমার লক্ষ্য মানের সাম্যতার চেয়ে বস্তুর পরিচয় তুলনা করা। সংখ্যা বাদে যেখানে আমি বস্তুর পরিচয়কে মানের সমতা হিসাবে একই আচরণ করতে চাই।"

হিসাবে আমরা সংখ্যা বা না কিছু শ্রেণিবদ্ধ করার নির্বাচন হবে কিনা তা আমরা সঙ্গে তুলনা এই এখনও অন্য উত্তর আছে, হবে ==বা isসিপিথন সংখ্যা প্রোটোকল সংজ্ঞায়িত করে PyNumber_Check সহ, কিন্তু এই পাইথন নিজেই থেকে অ্যাক্সেসযোগ্য নয়।

আমরা যে isinstanceসকল সংখ্যা জানি আমরা তার সাথে ব্যবহার করার চেষ্টা করতে পারি তবে এটি অবশ্যম্ভাবী অসম্পূর্ণ। প্রকারের মডিউলটিতে একটি স্ট্রিংটাইপস তালিকা রয়েছে তবে নম্বর টাইপ নেই। পাইথন ২.6 থেকে, অন্তর্নির্মিত সংখ্যা ক্লাসগুলির একটি বেস ক্লাস numbers.Numberরয়েছে তবে এতে একই সমস্যা রয়েছে:

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

উপায় দ্বারা, NumPy কম সংখ্যার পৃথক উদাহরণ তৈরি করবে।

আমি আসলে প্রশ্নের এই বৈকল্পিকের একটি উত্তর জানি না। আমি ধারণা করি যে কেউ কল করার জন্য তাত্ত্বিকভাবে সিটিপ ব্যবহার করতে পারে PyNumber_Check, তবে এমনকি সেই ফাংশনটি নিয়েও বিতর্ক হয়েছে এবং এটি অবশ্যই বহনযোগ্য নয়। আমরা আপাতত যা পরীক্ষা করি সে সম্পর্কে আমাদের কম নির্দিষ্ট হতে হবে।

শেষ অবধি, এই সমস্যাটি পাইথন থেকে এসেছে যে মূলত স্কিম এর number? বা হ্যাস্কেলের ধরণের শ্রেণির নম্বরের পূর্বাভাস সহ কোনও টাইপ ট্রি নেই । isবস্তুর পরিচয় যাচাই করে, সমতার মূল্য দেয় না। পিএইচপি-র বর্ণা history্য ইতিহাসও রয়েছে, যেখানে ===দৃশ্যত isকেবল পিএইচপি 5 এর অবজেক্টগুলির সাথে আচরণ করা হয় তবে পিএইচপি 4 নয় । এগুলি হ'ল ভাষা জুড়ে চলার ক্রমবর্ধমান বেদনা (একটির সংস্করণ সহ)।


4

এটি স্ট্রিংগুলির সাথেও ঘটে:

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

এখন সবকিছু ঠিক আছে বলে মনে হচ্ছে।

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

এটাও প্রত্যাশিত।

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

এখন তা অপ্রত্যাশিত।


এই ঘটেছে - সম্মত, এমনকি weirder। তাই আমি এটি নিয়ে খেলেছি, এবং এটি এখনও অবাক - স্থানের সাথে সম্পর্কিত। উদাহরণস্বরূপ, স্ট্রিংটি 'xx'যেমনটি প্রত্যাশিত, তেমনি রয়েছে 'xxx'তবে 'x x'তা নয়।
ব্রায়ান

2
এর কারণ এটি কোনও চিহ্নের মতো দেখায় যদি এতে কোনও স্থান নেই। নামগুলি স্বয়ংক্রিয়ভাবে অভ্যন্তরীণ হয়ে গেছে, সুতরাং xxআপনার পাইথন সেশনে কোথাও কোথাও নামকরণ করা থাকলে সেই স্ট্রিং ইতিমধ্যে ইন্টার্ন করা হয়েছে; এবং এটি একটি হিউরিস্টিক হতে পারে যা এটি কেবল একটি নামের সাথে সাদৃশ্যযুক্ত থাকলে তা করে। সংখ্যার মতোই এটি করা যেতে পারে কারণ এগুলি অপরিবর্তনীয়। docs.python.org/2/library/function.html#intern guilload.com/python-string-interning
Yann Vernier

3

পাইথন ৩.৮-তে নতুন কী রয়েছে: পাইথনের আচরণে পরিবর্তন :

সংকলকটি এখন একটি সিনট্যাক্স ওয়ার্নিং তৈরি করে যখন সনাক্তকরণের পরীক্ষাগুলি ( isএবং is not) নির্দিষ্ট ধরণের আক্ষরিক (উদাহরণস্বরূপ স্ট্রিংস, ইনস ) সাথে ব্যবহৃত হয়। এগুলি প্রায়শই সিপিথনে দুর্ঘটনাক্রমে কাজ করতে পারে তবে ভাষা অনুচ্ছেদে এর গ্যারান্টি নেই। সতর্কতা ব্যবহারকারীদের পরিবর্তে সাম্যতা পরীক্ষা ( == এবং !=) ব্যবহার করার পরামর্শ দেয় ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.