__Init __ () সর্বদা __ নতুন __ () এর পরে কেন ডাকা হয়?


568

আমি কেবল আমার ক্লাসগুলির মধ্যে একটিকে প্রবাহিত করার চেষ্টা করছি এবং ফ্লাইওয়েট ডিজাইনের ধরণ হিসাবে একই স্টাইলে কিছু কার্যকারিতা প্রবর্তন করেছি ।

যাইহোক, কেন __init__সবসময় এর পরে ডাকা হয় সে সম্পর্কে আমি কিছুটা বিভ্রান্ত __new__। আমি এটা আশা করছিলাম না। কেউ কি আমাকে বলতে পারবেন যে এটি কেন ঘটছে এবং আমি কীভাবে এই কার্যকারিতাটি বাস্তবায়ন করতে পারি? (বাস্তবায়নটিকে __new__পুরোপুরি হ্যাকি মনে করা ছাড়াও ))

এখানে একটি উদাহরণ:

class A(object):
    _dict = dict()

    def __new__(cls):
        if 'key' in A._dict:
            print "EXISTS"
            return A._dict['key']
        else:
            print "NEW"
            return super(A, cls).__new__(cls)

    def __init__(self):
        print "INIT"
        A._dict['key'] = self
        print ""

a1 = A()
a2 = A()
a3 = A()

আউটপুট:

NEW
INIT

EXISTS
INIT

EXISTS
INIT

কেন?


পাশাপাশি নকশার ধরণটিও বোঝার চেষ্টা করা হয়েছিল, এবং প্রথমবারের মতো শুনেছিলাম: ফ্লাইওয়েট ডিজাইনের ধরণ .. এবং খুব জনপ্রিয় লিঙ্কটি প্রায় সমস্ত জনপ্রিয় ল্যাঙ্গুয়েজে উদাহরণ রয়েছে।
এমা ইয়ং

উত্তর:


598

__new__যখন আপনাকে একটি নতুন উদাহরণ তৈরি করা নিয়ন্ত্রণ করতে হবে তখন ব্যবহার করুন ।

__init__আপনি যখন একটি নতুন উদাহরণের সূচনা নিয়ন্ত্রণ করতে হবে তখন ব্যবহার করুন ।

__new__উদাহরণস্বরূপ সৃষ্টির প্রথম পদক্ষেপ। এটিকে প্রথমে বলা হয় এবং এটি আপনার শ্রেণীর কোনও নতুন উদাহরণ ফিরে পাওয়ার জন্য দায়ী।

বিপরীতে, __init__কিছু ফেরত দেয় না; এটি তৈরির পরে উদাহরণটি শুরু করার জন্য এটি কেবল দায়বদ্ধ।

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

এপ্রিল ২০০ post সাল থেকে: বনাম কখন ব্যবহার করবেন ? __new____init__mail.python.org এ .org

আপনার বিবেচনা করা উচিত যে আপনি যা করতে চেষ্টা করছেন তা সাধারণত একটি কারখানার সাথে করা হয় এবং এটি করার সর্বোত্তম উপায়। ব্যবহার __new__করা ভাল পরিষ্কার সমাধান নয় তাই দয়া করে কারখানার ব্যবহার বিবেচনা করুন। এখানে আপনার একটি ভাল কারখানার উদাহরণ রয়েছে


1
__new__কারখানা শ্রেণীর অভ্যন্তরে ব্যবহার শেষ হয়েছে , যা বেশ পরিষ্কার হয়ে গেছে, তাই আপনার ইনপুটটির জন্য ধন্যবাদ।
ড্যান

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

170

__new__স্ট্যাটিক ক্লাস পদ্ধতি, অন্যদিকে __init__উদাহরণ পদ্ধতি। __new__প্রথমে উদাহরণটি তৈরি __init__করতে হবে , তাই এটি আরম্ভ করতে পারে। নোট যা প্যারামিটার হিসাবে __init__গ্রহণ করে self। যতক্ষণ না আপনি উদাহরণ তৈরি করবেন না self

