পাইথনে 'সুপার' কী করবে?


563

এর মধ্যে পার্থক্য কী:

class Child(SomeBaseClass):
    def __init__(self):
        super(Child, self).__init__()

এবং:

class Child(SomeBaseClass):
    def __init__(self):
        SomeBaseClass.__init__(self)

আমি superকেবল একক উত্তরাধিকার সহ ক্লাসে বেশ ব্যবহৃত হতে দেখেছি । আপনি দেখতে পাচ্ছেন যে আপনি কেন এটি একাধিক উত্তরাধিকার হিসাবে ব্যবহার করছেন তবে এ জাতীয় পরিস্থিতিতে এটির সুবিধা কী কী তা সম্পর্কে অস্পষ্ট।

উত্তর:


308

super()একক-উত্তরাধিকারের সুবিধাগুলি ন্যূনতম - বেশিরভাগ ক্ষেত্রে, আপনাকে বেসড ক্লাসের নামটি প্রতিটি পদ্ধতিতে ব্যবহার করতে হয় না যা তার পিতামাতার পদ্ধতিগুলি ব্যবহার করে।

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


6
"এটি সঠিকভাবে কাজ করবে না" এর সাথে আপনি কী বোঝাতে চেয়েছেন আপনি একটি উদাহরণ প্রদান করতে পারেন?
চার্লি পার্কার

319

পার্থক্য কি?

SomeBaseClass.__init__(self) 

কলে মানে SomeBaseClass's __init__। যখন

super(Child, self).__init__()

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

উদাহরণটি যদি সন্তানের একটি সাবক্লাস হয় তবে এমআরওয়ের পরবর্তী কোনও আলাদা পিতামাত থাকতে পারে।

সহজভাবে ব্যাখ্যা করা হয়েছে

আপনি যখন একটি ক্লাস লিখেন, আপনি অন্যান্য ক্লাসগুলি এটি ব্যবহারের জন্য সক্ষম হতে চান। super()অন্যান্য ক্লাসগুলির পক্ষে আপনি যে ক্লাসটি লিখছেন তা ব্যবহার করা সহজ করে তোলে।

বব মার্টিন যেমন বলেছেন, একটি ভাল আর্কিটেকচার আপনাকে যতক্ষণ সম্ভব সিদ্ধান্ত গ্রহণ স্থগিত করতে দেয়।

super() এই ধরণের আর্কিটেকচার সক্ষম করতে পারে।

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

superআপনি ছাড়াই সম্ভবত আপনি যে শ্রেণীর লেখছেন তার পিতামাতাকে হার্ড-কোড করতে হবে (যেমন উদাহরণটি দেয়)। এর অর্থ __init__হ'ল আপনি এমআরওতে পরবর্তী কল করবেন না এবং আপনি এতে কোডটি পুনরায় ব্যবহার করতে পারবেন না।

আপনি যদি ব্যক্তিগত ব্যবহারের জন্য নিজের কোড লিখছেন তবে আপনি এই পার্থক্যের বিষয়ে চিন্তা করবেন না। তবে আপনি যদি অন্যদের আপনার কোড ব্যবহার করতে চান তবে কোড ব্যবহারের ক্ষেত্রে superএমন একটি জিনিস যা ব্যবহারকারীর জন্য বৃহত্তর নমনীয়তার সুযোগ দেয়।

পাইথন 2 বনাম 3

এটি পাইথন 2 এবং 3 তে কাজ করে:

super(Child, self).__init__()

এটি কেবল পাইথন 3 এ কাজ করে:

super().__init__()

এটি স্ট্যাক ফ্রেমে উঠে এবং পদ্ধতির প্রথম যুক্তি (সাধারণত selfউদাহরণস্বরূপ বা clsকোনও শ্রেণীর পদ্ধতির জন্য - তবে অন্য নাম হতে পারে) এবং Childনিখরচায় ভেরিয়েবল ( যেমন ) শ্রেণীর সন্ধান করে কোনও যুক্তি ছাড়াই কাজ করে ( পদ্ধতিতে এটি __class__একটি মুক্ত ক্লোজার ভেরিয়েবল হিসাবে নামের সাথে দেখা হয় )।

