সুপারক্লাস __init__ পদ্ধতিগুলি কেন স্বয়ংক্রিয়ভাবে প্রার্থিত হয় না?


155

পাইথন ডিজাইনাররা কেন সিদ্ধান্ত নিয়েছিলেন যে সাবক্লাসের __init__()পদ্ধতিগুলি __init__()অন্য কয়েকটি ভাষায় যেমন স্বয়ংক্রিয়ভাবে তাদের চশমাগুলির পদ্ধতিগুলি কল করে না ? পাইথোনিক এবং প্রস্তাবিত প্রতিমাটি কি আসলে নীচের মত?

class Superclass(object):
    def __init__(self):
        print 'Do something'

class Subclass(Superclass):
    def __init__(self):
        super(Subclass, self).__init__()
        print 'Do something else'

2
__init__পদ্ধতিটি উত্তরাধিকারী করার জন্য আপনি একটি সজ্জনকারী লিখতে পারেন এবং এমনকি স্বয়ংক্রিয়ভাবে সাবক্লাসগুলির জন্য অনুসন্ধান করতে এবং সেগুলি সজ্জিত করতে পারেন।
ওসা

2
@ কী, সত্যিই খুব ভাল ধারণা শোনায়। আপনি কি সাজসজ্জার অংশ থেকে আরও কিছু বর্ণনা করতে চান?
দিয়ানশেং

1
@ হোস আরও বর্ণনা!
চার্লি পার্কার

উত্তর:


163

পাইথন এর মধ্যে গুরুত্বপূর্ণ পার্থক্য __init__এবং যারা অন্য ভাষায় কনস্ট্রাকটর যে __init__হয় না এটি একটি: একটি কন্সট্রাকটর সূচনাকারী (প্রকৃত কন্সট্রাকটর , (যদি থাকে, কিন্তু দেখতে পরে ;-) হয় __new__এবং কাজ করে সম্পূর্ণরূপে ভিন্নভাবে আবার)। সমস্ত সুপারক্লাস নির্মাণ করার সময় (এবং নিঃসন্দেহে, আপনি নীচের দিকে নির্মাণ চালিয়ে যেতে "আগে" এটি করা স্পষ্টতই বলছেন যে আপনি সাবক্লাসের উদাহরণটি নির্মাণ করছেন , এটি স্পষ্টতই আরম্ভের ক্ষেত্রে নয়), যেহেতু অনেকগুলি ব্যবহারের কেস রয়েছে যেখানে সুপারক্লাসের প্রারম্ভিককরণটি বাদ দেওয়া, পরিবর্তন করা, নিয়ন্ত্রিত - ঘটতে হবে, যদি আদৌ হয় তবে সাবক্লাস সূচনাটির "মাঝখানে" এবং আরও অনেক কিছু।

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


7
উত্সাহিত কারণ আমার জন্য, আসল উপকারিতা হ'ল সাবক্লাসের সূচনাকরণের কোনও পর্যায়ে (বা মোটেও নয়) সুপারক্লাসের _ ইনি (_) _ কল করার ক্ষমতা আপনি উল্লেখ করেছেন ।
kindall

53
-1 এর জন্য " __init__কনস্ট্রাক্টর নয় ... আসল কনস্ট্রাক্টর ... __new__"। আপনি যেমন খেয়াল করেন, __new__অন্য ভাষা থেকে কোনও নির্মাণকারীর মতো আচরণ করে না। __init__আসলে এটি খুব অনুরূপ (এটি নতুন অবজেক্ট তৈরির সময় বলা হয়, সেই বস্তুটি বরাদ্দের পরে নতুন বস্তুতে সদস্য ভেরিয়েবলগুলি সেট করার জন্য), এবং প্রায় সবসময় কার্যকারিতা বাস্তবায়নের জায়গা যেখানে অন্যান্য ভাষায় আপনি রাখতেন একজন কনস্ট্রাক্টর সুতরাং এটি কেবল একটি কনস্ট্রাক্টর বলুন!
বেন

