পাইথন (এবং পাইথন সি এপিআই): __ নতুন__ বনাম __init__


126

আমি যে প্রশ্নটি জিজ্ঞাসা করতে চাইছি তা পাইথন দ্বারা __ নতুন__ এবং __init__ ব্যবহারের সদৃশ ? কিন্তু নির্বিশেষে, এটা এখনও স্পষ্ট নয় আমার কাছে ঠিক কি মধ্যে ব্যবহারিক পার্থক্য __new__এবং __init__হয়।

আপনি আমাকে তাড়াহুড়া করার আগে যে __new__জিনিসগুলি তৈরির জন্য এবং __init__অবজেক্টগুলি আরম্ভ করার জন্য তাড়ানোর আগে, আমাকে পরিষ্কার করে দিন: আমি এটি পেয়েছি। আসলে, এই পার্থক্যটি আমার কাছে একেবারেই স্বাভাবিক, যেহেতু আমার সি ++ তে অভিজ্ঞতা আছে যেখানে আমাদের নতুন প্লেসমেন্ট রয়েছে , যা একইভাবে অবজেক্টের বরাদ্দকে আরম্ভকরণ থেকে পৃথক করে।

পাইথন সি এপিআই টিউটোরিয়াল এর মতো এটিকে ব্যাখ্যা করেছেন:

নতুন সদস্য এই ধরণের অবজেক্ট তৈরি করার জন্য (দায়বদ্ধ হওয়ার বিপরীতে) দায়বদ্ধ। এটি পাইথনের __new__()পদ্ধতি হিসাবে উদ্ভাসিত । ... একটি নতুন পদ্ধতি বাস্তবায়নের একটি কারণ হ'ল উদাহরণ ভেরিয়েবলের প্রাথমিক মানগুলি নিশ্চিত করা

সুতরাং, হাঁ - আমি পেতে কি __new__না, কিন্তু এই সত্ত্বেও, আমি এখনো বুঝতে পারছি না কেন এটা পাইথন দরকারী নয়। প্রদত্ত উদাহরণটি বলে যে __new__আপনি যদি "উদাহরণের ভেরিয়েবলের প্রাথমিক মানগুলি নিশ্চিত করতে চান" তা কার্যকর হতে পারে says ঠিক আছে, ঠিক তাই __init__করবে না?

সিপিআই টিউটোরিয়ালে, একটি উদাহরণ দেখানো হয় যেখানে একটি নতুন প্রকার ("নড্ডি" নামে পরিচিত) তৈরি হয়, এবং প্রকারটির __new__কার্যকারিতা সংজ্ঞায়িত হয়। নোডি টাইপের মধ্যে একটি স্ট্রিং সদস্য রয়েছে যার নাম রয়েছে firstএবং এই স্ট্রিং সদস্যকে খালি স্ট্রিংয়ের মতো করে আরম্ভ করা হয়:

static PyObject * Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    .....

    self->first = PyString_FromString("");
    if (self->first == NULL)
    {
       Py_DECREF(self);
       return NULL;
    }

    .....
}

নোট করুন যে __new__এখানে বর্ণিত পদ্ধতি ব্যতীত আমাদের ব্যবহার করতে হবে PyType_GenericNew, যা কেবল সমস্ত পরিবর্তনশীল সদস্যকে NUL তে সূচনা করে to সুতরাং __new__পদ্ধতির একমাত্র সুবিধা হ'ল উদাহরণটি ভেরিয়েবলটি NUL এর বিপরীতে খালি স্ট্রিং হিসাবে শুরু হবে। তবে কেন এটি সর্বদা কার্যকর, যেহেতু আমরা যদি আমাদের দৃষ্টান্তের ভেরিয়েবলগুলি কিছু ডিফল্ট মান দিয়ে শুরু করি তা নিশ্চিত করার বিষয়ে যত্নশীল হন, তবে আমরা কেবল __init__পদ্ধতিতে এটি করতে পারতাম ?

উত্তর:


137

পার্থক্যটি মূলত পরিবর্তিত বনাম অপরিবর্তনীয় প্রকারের সাথে উত্থাপিত হয়।

__new__একটি গ্রহণ ধরনের প্রথম আর্গুমেন্ট হিসাবে, এবং (সাধারণত) যে ধরনের একটি নতুন দৃষ্টান্ত ফেরৎ। সুতরাং এটি পরিবর্তনীয় এবং অপরিবর্তনীয় উভয় প্রকারের সাথে ব্যবহারের জন্য উপযুক্ত।