আমি ক্রসের সাথে সামঞ্জস্যপূর্ণ পদ্ধতিটি প্রদর্শন করতে পছন্দ করি superতবে আপনি যদি পাইথন 3 ব্যবহার করেন তবে আপনি কোনও যুক্তি ছাড়াই এটি কল করতে পারেন।

ফরোয়ার্ড সামঞ্জস্যের সাথে নির্দেশনা

এটা আপনাকে কি দেয়? একক উত্তরাধিকারের জন্য, প্রশ্ন থেকে প্রাপ্ত উদাহরণগুলি স্থির বিশ্লেষণের দৃষ্টিকোণ থেকে কার্যত অভিন্ন। তবে, ব্যবহার superআপনাকে সামনের সামঞ্জস্যের সাথে ইন্ডিয়ারেকশনের একটি স্তর দেয়।

ফরোয়ার্ড সামঞ্জস্যতা পাকা বিকাশকারীদের কাছে খুব গুরুত্বপূর্ণ। আপনি চান যে আপনার কোডটি পরিবর্তন করার সাথে সাথে ন্যূনতম পরিবর্তনগুলির সাথে কাজ করা চলবে। আপনি যখন আপনার পুনর্বিবেচনার ইতিহাসটি দেখেন, আপনি কখন কী পরিবর্তন হয়েছিল তা অবিকল দেখতে চান।

আপনি একক উত্তরাধিকার দিয়ে শুরু করতে পারেন, তবে আপনি যদি অন্য বেস ক্লাস যুক্ত করার সিদ্ধান্ত নিয়ে থাকেন তবে আপনাকে কেবল ঘাঁটিগুলির সাথে রেখাটি পরিবর্তন করতে হবে - যদি আপনি যে শ্রেণি থেকে উত্তরাধিকারী হন সেগুলিতে যদি ঘাঁটিগুলি পরিবর্তন হয় (বলুন একটি মিশ্রণ যোগ করা হয়েছে) আপনি পরিবর্তন করতে চান এই শ্রেণিতে কিছুই না। বিশেষত পাইথন ২-তে, যুক্তিগুলি superএবং সঠিক পদ্ধতির যুক্তিগুলি সঠিকভাবে পাওয়া কঠিন হতে পারে। আপনি যদি জানেন যে আপনি superএকক উত্তরাধিকারের সাথে সঠিকভাবে ব্যবহার করছেন , এটি ডিবাগিংকে সামনের দিকে এগিয়ে যাওয়া কম করে তোলে।

ইনজেকশন নির্ভরতা

অন্যান্য লোকেরা আপনার কোডটি ব্যবহার করতে পারেন এবং পদ্ধতি সমাধানের জন্য পিতামাতাকে ইনজেক্ট করতে পারেন:

class SomeBaseClass(object):
    def __init__(self):
        print('SomeBaseClass.__init__(self) called')

class UnsuperChild(SomeBaseClass):
    def __init__(self):
        print('UnsuperChild.__init__(self) called')
        SomeBaseClass.__init__(self)

class SuperChild(SomeBaseClass):
    def __init__(self):
        print('SuperChild.__init__(self) called')
        super(SuperChild, self).__init__()

বলুন যে আপনি নিজের অবজেক্টে আরও একটি ক্লাস যুক্ত করেছেন, এবং ফু এবং বার (পরীক্ষা করার জন্য বা অন্য কোনও কারণে) এর মধ্যে একটি ক্লাস ইনজেকশন করতে চান:

class InjectMe(SomeBaseClass):
    def __init__(self):
        print('InjectMe.__init__(self) called')
        super(InjectMe, self).__init__()

class UnsuperInjector(UnsuperChild, InjectMe): pass

class SuperInjector(SuperChild, InjectMe): pass

আন-সুপার শিশু ব্যবহার করা নির্ভরতা ইনজেকশনে ব্যর্থ হয় কারণ আপনি যে শিশুটি ব্যবহার করছেন তা তার নিজের নামে ডাকার পদ্ধতিটি কঠোর কোড করেছে:

>>> o = UnsuperInjector()
UnsuperChild.__init__(self) called
SomeBaseClass.__init__(self) called

তবে, শিশুটির সাথে যে শ্রেণিটি ব্যবহার করে superসঠিকভাবে নির্ভরতা ইনজেক্ট করতে পারে:

>>> o2 = SuperInjector()
SuperChild.__init__(self) called
InjectMe.__init__(self) called
SomeBaseClass.__init__(self) called

একটি মন্তব্য সম্বোধন

পৃথিবীতে কেন এটি দরকারী হবে?

পাইথন একটি পদ্ধতি রেজোলিউশন অর্ডার (এমআরও) তৈরি করতে সি 3 লিনিয়ারাইজেশন অ্যালগরিদমের মাধ্যমে একটি জটিল উত্তরাধিকার গাছকে লিনিয়ারাইজ করে

আমরা চাই পদ্ধতি তাকিয়ে করা , যাতে

কোনও পিতা-মাতার মধ্যে সংজ্ঞায়িত কোনও পদ্ধতির জন্য সেই ক্রম ছাড়াই পরবর্তীটিকে সন্ধান করার জন্য এটি superকরতে হবে

  1. উদাহরণের ধরণ থেকে ম্রো পান
  2. পদ্ধতিটি সংজ্ঞায়িত করে এমন ধরণের সন্ধান করুন
  3. পদ্ধতিটি সহ পরবর্তী ধরণের সন্ধান করুন
  4. এই পদ্ধতিটি আবদ্ধ করুন এবং এটি প্রত্যাশিত যুক্তি দিয়ে কল করুন

এর UnsuperChildঅ্যাক্সেস থাকা উচিত নয় InjectMe। "সর্বদা ব্যবহার এড়ানো" উপসংহারটি কেন হয় না super? আমি এখানে কি মিস করছি?

UnsuperChildনেই না এক্সেস আছে InjectMe। এটা UnsuperInjectorঅ্যাক্সেস আছে যে InjectMeএবং এখনো পদ্ধতি তা থেকে উত্তরাধিকারী থেকে ক্লাস পদ্ধতি কল করতে পারবেন না - UnsuperChild

উভয় শিশু শ্রেণীর এমআরও পরবর্তী যে পদ্ধতিটি একই নামে কল করার ইচ্ছা রয়েছে, এটি অন্য শ্রেণি হতে পারে এটি কখন তৈরি হয়েছিল তা অবগত ছিল না।

যার superহার্ড-কোডস নেই তার পিতামাতার পদ্ধতি - এইভাবে এটি তার পদ্ধতির আচরণকে সীমাবদ্ধ করেছে এবং উপক্লাসগুলি কল চেইনে কার্যকারিতা ইনজেক্ট করতে পারে না।

যার সাথে super আরও বেশি নমনীয়তা রয়েছে। পদ্ধতিগুলির জন্য কল চেইনটি আটকানো যেতে পারে এবং কার্যকারিতা ইনজেকশন করা যেতে পারে।

আপনার সেই কার্যকারিতাটির প্রয়োজন নাও হতে পারে তবে আপনার কোডের সাবক্ল্যাশাররা হয়ত থাকতে পারে।

উপসংহার

superপ্যারেন্ট ক্লাসটিকে হার্ড-কোডিংয়ের পরিবর্তে সর্বদা উল্লেখ করার জন্য ব্যবহার করুন ।

আপনার উদ্দেশ্যটি হ'ল পিতামাত্ত শ্রেণীর রেফারেন্স যা পরবর্তী লাইনে রয়েছে, বিশেষত আপনি সন্তানের উত্তরাধিকার সূত্রে দেখেন নি।

ব্যবহার superনা করা আপনার কোডের ব্যবহারকারীদের উপর অপ্রয়োজনীয় বাধা সৃষ্টি করতে পারে।


সি, দ্বি মত হল এই । কোড এখানে । যদি আমি listইন্টারফেসের আরও একটি বাস্তবায়ন যোগ করি, তবে বলুন doublylinkedlistঅ্যাপ্লিকেশনটি সহজেই এটিকে বেছে নিয়েছে। আমি config.txtলোড সময়ে পরিচয় এবং লিঙ্ক প্রয়োগের মাধ্যমে আমার উদাহরণটিকে আরও কনফিগার করতে পারি । এটি কি সঠিক উদাহরণ? যদি হ্যাঁ, আমি আপনার কোডটি কীভাবে সম্পর্কিত করব? উইকিতে ডিআই-এর প্রথম উপদেষ্টা দেখুন। কোন নতুন বাস্তবায়ন কনফিগারযোগ্য কোথায়? আপনার কোডে
23

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

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