8
আমিও মনে করি এটা একটা বরং কিম্ভুতকিমাকার বিবৃতি is: " নির্মাণের সব superclasses ... স্পষ্টত বলছে আপনি করছি অংশ নির্মাণের একটি উপশ্রেণী দৃষ্টান্ত স্পষ্ট কেনার ক্ষেত্রে নয় যে আরম্ভের "। নির্মাণ / সূচনা শব্দের মধ্যে এমন কোনও কিছুই নেই যা এটি কারও কাছে "স্পষ্ট" করে তোলে। এবং __new__স্বয়ংক্রিয়ভাবে সুপারক্লাসকেও ডাকে না __new__। সুতরাং আপনার দাবি যে কী পার্থক্য যে নির্মাণ অগত্যা superclasses নির্মাণের জড়িত যখন আরম্ভের নেই আপনার দাবির সঙ্গে সঙ্গতিহীন __new__কন্সট্রাকটর হয়।
বেন

36
বস্তুত, পাইথন ডক্স থেকে __init__docs.python.org/reference/datamodel.html#basic-customization : "একটি বিশেষ বাধ্যতা হিসাবে কনস্ট্রাকটর , কোন মান করা যেতে পারে; এমনটি একটি TypeError কারণ হবে রানটাইম এ উত্থাপিত করা "(জোর আমার)। সুতরাং সেখানে, এটি অফিসিয়াল, __init__একজন নির্মাতা।
বেন

3
পাইথন / জাভা পরিভাষায় __init__একে কনস্ট্রাক্টর বলা হয়। এই কনস্ট্রাক্টরটি একটি প্রাথমিককরণ ফাংশন যা অবজেক্টটি সম্পূর্ণরূপে নির্মিত হওয়ার পরে এবং তার চূড়ান্ত রানটাইম টাইপ সহ একটি ডিফল্ট অবস্থায় আরম্ভ হয়। এটি সি ++ কনস্ট্রাক্টরের সমতুল্য নয়, যা স্ট্যাটিকালি টাইপড, অবধারিত অবজেক্টের সাথে অপরিজ্ঞাত স্থিতিতে ডাকা হয়। এগুলি এর থেকেও পৃথক __new__, সুতরাং আমাদের কাছে কমপক্ষে চারটি বিভিন্ন ধরণের বরাদ্দ / নির্মাণ / প্রারম্ভিককরণ কার্য রয়েছে। ভাষাগুলি মিশ্র পরিভাষা ব্যবহার করে এবং গুরুত্বপূর্ণ অংশটি আচরণটি এবং পরিভাষা নয়।
এলাজার

36

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

কারণটি সহজ: আপনি বেস ক্লাসটি কীভাবে তৈরি করেন তার মতো আপনি কোনও উত্সবশত শ্রেণি তৈরি করবেন না। আপনার আরও প্যারামিটার থাকতে পারে, কম, সেগুলি অন্য কোনও ক্রমে থাকতে পারে বা সম্পর্কিত নয়।

class myFile(object):
    def __init__(self, filename, mode):
        self.f = open(filename, mode)
class readFile(myFile):
    def __init__(self, filename):
        super(readFile, self).__init__(filename, "r")
class tempFile(myFile):
    def __init__(self, mode):
        super(tempFile, self).__init__("/tmp/file", mode)
class wordsFile(myFile):
    def __init__(self, language):
        super(wordsFile, self).__init__("/usr/share/dict/%s" % language, "r")

এটি কেবলমাত্র নয়, সমস্ত উত্পন্ন পদ্ধতিতে প্রযোজ্য __init__


6
এই উদাহরণটি কি বিশেষ কিছু প্রস্তাব করে? স্থির ভাষা এটিও করতে পারে
জিন

18

জাভা এবং C ++ প্রয়োজন যে একটি বেস বর্গ কন্সট্রাকটর মেমরির লেআউট কারণ বলা হয়।