এখন, আমি একত্রিত হয়েছি যে আপনি পাইথনে সিঙ্গলটন প্যাটার্নটি প্রয়োগ করার চেষ্টা করছেন । এটি করার কয়েকটি উপায় রয়েছে।

এছাড়াও, পাইথন ২.6 হিসাবে, আপনি শ্রেণি সজ্জা ব্যবহার করতে পারেন ।

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
  ...

8
@ টাইলার লং, "@ সিংসেলটন" কীভাবে কাজ করে তা আমি পুরোপুরি বুঝতে পারি না? কারণ সাজসজ্জার একটি ফাংশন দেয় তবে মাই ক্লাস একটি শ্রেণি।
অ্যালকোট

11
অভিধান কেন? যেহেতু ক্লাস সবসময় একই থাকে এবং আপনি প্রতিটি সিঙ্গলটনের জন্য উদাহরণস্বরূপ একটি নতুন অভিধান পান তবে আপনি এটিতে কেবল একটি আইটেম দিয়ে একটি অভিধান তৈরি করছেন।
উইনস্টন ইওয়ার্ট

7
@ অ্যালকোট: কোনও মতামত প্রয়োজন নেই - ডক্স আপনার সাথে একমত।
ইথান ফুরম্যান

2
@Alcott। হ্যাঁ সাজসজ্জা একটি ফাংশন ফেরত। তবে ক্লাস এবং ফাংশন উভয়ই কলযোগ্য। আমি মনে করি দৃষ্টান্তগুলি = {a একটি বৈশ্বিক পরিবর্তনশীল হওয়া উচিত।
টাইলার লং

4
@ টিলারলং অ্যালকোটের একটি ভাল পয়েন্ট রয়েছে। নামটির MyClassফলে কোনও ফাংশনে আবদ্ধ হয়ে যায় যা মূল শ্রেণীর উদাহরণগুলি দেয়। তবে এখন আর মূল ক্লাসটি আদৌ উল্লেখ করার কোনও উপায় নেই, এবং MyClassএকটি ফাংশন বিরতি isinstance/ issubclassচেক হওয়া, শ্রেণীর বৈশিষ্ট্য / পদ্ধতিগুলিতে সরাসরি অ্যাক্সেস MyClass.something, superকলগুলিতে নামকরণ ইত্যাদি ইত্যাদি etc. যা সমস্যা বা না তার উপর নির্ভর করে ক্লাস আপনি এটি প্রয়োগ (এবং প্রোগ্রাম বাকি)।
বেন

148

বেশিরভাগ সুপরিচিত ওও ভাষাগুলিতে, মত একটি এক্সপ্রেশন SomeClass(arg1, arg2)একটি নতুন উদাহরণ বরাদ্দ করবে, উদাহরণের বৈশিষ্ট্যগুলি আরম্ভ করবে এবং তারপরে এটি ফিরিয়ে দেবে।

সবচেয়ে সুপরিচিত OO যেমন পণ্য ভাষায়, "উদাহরণস্বরূপ গুণাবলী ইনিশিয়ালাইজ" অংশ সংজ্ঞা দ্বারা প্রতিটি বর্গ জন্য কাস্টমাইজ করা যায় কন্সট্রাকটর , যা মূলত শুধু একটি কোড ব্লক যে (নতুন উদাহরণ করে পরিচালিত কন্সট্রাকটর এক্সপ্রেশন প্রদত্ত যুক্তিগুলির ব্যবহার করছে ) প্রারম্ভিক শর্তগুলি যা পছন্দসই সেট আপ করতে। পাইথনে এটি ক্লাসের সাথে __init__মেলে।

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

তবে এটি এখনও কাজের অর্ধেক অংশ, এবং পাইথন সিস্টেমের পক্ষে এটি জানার উপায় নেই যে কখনও কখনও আপনি কাজটির অর্ধেক চালাতে চান ( __init__) পরে এবং কখনও কখনও আপনি করেন না। যদি আপনি সেই আচরণটি চান, আপনাকে তাই স্পষ্ট করে বলতে হবে।

প্রায়শই, আপনি কেবল চুল্লি করতে পারেন যাতে আপনার কেবল প্রয়োজন হয় __new__, বা আপনার প্রয়োজন হয় না __new__, বা __init__এটি ইতিমধ্যে-আরম্ভকৃত কোনও বস্তুর উপর অন্যরকম আচরণ করে। তবে আপনি যদি সত্যিই চান, পাইথন আপনাকে "কাজ" নতুন করে সংজ্ঞায়িত করার অনুমতি দেয়, যাতে এটি SomeClass(arg1, arg2)প্রয়োজনীয়ভাবে __new__অনুসরণ করে কল না করে __init__। এটি করার জন্য, আপনাকে একটি মেটাক্লাস তৈরি করতে হবে এবং এর __call__পদ্ধতিটি নির্ধারণ করতে হবে ।

একটি মেটাক্লাস কেবল একটি শ্রেণীর শ্রেণি। এবং ক্লাসের একটি __call__পদ্ধতি যখন আপনি শ্রেণীর উদাহরণগুলি কল করেন তখন কী ঘটে তা নিয়ন্ত্রণ করে। সুতরাং একটি মেটাগ্লাস ' __call__পদ্ধতিটি আপনি যখন ক্লাস কল করেন তখন কী হয় তা নিয়ন্ত্রণ করে; অর্থাত্‍ এটি আপনাকে প্রথম থেকে শেষ পর্যন্ত ইনস্ট্যান্স-তৈরির প্রক্রিয়াটি পুনরায় সংজ্ঞায়িত করতে সহায়তা করে । এটি এমন একটি স্তর যেখানে আপনি সর্বাধিক মার্জিতভাবে সিঙ্গেলটন প্যাটার্নের মতো সম্পূর্ণ অ-মানক উদাহরণ নির্মাণ প্রক্রিয়াটি প্রয়োগ করতে পারেন। বস্তুত, কোডের কম 10 লাইনের আপনি যদি একটি বাস্তবায়ন করতে পারে Singletonক্লাসের অধীনে একটি ক্লাস যে তারপর এমনকি আপনি সঙ্গে futz করার প্রয়োজন হয় না __new__ এ সব , আর চালু করতে পারেন কোনো একটি Singleton মধ্যে কেবল যোগ করে অন্যথায়-স্বাভাবিক বর্গ __metaclass__ = Singleton!

class Singleton(type):
    def __init__(self, *args, **kwargs):
        super(Singleton, self).__init__(*args, **kwargs)
        self.__instance = None
    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            self.__instance = super(Singleton, self).__call__(*args, **kwargs)
        return self.__instance

তবে এটি সম্ভবত এই পরিস্থিতিটির সত্যতা চেয়ে বেশি গভীর যাদু!


25

ডকুমেন্টেশন উদ্ধৃতি :

সাধারণ বাস্তবায়নগুলি সুপারক্লাসের __ নতুন __ () পদ্ধতিটিকে "সুপার (কারেন্টক্লাস, ক্লস) ব্যবহার করে .__ নতুন __ (ক্লস [, ...])" উপযুক্ত যুক্তি সহকারে এবং তারপরে প্রয়োজনীয়ভাবে সদ্য নির্মিত ইভেন্টটি সংশোধন করে শ্রেণীর একটি নতুন উদাহরণ তৈরি করে এটি ফেরত দেওয়ার আগে

...

যদি __ নতুন __ () ক্লসের কোনও উদাহরণ না ফেরায়, তবে নতুন উদাহরণের __init __ () পদ্ধতিটি চাওয়া হবে না।

__ নতুন __ () মূলত অপরিবর্তনীয় ধরণের (যেমন int, str, বা tuple) সাবক্লাসগুলিকে উদাহরণস্বরূপ সৃষ্টিটি কাস্টমাইজ করার অনুমতি দেয়।


18
If __new__() does not return an instance of cls, then the new instance's __init__() method will not be invoked.এটি একটি গুরুত্বপূর্ণ বিষয়। আপনি যদি অন্য কোনও উদাহরণ ফিরে পান তবে আসলটিকে __init__কখনই ডাকা হয় না।
জেফরি জোস

@ টগ্রে আমি বুঝতে পারি আপনার উত্তরটি ডক্স থেকে এসেছে, তবে আপনি যদি ক্লসের উদাহরণ না ফেরার কোনও ব্যবহারের ক্ষেত্রে জানেন তবে আমি আগ্রহী। দেখে মনে হচ্ছে যে যখন ফিরে আসা অবজেক্টটি __new__তার শ্রেণীর জন্য পরীক্ষা করা হবে তখন পদ্ধতিটি ব্যর্থ চেকটি নীরবে পাস করার পরিবর্তে একটি ত্রুটি ছুঁড়ে মারবে, কারণ আপনি বুঝতে পারছেন না কেন আপনি কখনও শ্রেণীর অবজেক্ট ছাড়া আর কিছু ফিরিয়ে দিতে চান কেন? ।
soporific312

@ soporific312 আমি কোনও ব্যবহারের ক্ষেত্রে দেখিনি। এই উত্তরটি ডিজাইনের কিছু যুক্তি নিয়ে আলোচনা করেছে, যদিও তারা "কোডটি" ব্যবহার করে এমন কোনও কোডও দেখেনি।
tgray

12

আমি বুঝতে পারি যে এই প্রশ্নটি বেশ পুরানো তবে আমার একটি একই সমস্যা ছিল। নিম্নলিখিতগুলি যা চেয়েছিল তা করেছে:

class Agent(object):
    _agents = dict()

    def __new__(cls, *p):
        number = p[0]
        if not number in cls._agents:
            cls._agents[number] = object.__new__(cls)
        return cls._agents[number]

    def __init__(self, number):
        self.number = number

    def __eq__(self, rhs):
        return self.number == rhs.number

Agent("a") is Agent("a") == True

আমি একটি সম্পদ হিসেবে এই পৃষ্ঠার ব্যবহৃত http://infohost.nmt.edu/tcc/help/pubs/python/web/new-new-method.html


7
দ্রষ্টব্য: __ নতুন__ সর্বদা একটি উপযুক্ত বস্তু ফেরত দেয়, তাই __init__ সর্বদা বলা হয় - এমনকি উদাহরণটি ইতিমধ্যে উপস্থিত থাকলেও।
16-18 এ অবিশ্বাস্য

10

আমি মনে করি এই প্রশ্নের সহজ উত্তর হ'ল, যদি __new__শ্রেণীর মতো একই ধরণের কোনও মান ফিরিয়ে দেয় তবে __init__ফাংশনটি কার্যকর করে, অন্যথায় এটি হবে না। A._dict('key')এক্ষেত্রে আপনার কোড রিটার্ন দেয় যা একই ক্লাস cls, তাই __init__কার্যকর করা হবে।


10

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

এখানে সিঙ্গেলটন প্যাটার্নের জেনেরিক অ্যাপ্রোচ যা উপরে বর্ণের উত্তর প্রসারিত করে এবং এটি ঠিক করে দিয়েছে:

def SingletonClass(cls):
    class Single(cls):
        __doc__ = cls.__doc__
        _initialized = False
        _instance = None

        def __new__(cls, *args, **kwargs):
            if not cls._instance:
                cls._instance = super(Single, cls).__new__(cls, *args, **kwargs)
            return cls._instance

        def __init__(self, *args, **kwargs):
            if self._initialized:
                return
            super(Single, self).__init__(*args, **kwargs)
            self.__class__._initialized = True  # Its crucial to set this variable on the class!
    return Single

সম্পূর্ণ গল্প এখানে

আর একটি পদ্ধতি, যা বাস্তবে জড়িত __new__তা হ'ল শ্রেণীবদ্ধগুলি ব্যবহার করা:

class Singleton(object):
    __initialized = False

    def __new__(cls, *args, **kwargs):
        if not cls.__initialized:
            cls.__init__(*args, **kwargs)
            cls.__initialized = True
        return cls


class MyClass(Singleton):
    @classmethod
    def __init__(cls, x, y):
        print "init is here"

    @classmethod
    def do(cls):
        print "doing stuff"

দয়া করে মনোযোগ দিন, এই পদ্ধতির সাথে আপনার নিজের সমস্ত পদ্ধতি সাজাতে হবে @classmethod, কারণ আপনি কখনই এর বাস্তব উদাহরণ ব্যবহার করবেন না MyClass


6

এই দস্তাবেজের উল্লেখ :

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

নতুন পদ্ধতি তার প্রথম আর্গুমেন্ট হিসাবে শ্রেণির সাথে কল করা হয়; তার দায়িত্ব হল এই শ্রেণীর একটি নতুন উদাহরণ ফিরে আসা।

এই তুলনা init : Init তার প্রথম আর্গুমেন্ট হিসাবে একটি দৃষ্টান্ত দিয়ে বলা হয়, এবং এটি কিছু ফেরত না; এর দায়িত্ব হ'ল দৃষ্টান্তটি আরম্ভ করা।

এমন পরিস্থিতি রয়েছে যেখানে আরম্ভ না করেই একটি নতুন উদাহরণ তৈরি করা হয় (উদাহরণস্বরূপ যখন কোনও আচার থেকে লোড করা হয়)। কলিং ছাড়া একটি নতুন উদাহরণ সৃষ্টি করতে কোনো উপায় নেই নতুন (যদিও কিছু কিছু ক্ষেত্রে আপনি কলিং একটি বেস ক্লাস পার পেয়ে যাবে নতুন )।

আপনি কী অর্জন করতে চান তা সম্পর্কে, সেখানে সিঙ্গেলন প্যাটার্ন সম্পর্কে একই ডক তথ্যতে

class Singleton(object):
        def __new__(cls, *args, **kwds):
            it = cls.__dict__.get("__it__")
            if it is not None:
                return it
            cls.__it__ = it = object.__new__(cls)
            it.init(*args, **kwds)
            return it
        def init(self, *args, **kwds):
            pass

আপনি ডেকোরেটর ব্যবহার করে, PEP 318 থেকে এই বাস্তবায়নটি ব্যবহার করতে পারেন

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
...

1
শব্দগুলি initথেকে __new__জঘন্য আকারে কল করা সত্যিই হ্যাকি। এটি মেটাক্লাসগুলির জন্য।
ম্যাড পদার্থবিদ

6
class M(type):
    _dict = {}

    def __call__(cls, key):
        if key in cls._dict:
            print 'EXISTS'
            return cls._dict[key]
        else:
            print 'NEW'
            instance = super(M, cls).__call__(key)
            cls._dict[key] = instance
            return instance

class A(object):
    __metaclass__ = M

    def __init__(self, key):
        print 'INIT'
        self.key = key
        print

a1 = A('aaa')
a2 = A('bbb')
a3 = A('aaa')

আউটপুট:

NEW
INIT

NEW
INIT

EXISTS

বিশেষ দ্রষ্টব্য হিসাবে একটি পার্শ্ব প্রতিক্রিয়া M._dictসম্পত্তি স্বয়ংক্রিয়ভাবে থেকে অ্যাক্সেসযোগ্য হয়ে Aযেমন A._dictতাই এটি প্রসঙ্গক্রমে ওভাররাইট না যত্ন নিতে।


আপনি __init__সেট করে এমন একটি পদ্ধতি অনুপস্থিত cls._dict = {}। আপনি সম্ভবত এই মেটাটাইপের সমস্ত শ্রেণীর দ্বারা ভাগ করা একটি অভিধান চান না (তবে ধারণার জন্য +1)।
ম্যাড পদার্থবিদ

5

__ নতুন__ একটি ক্লাসের একটি নতুন, ফাঁকা দৃষ্টান্ত ফেরত দেওয়া উচিত। এরপরে __init__ কে সেই দৃষ্টান্তটি আরম্ভ করার জন্য বলা হয়। আপনি __ নতুন__ এর "নতুন" ক্ষেত্রে __init__ কে কল করছেন না, সুতরাং এটি আপনার জন্য ডাকা হচ্ছে। কোডটি যেটি কল করছে __new__তা __init__ কে নির্দিষ্ট উদাহরণে আহ্বান জানানো হয়েছে কি না তা ট্র্যাক করে না কারণ আপনি এখানে খুব অস্বাভাবিক কিছু করছেন।

আপনি __init__ ফাংশনটিতে অবজেক্টের কোনও বৈশিষ্ট্য যুক্ত করতে পারেন এটি সূচনা করার জন্য এটি শুরু করা হয়েছে। __Init__ এ প্রথম জিনিস হিসাবে সেই গুণটির অস্তিত্বের জন্য যাচাই করুন এবং এটি থাকলে আর এগিয়ে যান না।


5

@ অ্যান্টনিহ্যাচকিন্স উত্তরের একটি আপডেট, আপনি সম্ভবত মেটাটাইপের প্রতিটি শ্রেণীর জন্য উদাহরণগুলির পৃথক ডিকশনারি চান, অর্থাত্ __init__আপনার ক্লাসের অবজেক্টটি সমস্ত বিভাগে বৈশ্বিক করার পরিবর্তে সেই অভিধানটি দিয়ে আপনার মেটাচ্লাসে থাকা উচিত ।

class MetaQuasiSingleton(type):
    def __init__(cls, name, bases, attibutes):
        cls._dict = {}

    def __call__(cls, key):
        if key in cls._dict:
            print('EXISTS')
            instance = cls._dict[key]
        else:
            print('NEW')
            instance = super().__call__(key)
            cls._dict[key] = instance
        return instance

class A(metaclass=MetaQuasiSingleton):
    def __init__(self, key):
        print 'INIT'
        self.key = key
        print()

আমি একটি __init__পদ্ধতির সাহায্যে মূল কোডটি এগিয়ে গিয়ে আপডেট করেছি এবং বাক্য গঠনটি পাইথন 3 নোটেশনে পরিবর্তন করেছি (নো-আরগ কল এsuper এবং সিনথ্যাক্সটি বৈশিষ্ট্য হিসাবে পরিবর্তে ক্লাস আর্গুমেন্টে এবং মেটাক্লাস) নয়।

যেভাবেই হোক, এখানে গুরুত্বপূর্ণ বিষয়টি হ'ল আপনার শ্রেণি প্রারম্ভকালীন ( __call__পদ্ধতি) হয় কার্যকর করা হবে না __new__বা __init__কীটি সন্ধান পেলে। এটি ব্যবহারের চেয়ে অনেক বেশি পরিচ্ছন্ন __new__, যদি আপনি ডিফল্ট __init__পদক্ষেপটি এড়াতে চান তবে আপনাকে অবজেক্টটি চিহ্নিত করতে হবে ।


4

এর মধ্যে আরও গভীর খনন!

সিপিথনে জেনেরিক ক্লাসের ধরণ typeএবং এর বেস ক্লাসটি Object(আপনি যদি কোনও মেটা ক্লাসের মতো স্পষ্টভাবে অন্য বেস ক্লাসটি সংজ্ঞায়িত না করেন)। নিম্ন স্তরের কলগুলির ক্রমটি এখানে পাওয়া যাবে । প্রথম পদ্ধতিটি বলা হয় type_callযা পরে কল tp_newএবং তারপরেtp_init

এখানে আকর্ষণীয় অংশটি হ'ল '(বেস ক্লাস) নতুন পদ্ধতিটি tp_newকল করবে যা একটি ( ) যা বস্তুর জন্য স্মৃতি বরাদ্দ করে :)Objectobject_newtp_allocPyType_GenericAlloc