__init__প্রথম আর্গুমেন্ট হিসাবে একটি উদাহরণ গ্রহণ করে এবং সেই উদাহরণের বৈশিষ্ট্যগুলিকে সংশোধন করে। এটি অপরিবর্তনীয় ধরণের জন্য অনুপযুক্ত, কারণ এটি তাদের কল করে সৃষ্টির পরে সংশোধন করার অনুমতি দেয় obj.__init__(*args)

আচরণকে তুলনা tupleএবং list:

>>> x = (1, 2)
>>> x
(1, 2)
>>> x.__init__([3, 4])
>>> x # tuple.__init__ does nothing
(1, 2)
>>> y = [1, 2]
>>> y
[1, 2]
>>> y.__init__([3, 4])
>>> y # list.__init__ reinitialises the object
[3, 4]

কেন তারা পৃথক (সাধারণ historicalতিহাসিক কারণগুলি বাদ দিয়ে): __new__পদ্ধতিগুলি সঠিক হওয়ার জন্য একগুচ্ছ বয়লারপ্লেটের প্রয়োজন (প্রাথমিক বস্তুটি তৈরি করা, এবং তারপরে অবজেক্টটি ফিরে পাওয়ার জন্য মনে রাখা)। __init__বিপরীতে, পদ্ধতিগুলি মৃত সহজ, যেহেতু আপনি যে বৈশিষ্ট্যগুলি সেট করতে হবে তা আপনি কেবল সেট করে রেখেছেন।

ছাড়াও __init__পদ্ধতি লিখতে সহজ হচ্ছে, এবং চপল বনাম অপরিবর্তনীয় পার্থক্য উপরে উল্লেখ করেছি, বিচ্ছেদ এছাড়াও কলিং পিতা বা মাতা বর্গ করতে শোষণ __init__উপশ্রেণী মধ্যে যে কোন একেবারে প্রয়োজনীয় উদাহরণস্বরূপ invariants স্থাপন করে ঐচ্ছিক __new__। এটি সাধারণত একটি সন্দেহজনক অনুশীলন - এটি সাধারণত পিতাম শ্রেণীর __init__পদ্ধতিগুলি প্রয়োজনীয় হিসাবে কল করা আরও পরিষ্কার ।


1
আপনি যে কোডটি "বয়লারপ্লেট" হিসাবে উল্লেখ করেছেন __new__তা বোয়লারপ্লেট নয়, কারণ বয়লারপ্লেট কখনও পরিবর্তন হয় না। কখনও কখনও আপনাকে সেই নির্দিষ্ট কোডটি আলাদা কিছু দিয়ে প্রতিস্থাপন করতে হবে।
মাইলস রাউথ

13
তৈরি করা, বা অন্যথায় অর্জন করা, উদাহরণ (সাধারণত একটি superকল সহ) এবং উদাহরণটি ফিরিয়ে দেওয়া কোনও __new__বাস্তবায়নের প্রয়োজনীয় অংশ এবং আমি যে "বয়লারপ্লেট" উল্লেখ করছি। বিপরীতে, এর passজন্য একটি বৈধ বাস্তবায়ন __init__- যা কোনও প্রয়োজনের আচরণ নেই।
ncoghlan

37

এর জন্য সম্ভবত অন্যান্য ব্যবহার রয়েছে __new__তবে এর মধ্যে একটি সত্যই স্পষ্ট রয়েছে: আপনি ব্যবহার ছাড়াই অপরিবর্তনীয় ধরণের সাবক্লাস করতে পারবেন না __new__। সুতরাং উদাহরণস্বরূপ, বলুন যে আপনি টুপলের একটি সাবক্লাস তৈরি করতে চেয়েছিলেন যা কেবল 0 এবং এর মধ্যে কেবল অবিচ্ছেদ্য মান থাকতে পারে size

class ModularTuple(tuple):
    def __new__(cls, tup, size=100):
        tup = (int(x) % size for x in tup)
        return super(ModularTuple, cls).__new__(cls, tup)

আপনি কেবল এটি দিয়ে এটি করতে পারবেন না __init__- আপনি যদি সংশোধন করার চেষ্টা selfকরেন __init__, দোভাষী আপনি অভিযোগ করতে পারেন যে আপনি কোনও পরিবর্তনযোগ্য অবজেক্টকে সংশোধন করার চেষ্টা করছেন।


