পাইথনের "i + i + x" থেকে কখন "i + = x" আলাদা হয়?


212

আমাকে বলা হয়েছিল যে +=স্ট্যান্ডার্ড স্বরলিপি থেকে আলাদা প্রভাব থাকতে পারে i = i +। এমন কোনও মামলা আছে যা i += 1থেকে আলাদা হবে i = i + 1?


7
+=extend()তালিকার ক্ষেত্রে যেমন কাজ করে ।
অশ্বিনী চৌধুরী চৌধুরী

12
@AshwiniChaudhary সে খুবই সূক্ষ্ম পার্থক্য বিবেচনায় যে, i=[1,2,3];i=i+[4,5,6];i==[1,2,3,4,5,6]হয় True। অনেক বিকাশকারী নাও খেয়াল করতে পারে যে id(i)একটি অপারেশনের জন্য পরিবর্তন হয়েছে তবে অন্যটি নয়।
কোজিরো

1
@ কোজিরো - যদিও এটি একটি সূক্ষ্ম পার্থক্য, আমি মনে করি এটি একটি গুরুত্বপূর্ণ বিষয়।
মিগিলসন

@ মিগিলসন এটি গুরুত্বপূর্ণ, এবং আমি অনুভব করেছি যে এটির একটি ব্যাখ্যা দরকার। :)
কোজিরো

1
সংশ্লিষ্ট প্রশ্ন জাভা দুই মধ্যে পার্থক্য সংক্রান্ত: stackoverflow.com/a/7456548/245966
jakub.g

উত্তর:


317

এটি পুরোপুরি অবজেক্টের উপর নির্ভর করে i

+=কল __iadd__পদ্ধতি (এটা যদি উপস্থিত থাকে - ফিরে পতনশীল __add__যদি এটা কোন অস্তিত্ব নেই) যেহেতু +কল __add__পদ্ধতি 1 বা __radd__কয়েক ক্ষেত্রেই পদ্ধতি 2

একটি এপিআই দৃষ্টিকোণ থেকে, স্থান__iadd__ পরিবর্তনযোগ্য বস্তু পরিবর্তনের জন্য ব্যবহৃত হবে বলে মনে করা হচ্ছে (যে বস্তুটি রূপান্তরিত হয়েছিল তা ফেরত দেওয়া হয়েছে ) তবে কোনও কিছুর একটি নতুন উদাহরণ ফিরে আসা উচিত । জন্য অপরিবর্তনীয় বস্তু, উভয় পদ্ধতি একটি নতুন দৃষ্টান্ত আসতে, কিন্তু একই নামের পুরানো দৃষ্টান্ত ছিল বর্তমান নামস্থান নতুন দৃষ্টান্ত করবে। এই জন্যই__add____iadd__

i = 1
i += 1

বর্ধিত বলে মনে হচ্ছে i। বাস্তবে, আপনি একটি নতুন পূর্ণসংখ্যা পেয়েছেন এবং এটিকে "শীর্ষে" অর্পণ করুন i- পুরানো পূর্ণসংখ্যার একটি উল্লেখ হারিয়ে ফেলে। এই ক্ষেত্রে, i += 1ঠিক হিসাবে একই i = i + 1। তবে বেশিরভাগ পরিবর্তনযোগ্য বস্তুর সাথে এটি একটি ভিন্ন গল্প:

একটি দৃ concrete় উদাহরণ হিসাবে:

a = [1, 2, 3]
b = a
b += [1, 2, 3]
print a  #[1, 2, 3, 1, 2, 3]
print b  #[1, 2, 3, 1, 2, 3]

তুলনা করা:

a = [1, 2, 3]
b = a
b = b + [1, 2, 3]
print a #[1, 2, 3]
print b #[1, 2, 3, 1, 2, 3]