এই মুহুর্তে বস্তুটি স্মৃতিতে তৈরি হয় এবং তারপরে __init__পদ্ধতিটি কল হয়। যদি __init__আপনার ক্লাসে প্রয়োগ না করা হয় তবে object_initডাকা হবে এবং এটি কিছুই করে না :)

তারপরে type_callকেবল সেই বস্তুটি ফিরিয়ে দেয় যা আপনার ভেরিয়েবলের সাথে আবদ্ধ।


4

Traditional __init__তিহ্যবাহী ওও ভাষাগুলিতে একটি সাধারণ নির্মাতা হিসাবে দেখা উচিত । উদাহরণস্বরূপ, আপনি যদি জাভা বা সি ++ এর সাথে পরিচিত হন তবে কনস্ট্রাক্টরকে ইঙ্গিতযুক্তভাবে তার নিজস্ব পয়েন্টারে একটি পয়েন্টার দেওয়া হয়। জাভার ক্ষেত্রে এটি thisপরিবর্তনশীল। যদি কেউ জাভা জন্য উত্পন্ন বাইট কোড পরিদর্শন করেন, একজন দুটি কল লক্ষ্য করবেন। প্রথম কলটি একটি "নতুন" পদ্ধতির, এবং তারপরের কলটি হল ডিটি পদ্ধতিতে (যা ব্যবহারকারী সংজ্ঞায়িত নির্মাণকারীর কাছে আসল কল)। এই দুটি পদক্ষেপ প্রক্রিয়া শ্রেণীর কনস্ট্রাক্টর পদ্ধতিটি কল করার আগে প্রকৃত উদাহরণটি তৈরি করতে সক্ষম করে তোলে যা এই উদাহরণের অন্য একটি পদ্ধতি।

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


