পাইথনটি প্রসারিত করছে - সুপার () পাইথন 3 বনাম পাইথন 2 ব্যবহার করে


105

মূলত আমি এই প্রশ্নটি জিজ্ঞাসা করতে চেয়েছিলাম , কিন্তু তারপরে আমি দেখতে পেয়েছিলাম এটি ইতিমধ্যে আগেই ভাবা হয়েছিল ...

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

$ python3
Python 3.2.3rc2 (default, Mar 21 2012, 06:59:51) 
[GCC 4.6.3] on linux2
>>> from configparser import  SafeConfigParser
>>> class AmritaConfigParser(SafeConfigParser):
...     def __init_(self):
...         super().__init__()
... 
>>> cfg = AmritaConfigParser()

তবে পাইথন 2 এর সাথে নয়:

>>> class AmritaConfigParser(SafeConfigParser):
...       def __init__(self):
...           super(SafeConfigParser).init()
... 
>>> cfg = AmritaConfigParser()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
TypeError: must be type, not classob

তারপরে আমি পাইথন নিউ ক্লাস বনাম ওল্ড ক্লাস শৈলীতে কিছুটা পড়লাম (যেমন এখানে । এবং এখন আমি ভাবছি, আমি এটি করতে পারি:

class MyConfigParser(ConfigParser.ConfigParser):
      def Write(self, fp):
          """override the module's original write funcition"""
          ....
      def MyWrite(self, fp):
          """Define new function and inherit all others"""

কিন্তু, আমি কি কল না করা উচিত? এটি কি পাইথন 2 এর সমতুল্য:

 class AmritaConfigParser(ConfigParser.SafeConfigParser):
    #def __init__(self):
    #    super().__init__() # Python3 syntax, or rather, new style class syntax ...
    #
    # is this the equivalent of the above ? 
    def __init__(self):
        ConfigParser.SafeConfigParser.__init__(self)

4
আপনার উদাহরণে আপনাকে __init__()সাবক্লাসে কোনও সংজ্ঞায়িত করার দরকার নেই যদি এটি সুপার ক্লাসকে ' __init__()(পাইথন 2 বা 3 তে হয়) বলা হয় - পরিবর্তে কেবল সুপারটির উত্তরাধিকার সূত্রে আসুন।
মার্টিনিউ

দরকারী রেফারেন্স: amyboyle.ninja/Python-Inheritance
নিউ এভারেস্ট

সংশোধিত লিঙ্ক সহ দরকারী রেফারেন্স: amyboyle.ninja/Python-Inheritance
fearless_fool

উত্তর:


157
  • super()(তর্ক ছাড়াই) পাইথন 3 এ প্রবর্তিত হয়েছিল (পাশাপাশি __class__):

    super() -> same as super(__class__, self)
    

    সুতরাং এটি হবে নতুন স্টাইলের ক্লাসগুলির জন্য পাইথন 2 সমতুল্য:

    super(CurrentClass, self)
    
  • পুরানো স্টাইলের ক্লাসগুলির জন্য আপনি সর্বদা ব্যবহার করতে পারেন:

     class Classname(OldStyleParent):
        def __init__(self, *args, **kwargs):
            OldStyleParent.__init__(self, *args, **kwargs)
    

9
-1। এই উত্তরটি আমার পক্ষে কিছুই পরিষ্কার করে দেয় না। পাইথন 2 এ, super(__class__)দেয় NameError: global name '__class__' is not definedএবং super(self.__class__)ভুলও হয়। আপনাকে অবশ্যই দ্বিতীয় যুক্তি হিসাবে একটি উদাহরণ সরবরাহ করতে হবে, যা আপনাকে এটি করার দরকার পরামর্শ দেয় super(self.__class__, self)তবে এটি ভুল । যদি Class2থেকে উত্তরাধিকারী Class1এবং Class1কল super(self.__class__, self).__init__(), Class1এর __init__পরে হবে নিজেই কল যখন একটি দৃষ্টান্ত শুরু করতে গিয়ে Class2
jpmc26

একটি বিষয় স্পষ্ট করার জন্য, পাইথন ২ এ TypeError: super() takes at least 1 argument (0 given)কল করার চেষ্টা করার সময় আমি পেয়েছি super(self.__class__)2 (যা খুব একটা বোঝায় না, তবে এটি এই উত্তরটি থেকে কতটা তথ্য অনুপস্থিত তা দেখায়))
jpmc26