নোটিশ কিভাবে প্রথম উদাহরণে, যেহেতু bএবং aরেফারেন্স একই বস্তুর যখন আমি ব্যবহার +=উপর b, এটি একটি প্রকৃত পরিবর্তন b(এবং aতাও পরিবর্তন সূচিত - সব পরে, এটি একই তালিকা উল্লেখ করা হয়েছে)। তবে দ্বিতীয় ক্ষেত্রে, যখন আমি এটি করি b = b + [1, 2, 3], এটি সেই তালিকাটি bরেফারেন্স করছে এবং এটি একটি নতুন তালিকার সাথে যুক্ত করে [1, 2, 3]। এরপরে এটি বর্তমান নামস্থানে সংক্ষিপ্ত তালিকাটি সংরক্ষণ করে b- এর bআগে লাইনটি কী ছিল তা বিবেচনা ছাড়াই ।


1 এক্সপ্রেশনে x + y, যদি x.__add__বাস্তবায়িত হয়নি অথবা যদি x.__add__(y)আয় NotImplemented এবং xএবং yবিভিন্ন ধরনের আছে , তারপর x + yকল করার চেষ্টা করে y.__radd__(x)। সুতরাং, আপনার যেখানে আছে

foo_instance += bar_instance

যদি Fooবাস্তবায়ন না হয় __add__বা __iadd__তারপরে ফলাফল এখানে একই রকম

foo_instance = bar_instance.__radd__(bar_instance, foo_instance)

2 এক্সপ্রেশনে foo_instance + bar_instance, bar_instance.__radd__বিচার হবে সামনে foo_instance.__add__ যদি ধরণ bar_instanceধরণ একটি উপশ্রেণী হয় foo_instance(যেমন issubclass(Bar, Foo))। এই জন্য মূলদ কারণ Barএকটি "উচ্চ স্তরের" বস্তু চেয়ে কিছু অর্থে হয় Fooতাই Barঅগ্রাহ্য করার বিকল্প পাওয়া উচিত Foo'র আচরণ।


18
ঠিক আছে, +=কল __iadd__ থাকলে তা উপস্থিত থাকে এবং অন্যথায় যুক্ত ও পুনঃব্যবস্থা করতে ফিরে আসে। যে কারণ i = 1; i += 1নেই যদিও কাজ করে int.__iadd__। তবে সেই ছোটখাটো নীট ছাড়াও দুর্দান্ত ব্যাখ্যা।
3:30

4
@ বার্নার্ট - আমি সর্বদা ধরে নিয়েছি যে int.__iadd__সবেমাত্র ডাকা হয়েছে __add__। আমি আজ নতুন কিছু শিখতে পেরে আনন্দিত :)।
মিগিলসন

@abarnert - আমি হতে হয়তো অনুমান করা সম্পূর্ণ , x + yকল y.__radd__(x)যদি x.__add__(অথবা আয় অস্তিত্ব নেই NotImplementedএবং xএবং yবিভিন্ন ধরনের হয়)
mgilson

আপনি যদি সত্যিই সম্পূর্ণবাদী হতে চান তবে আপনাকে অবশ্যই উল্লেখ করতে হবে যে ক্লাসিক ক্লাস সহ কিছু গণ্ডগোল বাদে এবং "সিটি এপিআই" এ প্রয়োগ করা প্রকারের জন্য, "বিস্তৃত থাকলে" বিটটি সাধারণ গ্যাটট্রার প্রক্রিয়াগুলির মধ্য দিয়ে যায় এবং পরিবর্তে এটি উভয়ই সন্ধান করে nb_inplace_addবা sq_inplace_concat, এবং সি সি এপিআই ফাংশনগুলির পাইথন ডানডারের পদ্ধতিগুলির চেয়ে কঠোর প্রয়োজনীয়তা রয়েছে এবং ... তবে আমি মনে করি না যে এটি উত্তরের সাথে প্রাসঙ্গিক। মূল পার্থক্য হ'ল +=অভিনয়ের মতো ফিরে আসার আগে একটি জায়গায় যুক্ত করার চেষ্টা করে +যা আমি মনে করি আপনি ইতিমধ্যে ব্যাখ্যা করেছেন।
অবার্নার্ট