35

আমি কিছুটা খেলেছি super()এবং স্বীকৃতি পেয়েছিলাম যে আমরা কলিং অর্ডার পরিবর্তন করতে পারি।

উদাহরণস্বরূপ, আমাদের পরবর্তী স্তরক্রম কাঠামো রয়েছে:

    A
   / \
  B   C
   \ /
    D

এই ক্ষেত্রে ম্রো ডি এর (শুধুমাত্র পাইথন 3 জন্য) হবে:

In [26]: D.__mro__
Out[26]: (__main__.D, __main__.B, __main__.C, __main__.A, object)

আসুন একটি ক্লাস তৈরি করুন যেখানে super()পদ্ধতি প্রয়োগের পরে কল করুন।

In [23]: class A(object): #  or with Python 3 can define class A:
...:     def __init__(self):
...:         print("I'm from A")
...:  
...: class B(A):
...:      def __init__(self):
...:          print("I'm from B")
...:          super().__init__()
...:   
...: class C(A):
...:      def __init__(self):
...:          print("I'm from C")
...:          super().__init__()
...:  
...: class D(B, C):
...:      def __init__(self):
...:          print("I'm from D")
...:          super().__init__()
...: d = D()
...:
I'm from D
I'm from B
I'm from C
I'm from A

    A
   / 
  B  C
    /
    D

সুতরাং আমরা দেখতে পাচ্ছি যে রেজোলিউশন অর্ডার এমআরওয়ের মতো। তবে আমরা যখন super()পদ্ধতির শুরুতে কল করি :

In [21]: class A(object):  # or class A:
...:     def __init__(self):
...:         print("I'm from A")
...:  
...: class B(A):
...:      def __init__(self):
...:          super().__init__()  # or super(B, self).__init_()
...:          print("I'm from B")
...:   
...: class C(A):
...:      def __init__(self):
...:          super().__init__()
...:          print("I'm from C")
...:  
...: class D(B, C):
...:      def __init__(self):
...:          super().__init__()
...:          print("I'm from D")
...: d = D()
...: 
I'm from A
I'm from C
I'm from B
I'm from D

আমাদের আলাদা অর্ডার রয়েছে এটি এমআরও টিপলের ক্রমটিকে বিপরীত করে।

    A
   / 
  B  C
    /
    D 

অতিরিক্ত পড়ার জন্য আমি পরবর্তী উত্তরগুলি সুপারিশ করব:

  1. সুপার (একটি বৃহত শ্রেণিবিন্যাস) সহ সি 3 লিনিয়ারাইজেশন উদাহরণ
  2. পুরানো এবং নতুন স্টাইলের ক্লাসগুলির মধ্যে গুরুত্বপূর্ণ আচরণের পরিবর্তন
  3. ইনসাইড স্টোরি অন নিউ স্টাইল ক্লাসেস

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

আমার খারাপ, আমি লক্ষ্য করিনি যে প্রতিটি ক্লাসের উদাহরণগুলি প্রথমে সুপার () দিয়ে শুরু করা হয়েছে। তারপরে যদি তা হয় তবে এটিসিবিডি করা উচিত নয়? আমি একরকম বুঝতে পারি কীভাবে এসিবিডি এসেছিল তবে এখনও তা বোঝাতে পারেনি এবং এখনও কিছুটা বিভ্রান্তি আছে। আমার বোঝাটি হ'ল, ডি = ডি () কে 2 টি স্ব-পরামিতি সহ ক্লাস ডি (বি, সি) বলা হয়, যেহেতু প্রথমে সুপার () সূচনা করা হয় তারপরে বিটিকে তার বৈশিষ্ট্যগুলির সাথে একত্রে ডাকা হয় তারপর ডি সি এর আগে মুদ্রণ করা হয় না কারণ শ্রেণি হয় ডি (বি, সি) এ দুটি স্ব-পরামিতি রয়েছে সুতরাং এটি দ্বিতীয় শ্রেণীর অবশ্যই চালিত করতে হবে যা ক্লাস সি (এ), মৃত্যুদন্ড কার্যকর করার পরে আর
সম্পাদনের