4

যাইহোক, কেন __init__সবসময় এর পরে ডাকা হয় সে সম্পর্কে আমি কিছুটা বিভ্রান্ত __new__

আমি মনে করি যে এখানে সি ++ উপমাটি কার্যকর হবে:

  1. __new__কেবলমাত্র বস্তুর জন্য মেমরি বরাদ্দ করে। কোনও অবজেক্টের উদাহরণের ভেরিয়েবলগুলি ধরে রাখতে মেমরি দরকার এবং পদক্ষেপটি এটিই __new__করবে।

  2. __init__ নির্দিষ্ট মানগুলিতে অবজেক্টের অভ্যন্তরীণ ভেরিয়েবলগুলি সূচনা করুন (ডিফল্ট হতে পারে)।


2

এর __init__পরে কল করা হয় __new__যাতে আপনি যখন এটি একটি সাবক্লাসে ওভাররাইড করেন, তখন আপনার যুক্ত কোডটি কল হয়ে যাবে।

আপনি যদি ইতিমধ্যে একটি ক্লাসের সাবক্লাস করার চেষ্টা করছেন __new__, তবে এ সম্পর্কে কিছু জানেন না এমন কেউ মানিয়ে নিতে __init__এবং কলটি সাবক্লাসে ফরোয়ার্ড করে শুরু করতে পারেন __init____init__পরে আহ্বান এই সম্মেলন__new__ সেই প্রত্যাশার মতো কাজ করতে সহায়তা করে।