4
@ jpmc26: python2 আপনি কারণ আপনার কল করতে চাইছেন এই ভুল পান __init__()আনবাউন্ড সুপার বস্তু (যা আপনি কল করে পেতে উপর যুক্তি ছাড়া super(self.__class__)শুধুমাত্র একটি আর্গুমেন্ট সহ), আপনি একটি বাউন্ড সুপার বস্তুর প্রয়োজন তাহলে এটি কাজ করা উচিত: super(CurrentClass, self).__init__()। ব্যবহার করবেন না self.__class__কারণ পিতামাতাকে কল করার সময় এটি সর্বদা একই ক্লাসের সাথে সম্পর্কিত হবে এবং যদি সেই পিতামাতারও একই কাজ করে তবে একটি অসীম লুপ তৈরি করে।
মাতা

__class__পাইথন 2 এও (সদস্য) উপস্থিত রয়েছে ।
ক্রিশ্চটি ফাতি

4
@ ক্রিসিটি ফাতি এটি __class__সদস্য সম্পর্কে নয় তবে পরিপূর্ণভাবে তৈরি করা লেজিকাল __class__ক্লোজার সম্পর্কে যা সর্বদা বর্তমানে সংজ্ঞায়িত শ্রেণিকে বোঝায়, যা পাইথন 2 তে নেই।
মাতা

51

একক উত্তরাধিকারের ক্ষেত্রে (যখন আপনি কেবল একটি শ্রেণীর সাবক্লাস করেন), আপনার নতুন শ্রেণিটি বেস শ্রেণির পদ্ধতি উত্তরাধিকার সূত্রে প্রাপ্ত। এর মধ্যে রয়েছে __init__। সুতরাং আপনি যদি এটি আপনার ক্লাসে সংজ্ঞায়িত না করেন তবে আপনি বেস থেকে একটি পাবেন।

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

এই ধরনের ক্ষেত্রে, আপনি যদি সত্যিই ব্যবহার superকরতে পারেন তবে আমি কেন তা ব্যাখ্যা করব। কিন্তু সবসময় আপনি পারেন না। সমস্যাটি হ'ল আপনার সমস্ত বেস ক্লাসগুলিও এটি ব্যবহার করতে হবে (এবং তাদের বেস ক্লাসগুলিও - পুরো গাছ)।

যদি এটি হয় তবে এটিও সঠিকভাবে কাজ করবে (পাইথন 3 এ তবে আপনি এটি পাইথন 2 এ পুনরায় কাজ করতে পারেন - এটিতেও রয়েছে super):

class A:
    def __init__(self):
        print('A')
        super().__init__()

class B:
    def __init__(self):
        print('B')
        super().__init__()

class C(A, B):
    pass

C()
#prints:
#A
#B

উভয় বেস ক্লাস superতাদের নিজস্ব বেস ক্লাস না থাকলেও কীভাবে ব্যবহার করে তা লক্ষ্য করুন ।

কি superকরে: এটি ম্রো পরবর্তী ক্লাস থেকে পদ্ধতি (পদ্ধতি রেজল্যুশন অর্ডার) কল। জন্য ম্রো Cহল: (C, A, B, object)। আপনি এটি মুদ্রণ C.__mro__করতে পারেন।

সুতরাং, Cউত্তরাধিকারী __init__থেকে Aএবং superA.__init__কল B.__init__( Bঅনুসরণ Aম্রো মধ্যে)।

তাই কিছুই না করে Cআপনি উভয়কেই কল করবেন, যা আপনি চান।

এখন যদি আপনি ব্যবহার করা হয় নি super, আপনি inheriting শেষ পর্যন্ত হবে A.__init__(পূর্বের মত) কিন্তু এই সময় কিছু না যে কল করবে আছে B.__init__আপনার জন্য।

class A:
    def __init__(self):
        print('A')

class B:
    def __init__(self):
        print('B')

class C(A, B):
    pass

C()
#prints:
#A