1
আমি বুঝতে পারি না কেন আমাদের সুপার ব্যবহার করা উচিত? আমি বলতে চাই নতুন কেন সুপারক্লাসের একটি উদাহরণ ফেরত দেওয়া উচিত ? তদ্ব্যতীত, আপনার যেমনটি বলা হয়েছে, কেন আমরা ক্লাসগুলি নতুন করে স্পষ্টভাবে পাস করব ? সুপার (ModularTuple, cls) একটি আবদ্ধ পদ্ধতি ফিরে না?
অ্যালকোট

3
@ অ্যালকোট, আমি মনে করি আপনি এর আচরণকে ভুল বুঝছেন __new__। আমরা clsস্পষ্টভাবে পাস করি __new__কারণ আপনি এখানে পড়তে পারেন এর __new__ সর্বদা প্রথম যুক্তি হিসাবে একটি ধরণের প্রয়োজন। এরপরে এটি সেই ধরণের উদাহরণ দেয়। সুতরাং আমরা সুপারক্লাসের কোনও উদাহরণ ফিরিয়ে দিচ্ছি না - আমরা একটি উদাহরণ ফিরিয়ে দিচ্ছি cls। এই ক্ষেত্রে, এটা ঠিক একই হিসাবে যদি আমরা বলেছিলেন tuple.__new__(ModularTuple, tup)
প্রেরক

35

__new__()যে শ্রেণিতে আবদ্ধ তা ব্যতীত অন্য ধরণের জিনিসগুলি ফিরিয়ে দিতে পারে। __init__()কেবলমাত্র ক্লাসের একটি বিদ্যমান উদাহরণ সূচনা করে।

>>> class C(object):
...   def __new__(cls):
...     return 5
...
>>> c = C()
>>> print type(c)
<type 'int'>
>>> print c
5

এটি এখন পর্যন্ত সবচেয়ে বিশুদ্ধ ব্যাখ্যা is
তারিক

বেশ সত্য নয়। আমার কাছে এমন __init__পদ্ধতি রয়েছে যার মতো কোড রয়েছে self.__class__ = type(...)। যার ফলে আপনি যে ভেবেছিলেন আপনি যেটিকে তৈরি করছেন তার চেয়ে এই বিষয়টি অন্য শ্রেণীর হয়ে যায়। intআপনি যেমন করেছিলেন তেমন আমি আসলে এটিকে রূপান্তর করতে পারি না ... আমি হ্যাপের ধরণ বা অন্য কিছু সম্পর্কে একটি ত্রুটি পেয়েছি ... তবে এটি গতিশীলভাবে তৈরি শ্রেণীর কাজগুলিতে নির্ধারণের আমার উদাহরণ।
আর্টঅফ ওয়ারফেয়ার

আমিও কখন __init__()ডাকা হবে তা নিয়ে বিভ্রান্ত হয়ে পড়েছি । উদাহরণস্বরূপ, লোনটউইনের উত্তরে , কোন ধরণের প্রত্যাবর্তনের উপর নির্ভর করে হয় Triangle.__init__()বা Square.__init__()স্বয়ংক্রিয়ভাবে কল হয়ে যায় __new__()। আপনার উত্তরে আপনি যা বলছেন (এবং আমি এটি অন্য কোথাও পড়েছি) থেকে মনে হয় না যেহেতু তাদের কোনওটিরই হওয়া উচিত, যেহেতু এটির কোনও উদাহরণই ফিরে আসে Shape.__new__() নাcls (বা এটির একটি সাবক্লাসের একটিও নয়)।
মার্টিনো

1
@ মার্টিনো: __init__()পৃথক বস্তুগুলি তাত্ক্ষণিকভাবে চালিত হলে (যেমন তাদের __new__() পদ্ধতিটি ফিরে আসে) ফিরে আসে না, যখন লোনটউইনের উত্তরের পদ্ধতিগুলি বলা হয় Shape.__new__()
Ignacio Vazquez-Abram

আহ, ঠিক আছে, Shape.__init__()(যদি এটি থাকে) ডাকা হত না। এখন এটি আরও বেশি :¬)
অর্থবোধ করছে

13

একটি সম্পূর্ণ উত্তর নয় তবে সম্ভবত এমন কিছু যা পার্থক্যটির চিত্রিত করে।

__new__যখন কোনও বস্তু তৈরি করতে হয় তখন সর্বদা ডাকা হবে। কিছু পরিস্থিতি রয়েছে যেখানে কল __init__হবে না। একটি উদাহরণ হ'ল আপনি যখন কোনও আচার ফাইল থেকে বস্তুগুলি আনচিকল করেন, তখন তারা বরাদ্দ পাবেন ( __new__) তবে আরম্ভ করা হবে না __init__)।