হ্যাঁ, আমি মনে করি আপনি ঠিক বলেছেন ... যদিও আমি কেবল এই অবস্থানটিতে ফিরে যেতে পারলাম যে সিআইপিটি পাইথনের অংশ নয় । এটা তোলে এর অংশ Cpython :-P
mgilson

67

প্রচ্ছদের নীচে, i += 1এই জাতীয় কিছু করে:

try:
    i = i.__iadd__(1)
except AttributeError:
    i = i.__add__(1)

i = i + 1এইরকম কিছু করার সময় :

i = i.__add__(1)

এটি সামান্য ওভারসিম্প্লিফিকেশন, তবে আপনি ধারণাটি পাবেন: পাইথন +=একটি __iadd__পদ্ধতি এবং একটি তৈরি করে বিশেষতভাবে পরিচালনা করার জন্য প্রকারগুলি দেয় __add__

অভিপ্রায়টি হ'ল পরিবর্তিত প্রকারগুলি, যেমন listতাদের মধ্যে রূপান্তরিত করবে __iadd__(এবং তারপরে ফিরে আসবে self, যদি না আপনি খুব কৃপণ কিছু করে থাকেন) তবে অপরিবর্তনীয় প্রকারগুলি intকেবল এটিকে বাস্তবায়ন করবে না।

উদাহরণ স্বরূপ:

>>> l1 = []
>>> l2 = l1
>>> l1 += [3]
>>> l2
[3]

কারণ l2হিসাবে একই বস্তু l1, এবং আপনি রূপান্তরিত l1, আপনিও পরিবর্তন l2

কিন্তু:

>>> l1 = []
>>> l2 = l1
>>> l1 = l1 + [3]
>>> l2
[]

এখানে, আপনি পরিবর্তন করতে পারেন নি l1; পরিবর্তে, আপনি একটি নতুন তালিকা তৈরি করেছেন এবং মূল তালিকার দিকে ইঙ্গিত রেখে l1 + [3]নামটিকে পুনরায় লক্ষ্য করুন ।l1l2

( +=সংস্করণে, আপনিও রিমন্ডিং করছিলেন l1, এটি ঠিক যে সেই ক্ষেত্রে আপনি listএটি ইতিমধ্যে আবদ্ধ হয়েছিলেন তেমন পুনরায় রিমান্ড দিচ্ছিলেন, তাই আপনি সাধারণত সেই অংশটি উপেক্ষা করতে পারেন))


__iadd__আসলেই কি কোন __add__ইভেন্টে ফোন করে AttributeError?
মিগিলসন

ঠিক আছে, i.__iadd__ডাকবে না __add__; এটা i += 1যে কল __add__
abarnert

ভুল ... হ্যাঁ, এটাই আমি বোঝাতে চাইছিলাম মজাদার. আমি বুঝতে পারিনি যে এটি স্বয়ংক্রিয়ভাবে সম্পন্ন হয়েছিল।
মিগিলসন

3
প্রথম প্রচেষ্টাটি আসলে i = i.__iadd__(1)- বস্তুটি জায়গায় সংশোধন iadd করতে পারে তবে তা করতে হবে না এবং তাই ফল উভয় ক্ষেত্রেই প্রত্যাবর্তন প্রত্যাশিত।
lvc

নোট এর অর্থ এই যে যে operator.iaddকল __add__উপর AttributeError, কিন্তু এটা ফলাফলের নতুন করে বাঁধানো না ... তাই i=1; operator.iadd(i, 1)আয় 2 এবং পাতার iসেট 1। যা কিছুটা বিভ্রান্তিকর।
abarnert

6

এখানে একটি উদাহরণ যা সরাসরি তুলনা i += xকরে i = i + x:

def foo(x):
  x = x + [42]

def bar(x):
  x += [42]

c = [27]
foo(c); # c is not changed
bar(c); # c is changed to [27, 42]
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.