আপনার যদি BaseClassকোনও সদস্যের সাথে ক্লাস থাকে field1এবং আপনি একটি নতুন শ্রেণি তৈরি করেন SubClassযা কোনও সদস্যকে যুক্ত করে field2, তবে একটি উদাহরণে SubClassস্থান থাকেfield1 এবং field2। আপনার BaseClassপূরণের জন্য একজন কনস্ট্রাক্টর প্রয়োজন field1, যদি না আপনি সমস্ত উত্তরাধিকার সূত্রে প্রাপ্ত ক্লাসগুলির BaseClassনিজস্ব নির্মাণকারীগুলিতে পুনরায় আরম্ভ করার প্রয়োজন হয়। এবং যদি field1ব্যক্তিগত হয়, তবে উত্তরাধিকার সূত্রে প্রাপ্ত ক্লাসগুলি আরম্ভ করতে পারে নাfield1

পাইথন জাভা বা সি ++ নয়। সমস্ত ব্যবহারকারী-সংজ্ঞায়িত শ্রেণীর সমস্ত দৃষ্টান্তের একই 'আকার' থাকে। এগুলি মূলত কেবল অভিধান যা বৈশিষ্ট্যগুলি .োকানো যেতে পারে। কোনও সূচনা হওয়ার আগে, সমস্ত ব্যবহারকারী-সংজ্ঞায়িত শ্রেণীর সমস্ত উদাহরণ প্রায় একই রকম ; এগুলি কেবলমাত্র এমন বৈশিষ্ট্যগুলি সংরক্ষণ করার জন্য জায়গা যা এখনও কোনও সঞ্চয় করে না।

সুতরাং এটি পাইথন সাবক্লাসের জন্য তার বেস শ্রেণীর কনস্ট্রাক্টরকে কল না করার জন্য এটি সঠিক ধারণা দেয়। এটি চাইলে কেবল এটি বৈশিষ্ট্যগুলি যুক্ত করতে পারে। অনুক্রমের প্রতিটি শ্রেণীর জন্য প্রদত্ত সংখ্যার ক্ষেত্রের জন্য কোনও স্থান সংরক্ষিত নেই BaseClassএবং কোনও SubClassপদ্ধতি থেকে কোড দ্বারা সংযুক্ত একটি গুণাবলী এবং কোনও পদ্ধতি থেকে কোড দ্বারা সংযুক্ত একটি গুণীর মধ্যে পার্থক্য নেই ।

যদি, সাধারণ হিসাবে, SubClass আসলে BaseClassএটির নিজস্ব কাস্টমাইজেশনটি চালানোর আগে তার সমস্ত আক্রমণকারী সেট আপ করতে চায় তবে হ্যাঁ আপনি কেবল কল করতে পারেন BaseClass.__init__()(বা ব্যবহার করুন super, তবে এটি জটিল এবং কখনও কখনও এর নিজস্ব সমস্যা আছে)। তবে আপনার দরকার নেই। এবং আপনি এটি আগে বা পরে বা বিভিন্ন যুক্তি দিয়ে করতে পারেন। জাহান্নাম, আপনি চাইলে আপনি BaseClass.__init__অন্য কোনও পদ্ধতি থেকে পুরোপুরি কল করতে পারেন __init__; সম্ভবত আপনার কিছু উদ্ভট অলস সূচনা চলছে।

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


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

10

"অন্তর্নিহিতের চেয়ে সুস্পষ্ট ভাল" " এটি একই যুক্তি যা ইঙ্গিত দেয় যে আমাদের স্পষ্টভাবে 'স্ব' লিখতে হবে।

আমি মনে করি শেষ পর্যন্ত এটি একটি উপকার - আপনি সুপার ক্লাসের কনস্ট্রাক্টরদের কল করার বিষয়ে জাভা যে সমস্ত নিয়মাবলী আবৃত্তি করতে পারেন তা কি পাঠ করতে পারেন?


8
আমি বেশিরভাগ অংশে আপনার সাথে একমত, তবে জাভার নিয়মটি আসলে বেশ সহজ: আপনি নির্দিষ্টভাবে অন্যটির জন্য না চাইলে নো-আরগ নির্মাণকারীকে ডাকা হবে।
লরেন্স গনসালভেস