আমি যদি মেমরির বরাদ্দ রাখতে এবং ডেটা শুরু করার জন্য চাই তবে আমি কি নতুন থেকে দীক্ষা কল করব? কেন যদি নতুন কোন অস্তিত্ব নেই যখন উদাহরণস্বরূপ তৈরি Init নামক পায়?
redpix_

2
কাজ __new__পদ্ধতি হয় তৈরি (এই মেমরি অ্যালোকেশন বোঝা) ক্লাসের একটা নিদর্শন এবং এটি ফিরে। আরম্ভটি একটি পৃথক পদক্ষেপ এবং এটি সাধারণত ব্যবহারকারীর কাছে দৃশ্যমান। আপনার যদি কোনও নির্দিষ্ট সমস্যার মুখোমুখি হয় তবে দয়া করে একটি পৃথক প্রশ্ন জিজ্ঞাসা করুন।
নওফাল ইব্রাহিম

3

বনাম নির্ধারণের অভিপ্রায় (আচরণের বিপরীতে) সম্পর্কে কেবল একটি শব্দ যুক্ত করতে চান ।__new____init__

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

সুতরাং __ নতুন__ পদ্ধতির একমাত্র সুবিধা হ'ল এনুলের বিপরীতে উদাহরণের পরিবর্তনশীলটি খালি স্ট্রিং হিসাবে শুরু হবে। তবে কেন এটি সর্বদা দরকারী, যেহেতু আমরা যদি নিশ্চিত হয়ে দেখি যে আমাদের দৃষ্টান্তের ভেরিয়েবলগুলি কোনও ডিফল্ট মান থেকে আরম্ভ করা হয় তবে আমরা __init__ পদ্ধতিতে কেবল এটি করতে পারতাম?

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

আমি ধারণাটি অবধি কেবল তার অর্থের পরিবর্তে প্রয়োগের বিষয়ে চিন্তা না করা পর্যন্ত আমি এ সম্পর্কে বিভ্রান্ত হয়ে পড়েছিলাম। এখানে একটি উদাহরণ যা আশাবাদী পার্থক্যটি পরিষ্কার করবে:

a = Shape(sides=3, base=2, height=12)
b = Shape(sides=4, length=2)
print(a.area())
print(b.area())

# I want `a` and `b` to be an instances of either of 'Square' or 'Triangle'
# depending on number of sides and also the `.area()` method to do the right
# thing. How do I do that without creating a Shape class with all the
# methods having a bunch of `if`s ? Here is one possibility

class Shape:
    def __new__(cls, sides, *args, **kwargs):
        if sides == 3:
            return Triangle(*args, **kwargs)
        else:
            return Square(*args, **kwargs)

class Triangle:
    def __init__(self, base, height):
        self.base = base
        self.height = height

    def area(self):
        return (self.base * self.height) / 2

class Square:
    def __init__(self, length):
        self.length = length

    def area(self):
        return self.length*self.length

দ্রষ্টব্য এটি কেবল একটি বিক্ষোভমূলক উদাহরণ। উপরের মতো ক্লাস ফ্যাক্টরি পদ্ধতির অবলম্বন না করে সমাধান পাওয়ার একাধিক উপায় রয়েছে এবং এমনকি যদি আমরা এই পদ্ধতিতে সমাধানটি কার্যকর করতে বেছে না নিই তবে ব্রিভটির পক্ষে কিছুটা সতর্কতা অবলম্বন করা যায় (উদাহরণস্বরূপ, মেটাক্লাসকে স্পষ্টভাবে ঘোষণা করা) )

যদি আপনি একটি নিয়মিত ক্লাস তৈরি করছেন (ওরফে একটি অ-মেটাক্লাস), তবে এনকোঘ্লানের উত্তর উত্তরে (যেটি মূলত সংজ্ঞায়নের ধারণার আরও নির্দিষ্ট উদাহরণ) হিসাবে __new__পরিবর্তনীয় বনাম অপরিবর্তনীয় দৃশ্যের মতো বিশেষ ঘটনা না ঘটে তা আসলেই বোধগম্য হয় না unless ক্লাস / প্রকারের প্রাথমিক মান / বৈশিষ্ট্যগুলি এর মাধ্যমে তৈরি করার মাধ্যমে তৈরি __new__করা হবে __init__) এর মাধ্যমে ) initial

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