আপনাকে সংজ্ঞায়িত করতে হবে তা ঠিক করতে C.__init__:

class C(A, B):
    def __init__(self):
        A.__init__(self)
        B.__init__(self)

এর সাথে সমস্যাটি হ'ল আরও জটিল এমআই গাছগুলিতে __init__কিছু শ্রেণির পদ্ধতিগুলি একাধিকবার কল হতে পারে তবে সুপার / এমআরও গ্যারান্টি দেয় যে তারা কেবল একবার ডেকেছে।


11
Notice how both base classes use super even though they don't have their own base classes.তাদের আছে. Py3k এ প্রতিটি শ্রেণীর সাবক্লাস অবজেক্ট।
ওরফেমে

এই উত্তরটি আমি খুঁজছিলাম, তবে কীভাবে জিজ্ঞাসা করতে হবে তা জানতাম না। এমআরও বর্ণনাটি ভাল।
dturvene

27

সংক্ষেপে, তারা সমতুল্য। আসুন একটি ইতিহাস দেখুন:

(1) প্রথমে, ফাংশনটি এর মতো দেখাচ্ছে।

    class MySubClass(MySuperClass):
        def __init__(self):
            MySuperClass.__init__(self)

(২) কোডটিকে আরও বিমূর্ত (এবং আরও বহনযোগ্য) করা। সুপার-ক্লাস পাওয়ার জন্য একটি সাধারণ পদ্ধতি আবিষ্কার করা হয়েছে যেমন:

    super(<class>, <instance>)

আর init ফাংশনটি হ'ল:

    class MySubClassBetter(MySuperClass):
        def __init__(self):
            super(MySubClassBetter, self).__init__()

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

(3) ভি 3 এ। এটি আরও স্মার্ট,

    super()

বেশিরভাগ ক্ষেত্রেই যথেষ্ট। আপনি http://www.python.org/dev/peps/pep-3135/ দেখুন


23

পাইথন 3 এর জন্য কেবল একটি সাধারণ এবং সম্পূর্ণ উদাহরণ রয়েছে, যা বেশিরভাগ লোকেরা এখন ব্যবহার করছেন বলে মনে হয়।

class MySuper(object):
    def __init__(self,a):
        self.a = a

class MySub(MySuper):
    def __init__(self,a,b):
        self.b = b
        super().__init__(a)

my_sub = MySub(42,'chickenman')
print(my_sub.a)
print(my_sub.b)

দেয়

42
chickenman

3

আরও একটি পাইথন 3 বাস্তবায়ন যা সুপার () সহ বিমূর্ত শ্রেণির ব্যবহারের সাথে জড়িত। আপনার এটা মনে রাখা উচিত

super().__init__(name, 10)

হিসাবে একই প্রভাব আছে

Person.__init__(self, name, 10)

মনে রাখবেন সুপার () এ একটি লুকানো 'স্ব' রয়েছে, সুতরাং একই বস্তু সুপারক্লাস আর ডি পদ্ধতিতে চলে যায় এবং বৈশিষ্ট্যগুলিকে সেই বস্তুতে যুক্ত করা হয় যেটিকে এটি বলে। সুতরাং super()অনুবাদ করা হয় Personএবং তারপরে আপনি যদি লুকানো স্ব অন্তর্ভুক্ত করেন তবে আপনি উপরের কোডটি ভঙ্গুর পেতে পারেন।

from abc import ABCMeta, abstractmethod
class Person(metaclass=ABCMeta):
    name = ""
    age = 0

    def __init__(self, personName, personAge):
        self.name = personName
        self.age = personAge

    @abstractmethod
    def showName(self):
        pass

    @abstractmethod
    def showAge(self):
        pass


class Man(Person):

    def __init__(self, name, height):
        self.height = height
        # Person.__init__(self, name, 10)
        super().__init__(name, 10)  # same as Person.__init__(self, name, 10)
        # basically used to call the superclass init . This is used incase you want to call subclass init
        # and then also call superclass's init.
        # Since there's a hidden self in the super's parameters, when it's is called,
        # the superclasses attributes are a part of the same object that was sent out in the super() method

    def showIdentity(self):
        return self.name, self.age, self.height

    def showName(self):
        pass

    def showAge(self):
        pass


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