__init__এখনও যে কোন প্যারামিটার সুপারক্লাস জন্য অনুমতি প্রয়োজন __new__প্রয়োজন ছিল, কিন্তু তা করতে ব্যর্থ সাধারণত একটি স্পষ্ট রানটাইম এরর তৈরি করবে। এবং __new__সম্ভবত সম্ভবত স্পষ্টভাবে *argsএবং '** কেডব্লু' এর জন্য অনুমতি দেওয়া উচিত , যাতে এটি পরিষ্কার হয়ে যায় যে এক্সটেনশনটি ঠিক আছে।

মূল পোস্টার বর্ণিত আচরণের কারণেই উত্তরাধিকারের একই স্তরে উভয় __new__এবং __init__একই শ্রেণিতে থাকা সাধারণত খারাপ ফর্ম ।


1

যাইহোক, কেন __init__সবসময় এর পরে ডাকা হয় সে সম্পর্কে আমি কিছুটা বিভ্রান্ত __new__

এটি কেবল যেভাবে করা হয় তা ছাড়া অন্য কোনও কারণ নয় of __new__ক্লাসটি আরম্ভ করার দায়িত্ব নেই, অন্য কিছু পদ্ধতি রয়েছে ( __call__সম্ভবত, আমি নিশ্চিতভাবে জানি না)।