এটি ম্রো সংজ্ঞা উপর ভিত্তি করে চলছে ।
এসখালমন

1
তারপরে এটি সি মুদ্রণ করে বি প্রিন্ট করবে এবং শেষ পর্যন্ত ডি প্রিন্ট করবে আমি ঠিক আছি?
জেজেসন 3:38

2
আপনি প্রথমটি যতক্ষণ পেয়েছেন ততক্ষণ দ্বিতীয়টি বোঝা খুব সহজ। এটা ঠিক স্ট্যাকের মতো। আপনি মুদ্রণটিকে 'স্ট্যাকের দিকে ধাক্কা দিয়ে সুপার () ব্যবহার করেন, যখন এটি এ শেষ হয়ে যায় তখন এটি স্ট্যাকের মধ্যে জিনিসগুলি মুদ্রণ করা শুরু করে, যাতে আদেশটি বিপরীত হয়।
রোদ মঞ্জুর করুন

35

এই সমস্ত কি বেস ক্লাসটি একটি নতুন ধাঁচের শ্রেণি বলে ধরে নেওয়া যায় না?

class A:
    def __init__(self):
        print("A.__init__()")

class B(A):
    def __init__(self):
        print("B.__init__()")
        super(B, self).__init__()

পাইথন ২ এ কাজ করবে না ২ class Aঅবশ্যই নতুন স্টাইলের হতে হবে, অর্থাত:class A(object)


20

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

বিবেচনা করুন একটি বর্গ অনুক্রমের A, Bএবং Cযেখানে প্রতিটি বর্গ এটা নিম্নলিখিত এক অভিভাবক, এবং a, bএবং cপ্রতিটি নিজ নিজ দৃষ্টান্ত।

super(B, b) 
# resolves to the scope of B's parent i.e. A 
# and applies that scope to b, as if b was an instance of A

super(C, c) 
# resolves to the scope of C's parent i.e. B
# and applies that scope to c

super(B, c) 
# resolves to the scope of B's parent i.e. A 
# and applies that scope to c

superএকটি স্ট্যাটিকমেডোথের সাথে ব্যবহার করা

যেমন পদ্ধতি super()মধ্যে থেকে ব্যবহার__new__()

class A(object):
    def __new__(cls, *a, **kw):
        # ...
        # whatever you want to specialize or override here
        # ...

        return super(A, cls).__new__(cls, *a, **kw)

ব্যাখ্যা:

1- যদিও এটি __new__()প্রথম পরম হিসাবে কলিং ক্লাসের রেফারেন্স হিসাবে গ্রহণ করা স্বাভাবিক , এটি পাইথনে ক্লাসমেডুড হিসাবে প্রয়োগ করা হয় না , বরং একটি স্ট্যাটিকমেডোর হিসাবে প্রয়োগ করা হয়। এটি হ'ল, __new__()সরাসরি কল করার সময় কোনও শ্রেণীর রেফারেন্সটি প্রথম যুক্তি হিসাবে স্পষ্টভাবে পাস করতে হবে :

# if you defined this
class A(object):
    def __new__(cls):
        pass

# calling this would raise a TypeError due to the missing argument
A.__new__()

# whereas this would be fine
A.__new__(A)

2- super()অভিভাবক শ্রেণিতে উঠার জন্য যখন আমরা শিশু শ্রেণিকে Aপ্রথম যুক্তি হিসাবে পাস করি তখন আমরা আগ্রহের উদ্দেশ্যে একটি রেফারেন্স পাস করি, এক্ষেত্রে এটি শ্রেণীর রেফারেন্স যা A.__new__(cls)বলা হয়েছিল তা পাস হয়েছিল। বেশিরভাগ ক্ষেত্রে এটি শিশু শ্রেণির একটি রেফারেন্স হতে পারে। কিছু পরিস্থিতিতে এটি একাধিক প্রজন্মের উত্তরাধিকারের ক্ষেত্রে নাও হতে পারে।

super(A, cls)

3- যেহেতু একটি সাধারণ নিয়ম __new__()একটি অবিচলিত হিসাবে, super(A, cls).__new__তেমনি একটি স্ট্যাটিকমেডোথও ফিরিয়ে দেবে এবং এক্ষেত্রে অন্তর্দৃষ্টির বিষয়টির রেফারেন্স সহ সমস্ত যুক্তি সুস্পষ্টভাবে সরবরাহ করা দরকার cls