1
@ লরেন্স - যখন প্যারেন্ট ক্লাসটি নো-আরগ কনস্ট্রাক্টরকে সংজ্ঞায়িত না করে তখন কী হয়? নো-আরগ কনস্ট্রাক্টর সুরক্ষিত বা ব্যক্তিগত হলে কী হবে?
মাইক অ্যাক্সিয়াক

8
আপনি একইভাবে কল করার চেষ্টা করলে ঠিক একই জিনিসটি ঘটবে।
লরেন্স গনসাল্ভেস

8

প্রায়শই সাবক্লাসে অতিরিক্ত পরামিতি থাকে যা সুপারক্লাসে যেতে পারে না।


7

এই মুহুর্তে, আমাদের একাধিক উত্তরাধিকারের ক্ষেত্রে পদ্ধতি রেজোলিউশন অর্ডার বর্ণনা করার পরিবর্তে একটি দীর্ঘ পৃষ্ঠা রয়েছে: http://www.python.org/download/releases/2.3/mro/

যদি কনস্ট্রাক্টরকে স্বয়ংক্রিয়ভাবে ডাকা হত, আপনার ঘটনার ক্রম ব্যাখ্যা করে আপনার কমপক্ষে একই দৈর্ঘ্যের আরেকটি পৃষ্ঠা প্রয়োজন। এটা জাহান্নাম হবে ...


এই ছিল সঠিক উত্তর। পাইথনের সাবক্লাস এবং সুপারক্লাসের মধ্যে পাস করার যুক্তিগুলির শব্দার্থবিজ্ঞানের সংজ্ঞা দেওয়া দরকার। খুব খারাপ এই উত্তরটি আপভোট করা হয় না। এটি যদি কিছু উদাহরণ দিয়ে সমস্যাটি দেখায়?
গ্যারি ওয়েইস

5

বিভ্রান্তি এড়ানোর জন্য এটি জেনে রাখা কার্যকর হবে যে __init__()যদি চাইল্ড_ক্লাসের __init__()ক্লাস না থাকে তবে আপনি বেস_ক্লাস পদ্ধতিটি চালু করতে পারেন ।

উদাহরণ:

class parent:
  def __init__(self, a=1, b=0):
    self.a = a
    self.b = b

class child(parent):
  def me(self):
    pass

p = child(5, 4)
q = child(7)
z= child()

print p.a # prints 5
print q.b # prints 0
print z.a # prints 1

প্রকৃতপক্ষে পাইথনের এমআরও পিতামাত্ত __init__()শ্রেণিতে সন্ধান করবে যখন শিশু শ্রেণিতে এটি খুঁজে পাবে না। আপনার যদি ইতিমধ্যে __init__()বাচ্চাদের ক্লাসে কোনও পদ্ধতি থাকে তবে আপনাকে সরাসরি অভিভাবক শ্রেণীর নির্মাতাকে ডাকতে হবে ।

উদাহরণস্বরূপ নিম্নলিখিত কোডটি একটি ত্রুটি ফিরিয়ে দেবে: শ্রেণি পিতামাতার: ডিফ আরম্ভ (স্ব, a = 1, খ = 0): স্ব.এ = একটি স্ব.বি = বি

    class child(parent):
      def __init__(self):
        pass
      def me(self):
        pass

    p = child(5, 4) # Error: constructor gets one argument 3 is provided.
    q = child(7)  # Error: constructor gets one argument 2 is provided.

    z= child()
    print z.a # Error: No attribute named as a can be found.

3

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

যদি সেগুলি আপনাকে দমন করে না, তবে __init__এটি কেবল অন্য একটি কাজ consider যদি প্রশ্নটির মধ্যে ফাংশনটি dostuffপরিবর্তিত হয়, আপনি কি চাইবেন যে পাইথন স্বয়ংক্রিয়ভাবে প্যারেন্ট ক্লাসে সংশ্লিষ্ট ফাংশনটি কল করতে চান?


2

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

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

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