আমি এটা আশা করছিলাম না। কেউ কি আমাকে বলতে পারবেন যে এটি কেন হচ্ছে এবং আমি অন্যভাবে কীভাবে এই কার্যকারিতাটি বাস্তবায়ন করব? (বাস্তবায়নটিকে __new__পুরোপুরি হ্যাকি মনে করে putting

__init__এটি ইতিমধ্যে আরম্ভ করা থাকলে আপনি কিছুই করতে পারতেন না বা আপনি একটি নতুন দিয়ে একটি নতুন মেটাক্লাস লিখতে পারেন __call__যা কেবলমাত্র __init__নতুন উদাহরণগুলিতে কল করে এবং অন্যথায় কেবল ফিরে আসে __new__(...)


1

সহজ কারণে যে নতুন , একটি দৃষ্টান্ত তৈরি করার জন্য ব্যবহার করা হয় যখন Init উদাহরণস্বরূপ আরম্ভের জন্য ব্যবহৃত হয়। আরম্ভ করার আগে, উদাহরণটি প্রথমে তৈরি করা উচিত। যে কেন নতুন আগে বলা উচিত Init


1

এখন আমিও একই সমস্যা পেয়েছি এবং কিছু কারণে আমি সজ্জকার, কারখানা এবং মেটাক্লাসগুলি এড়িয়ে যাওয়ার সিদ্ধান্ত নিয়েছি। আমি এটি এর মতো করেছিলাম:

প্রধান ফাইল

def _alt(func):
    import functools
    @functools.wraps(func)
    def init(self, *p, **k):
        if hasattr(self, "parent_initialized"):
            return
        else:
            self.parent_initialized = True
            func(self, *p, **k)

    return init


class Parent:
    # Empty dictionary, shouldn't ever be filled with anything else
    parent_cache = {}

    def __new__(cls, n, *args, **kwargs):

        # Checks if object with this ID (n) has been created
        if n in cls.parent_cache:

            # It was, return it
            return cls.parent_cache[n]

        else:

            # Check if it was modified by this function
            if not hasattr(cls, "parent_modified"):
                # Add the attribute
                cls.parent_modified = True
                cls.parent_cache = {}

                # Apply it
                cls.__init__ = _alt(cls.__init__)

            # Get the instance
            obj = super().__new__(cls)

            # Push it to cache
            cls.parent_cache[n] = obj

            # Return it
            return obj

উদাহরণ ক্লাস

class A(Parent):

    def __init__(self, n):
        print("A.__init__", n)


class B(Parent):

    def __init__(self, n):
        print("B.__init__", n)

ব্যাবহৃত হচ্ছে

>>> A(1)
A.__init__ 1  # First A(1) initialized 
<__main__.A object at 0x000001A73A4A2E48>
>>> A(1)      # Returned previous A(1)
<__main__.A object at 0x000001A73A4A2E48>
>>> A(2)
A.__init__ 2  # First A(2) initialized
<__main__.A object at 0x000001A7395D9C88>
>>> B(2)
B.__init__ 2  # B class doesn't collide with A, thanks to separate cache
<__main__.B object at 0x000001A73951B080>
  • সতর্কতা: আপনার পিতামাতাকে আরম্ভ করা উচিত নয়, এটি অন্যান্য ক্লাসগুলির সাথে সংঘর্ষে পড়বে - যদি না আপনি প্রতিটি সন্তানের পৃথক ক্যাশে সংজ্ঞায়িত করেন, তবে আমরা যা চাই তা তা নয়।
  • সতর্কতা: পিতামাতার সাথে অদ্ভুত আচরণ করার কারণে এটি পিতামাতার সাথে একটি বর্গ বলে মনে হচ্ছে। [অযাচাইকৃত]

এটি অনলাইন চেষ্টা করুন!

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