super(A, cls).__new__(cls, *a, **kw)

4- ছাড়া একই জিনিস করছেন super

class A(object):
    def __new__(cls, *a, **kw):
        # ...
        # whatever you want to specialize or override here
        # ...

        return object.__new__(cls, *a, **kw)

superএকটি উদাহরণ পদ্ধতি ব্যবহার করে

যেমন super()মধ্যে থেকে ব্যবহার__init__()

class A(object): 
    def __init__(self, *a, **kw):
        # ...
        # you make some changes here
        # ...

        super(A, self).__init__(*a, **kw)

ব্যাখ্যা:

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

# you try calling `__init__()` from the class without specifying an instance
# and a TypeError is raised due to the expected but missing reference
A.__init__() # TypeError ...

# you create an instance
a = A()

# you call `__init__()` from that instance and it works
a.__init__()

# you can also call `__init__()` with the class and explicitly pass the instance 
A.__init__(a)

2- যখন কলিং super()মধ্যে __init__()আমরা প্রথম আর্গুমেন্ট হিসাবে সন্তানের শ্রেণী এবং একটি দ্বিতীয় যুক্তি, যা সাধারণভাবে শিশু ক্লাসের একটা নিদর্শন একটি রেফারেন্স হিসাবে সুদ বস্তুর পাস।

super(A, self)

3- কলটি super(A, self)এমন একটি প্রক্সি প্রদান করে যা সুযোগটি সমাধান করবে এবং এটিকে selfএমনভাবে প্রয়োগ করবে যেন এটি এখন পিতামাতার শ্রেণীর উদাহরণ। আসুন যে প্রক্সি কল s। যেহেতু __init__()একটি উদাহরণ পদ্ধতি হ'ল কলটি পিতামাতার কাছে প্রথম যুক্তি হিসাবে s.__init__(...)একটি সূত্রটি স্পষ্টভাবে প্রেরণ করবে ।self__init__()

4- superআমাদের পিতামাতার সংস্করণটিতে স্পষ্টভাবে একটি উদাহরণের একটি রেফারেন্স দেওয়ার প্রয়োজন ছাড়াই এটি করার জন্য __init__()

class A(object): 
    def __init__(self, *a, **kw):
        # ...
        # you make some changes here
        # ...

        object.__init__(self, *a, **kw)

superএকটি শ্রেণিবদ্ধ সঙ্গে ব্যবহার করে

class A(object):
    @classmethod
    def alternate_constructor(cls, *a, **kw):
        print "A.alternate_constructor called"
        return cls(*a, **kw)

class B(A):
    @classmethod
    def alternate_constructor(cls, *a, **kw):
        # ...
        # whatever you want to specialize or override here
        # ...

        print "B.alternate_constructor called"
        return super(B, cls).alternate_constructor(*a, **kw)

ব্যাখ্যা:

1- একটি শ্রেণিবদ্ধকে সরাসরি শ্রেণি থেকে ডাকা যায় এবং তার প্রথম পরামিতি হিসাবে শ্রেণীর রেফারেন্স গ্রহণ করে।

# calling directly from the class is fine,
# a reference to the class is passed implicitly
a = A.alternate_constructor()
b = B.alternate_constructor()

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

super(B, cls_or_subcls)

3- কলটি এর super(B, cls)পরিসীমাতে সমাধান হয় Aএবং এটি প্রয়োগ করে cls। যেহেতু alternate_constructor()একটি শ্রেণিবদ্ধ, কলটি স্পষ্টভাবে এর সংস্করণের সংস্করণটির প্রথম যুক্তি হিসাবে super(B, cls).alternate_constructor(...)একটি রেফারেন্স পাস করবে passclsAalternate_constructor()

super(B, cls).alternate_constructor()

4- ব্যবহার না করেই এটি করার জন্য super()আপনাকে আনবাউন্ড সংস্করণটির A.alternate_constructor()(যেমন ফাংশনের সুস্পষ্ট সংস্করণ) রেফারেন্স পেতে হবে । কেবল এটি করা কার্যকর হবে না:

class B(A):
    @classmethod
    def alternate_constructor(cls, *a, **kw):
        # ...
        # whatever you want to specialize or override here
        # ...

        print "B.alternate_constructor called"
        return A.alternate_constructor(cls, *a, **kw)

উপরের কাজ করবে না কারণ A.alternate_constructor()পদ্ধতিটি Aতার প্রথম যুক্তি হিসাবে একটি অন্তর্নিহিত রেফারেন্স নেয় । এখানে clsপাস করা এটি দ্বিতীয় যুক্তি হবে।

class B(A):
    @classmethod
    def alternate_constructor(cls, *a, **kw):
        # ...
        # whatever you want to specialize or override here
        # ...

        print "B.alternate_constructor called"
        # first we get a reference to the unbound 
        # `A.alternate_constructor` function 
        unbound_func = A.alternate_constructor.im_func
        # now we call it and pass our own `cls` as its first argument
        return unbound_func(cls, *a, **kw)

6

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

jackক্লাস থেকে এমন একটি উদাহরণ তৈরি হয়েছে তা কল্পনা করুন Jack, যার উত্তরাধিকার শৃঙ্খলা রয়েছে যা ছবিতে সবুজ দেখায়। কল করা হচ্ছে:

super(Jack, jack).method(...)

( jackনির্দিষ্ট ক্রমে এর উত্তরাধিকারী গাছ ) এর এমআরও (মেথড রেজোলিউশন অর্ডার) ব্যবহার করবে এবং সেখান থেকে অনুসন্ধান শুরু করবে Jack। কেন একজন প্যারেন্ট ক্লাস সরবরাহ করতে পারেন? ঠিক আছে যদি আমরা উদাহরণ থেকে অনুসন্ধান শুরু jackকরি তবে এটি উদাহরণ পদ্ধতিটি আবিষ্কার করবে, পুরো বিষয়টিটি তার পিতামাতার পদ্ধতিটি অনুসন্ধান করা।

যদি কেউ সুপারকে তর্ক সরবরাহ না করে তবে প্রথম আর্গুমেন্টের মতো এটি পাস করার শ্রেণি selfএবং দ্বিতীয় আর্গুমেন্টটি পাস হয় self। পাইথন 3 এ এগুলি আপনার জন্য স্বয়ংক্রিয়ভাবে গণনা করা হয়।

তবে বলুন যে আমরা প্রবেশের Jackপরিবর্তে, এর পদ্ধতিটি ব্যবহার করতে চাই না Jack, আমরা Jenসেই পদ্ধতির উপরের দিকে অনুসন্ধান শুরু করতে পেরিয়ে যেতে পারি Jen

এটি একবারে একটি স্তর অনুসন্ধান করে (প্রস্থ গভীরতা নয়), উদাহরণস্বরূপ Adamএবং যদি Sueউভয়েরই প্রয়োজনীয় পদ্ধতি থাকে তবে সেটির একটিটি Sueপ্রথমে পাওয়া যাবে।

যদি Cainএবং Sueউভয়েরই প্রয়োজনীয় পদ্ধতি ছিল তবে Cainএর পদ্ধতিটি প্রথমে কল করা হবে। এটি কোডের সাথে মিলে যায়:

Class Jen(Cain, Sue):

এমআরও বাম থেকে ডানে।


2

কিছু দুর্দান্ত উত্তর এখানে, তবে super()শ্রেণিবিন্যাসের বিভিন্ন শ্রেণীর বিভিন্ন স্বাক্ষর রয়েছে এমন ক্ষেত্রে তারা কীভাবে ব্যবহার করবেন তা মোকাবেলা করবেন না ... বিশেষত ক্ষেত্রে__init__

এই অংশটির উত্তর দিতে এবং কার্যকরভাবে ব্যবহার করতে সক্ষম হওয়ার জন্য super()আমি আমার উত্তরটি সুপার () পড়ার এবং সমবায় পদ্ধতির স্বাক্ষর পরিবর্তনের পরামর্শ দিচ্ছি ।

এই দৃশ্যের কেবল সমাধান এখানে:

  1. আপনার শ্রেণিবিন্যাসের শীর্ষ স্তরের শ্রেণীর অবশ্যই একটি কাস্টম শ্রেণীর উত্তরাধিকার হতে হবে SuperObject:
  2. ক্লাসগুলি যদি পৃথক পৃথক যুক্তি নিতে পারে, আপনি সর্বদা সুপার ফাংশনে প্রাপ্ত সমস্ত যুক্তি কীওয়ার্ড আর্গুমেন্ট হিসাবে পাস করুন এবং সর্বদা গ্রহণ করুন **kwargs
class SuperObject:        
    def __init__(self, **kwargs):
        print('SuperObject')
        mro = type(self).__mro__
        assert mro[-1] is object
        if mro[-2] is not SuperObject:
            raise TypeError(
                'all top-level classes in this hierarchy must inherit from SuperObject',
                'the last class in the MRO should be SuperObject',
                f'mro={[cls.__name__ for cls in mro]}'
            )

        # super().__init__ is guaranteed to be object.__init__        
        init = super().__init__
        init()

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

class A(SuperObject):
    def __init__(self, **kwargs):
        print("A")
        super(A, self).__init__(**kwargs)

class B(SuperObject):
    def __init__(self, **kwargs):
        print("B")
        super(B, self).__init__(**kwargs)

class C(A):
    def __init__(self, age, **kwargs):
        print("C",f"age={age}")
        super(C, self).__init__(age=age, **kwargs)

class D(B):
    def __init__(self, name, **kwargs):
        print("D", f"name={name}")
        super(D, self).__init__(name=name, **kwargs)

class E(C,D):
    def __init__(self, name, age, *args, **kwargs):
        print( "E", f"name={name}", f"age={age}")
        super(E, self).__init__(name=name, age=age, *args, **kwargs)

E(name='python', age=28)

আউটপুট:

E name=python age=28
C age=28
A
D name=python
B
SuperObject

0
class Child(SomeBaseClass):
    def __init__(self):
        SomeBaseClass.__init__(self)

এটি মোটামুটি বোঝা সহজ।

class Child(SomeBaseClass):
    def __init__(self):
        super(Child, self).__init__()

ঠিক আছে, আপনি যদি এখন ব্যবহার করেন super(Child,self)?

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

উত্তীর্ণ হয়ে Child, self, উদাহরণের superএমআরও অনুসন্ধান করে এবং selfসন্তানের পরবর্তী প্রক্সি অবজেক্টটি ফিরিয়ে দিন, এক্ষেত্রে এটি সামারবেসক্লাস, এই অবজেক্টটি __init__সামারবেস ক্লাসের পদ্ধতিটি আহ্বান করে । অন্য কথায়, যদি এটি হয় super(SomeBaseClass,self)তবে প্রক্সি অবজেক্টটি superফিরে আসবেobject

বহু উত্তরাধিকারের জন্য, এমআরওতে অনেকগুলি শ্রেণি থাকতে পারে, তাই মূলত superআপনাকে সিদ্ধান্ত নিতে দেয় যে আপনি এমআরওতে কোথায় অনুসন্ধান শুরু করতে চান।


0

নিম্নলিখিত কোড বিবেচনা করুন:

class X():
    def __init__(self):
        print("X")

class Y(X):
    def __init__(self):
        # X.__init__(self)
        super(Y, self).__init__()
        print("Y")

class P(X):
    def __init__(self):
        super(P, self).__init__()
        print("P")

class Q(Y, P):
    def __init__(self):
        super(Q, self).__init__()
        print("Q")

Q()

যদি পরিবর্তনের কন্সট্রাকটর Yকরতে X.__init__, আপনি পেতে হবে:

X
Y
Q

তবে ব্যবহার করে super(Y, self).__init__(), আপনি পাবেন:

X
P
Y
Q

এবং Pঅথবা Qএমন কোনও অন্য ফাইল থেকেও জড়িত থাকতে পারে যা আপনি কখন লিখবেন Xএবং কখন জানেন না Y। সুতরাং, মূলত, আপনি super(Child, self)যখন লিখবেন তখন কী কী রেফারেন্স দেবে তা আপনি জানেন না class Y(X), এমনকি ওয়াইয়ের স্বাক্ষরও এত সহজ Y(X)। সে কারণেই সুপার আরও ভাল পছন্দ হতে পারে।

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