পাইথন 3.x এর দুর্দান্ত () জাদু কেন?


159

পাইথন ৩.x এ super()যুক্তি ছাড়াই কল করা যেতে পারে:

class A(object):
    def x(self):
         print("Hey now")

class B(A):
    def x(self):
        super().x()
>>> B().x()
Hey now

এই কাজটি করার জন্য, কিছু সংকলন-সময় যাদু করা হয়, যার একটি ফলস্বরূপ নিম্নলিখিত কোডটি (যা পুনরায় প্রত্যাবর্তন superকরে super_) ব্যর্থ হয়:

super_ = super

class A(object):
    def x(self):
        print("No flipping")

class B(A):
    def x(self):
        super_().x()
>>> B().x()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in x
RuntimeError: super(): __class__ cell not found

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

... এবং, একটি পার্শ্ব প্রশ্ন হিসাবে: ফাংশন, পদ্ধতি ইত্যাদির পাইথনগুলিতে অন্য কোনও উদাহরণ রয়েছে যা এগুলিকে আলাদা নামে পুনর্নির্মাণের মাধ্যমে ভেঙে ফেলা যায়?


6
আমি আরমিন ব্যাখ্যা না এই জানাবো এক । এটি আরও একটি ভাল পোস্ট
গেমস ব্রেনিয়াক

সম্পর্কিত: stackoverflow.com/q/36993577/674039
wim

উত্তর:


216

super()ডিআরওয়াই (নিজেকে পুনরাবৃত্তি করবেন না) নীতির লঙ্ঘন এড়াতে নতুন যাদু আচরণ যুক্ত করা হয়েছিল, পিইপি 3135 দেখুন । ক্লাসটিকে বিশ্বব্যাপী হিসাবে উল্লেখ করে স্পষ্টরূপে নামকরণ করা আপনার super()নিজের সাথে আবিষ্কার করা একই পুনরায় রিমন্ডিং ইস্যুতে ঝুঁকিপূর্ণ :

class Foo(Bar):
    def baz(self):
        return super(Foo, self).baz() + 42

Spam = Foo
Foo = something_else()

Spam().baz()  # liable to blow up

ক্লাস সাজসজ্জার ব্যবহারে এটি একই প্রযোজ্য যেখানে সাজসজ্জা একটি নতুন অবজেক্ট ফেরত দেয় যা শ্রেণীর নামটি পুনরায় প্রত্যাবর্তন করে:

@class_decorator_returning_new_class
class Foo(Bar):
    def baz(self):
        # Now `Foo` is a *different class*
        return super(Foo, self).baz() + 42

ম্যাজিক super() __class__সেল আপনাকে মূল শ্রেণীর অবজেক্টে অ্যাক্সেস দিয়ে সুন্দরভাবে এই সমস্যাগুলিকে পাশ কাটিয়ে দেয়।

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

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

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

সুতরাং, শেষ পর্যন্ত, নিজেই গুইডো ঘোষণা করেছিলেন যে কোনও superকীওয়ার্ড ব্যবহার করা সঠিক মনে হচ্ছে না এবং একটি যাদু __class__ঘর সরবরাহ করা একটি গ্রহণযোগ্য আপস ছিল।

আমি সম্মত হচ্ছি যে বাস্তবায়নের যাদু, অন্তর্নিহিত আচরণ কিছুটা অবাক করা হলেও super()ভাষাটির মধ্যে সবচেয়ে বেশি ভুল-প্রয়োগকৃত কাজ। ইন্টারনেটে পাওয়া সমস্ত অপ্রয়োগিত super(type(self), self)বা super(self.__class__, self)অনুরোধগুলির দিকে একবার নজর দিন ; যদি সেই কোডটির কোনওটি যদি কখনও উদ্ভূত শ্রেণীর কাছ থেকে কল করা হয় তবে আপনি অসীম পুনরাবৃত্তি ব্যতিক্রম সহ শেষ করতে চান । অন্ততপক্ষে সরলীকৃত এ super()কল, আর্গুমেন্ট ছাড়াই এড়াতে যে সমস্যা।

নাম পরিবর্তন হিসাবে super_; শুধু রেফারেন্স __class__আপনার পদ্ধতিতে পাশাপাশি এবং এটি আবার কাজ করব। আপনি যদি আপনার পদ্ধতির নাম super বা __class__ নাম উল্লেখ করেন তবে ঘরটি তৈরি করা হয়েছে :

>>> super_ = super
>>> class A(object):
...     def x(self):
...         print("No flipping")
... 
>>> class B(A):
...     def x(self):
...         __class__  # just referencing it is enough
...         super_().x()
... 
>>> B().x()
No flipping

1
ভাল লেখার আপ। এটি এখনও কাদা হিসাবে পরিষ্কার। আপনি বলছেন যে সুপার () একটি স্বয়ংক্রিয়ভাবে ইনস্ট্যান্টেড ফাংশনের মতো def super(of_class=magic __class__)এর মতো self.super(); def super(self): return self.__class__?
চার্লস মেরিয়াম

17
@ চারলেস মেরেরিয়াম: এই পোস্টটি super()যুক্তি ছাড়াই কীভাবে কাজ করে তা নিয়ে নয় ; এটি বেশিরভাগ ক্ষেত্রে কেন এটি বিদ্যমান তা নিয়ে আলোচনা করে । super()ক্লাস পদ্ধতিতে, সমান super(ReferenceToClassMethodIsBeingDefinedIn, self), যেখানে ReferenceToClassMethodIsBeingDefinedInসংকলন সময়ে নির্ধারিত হয়, নামটি বন্ধ করার পদ্ধতি হিসাবে সংযুক্ত করা হয় __class__, এবং super()রানটাইমের সময় কলিং ফ্রেম থেকে উভয়ই সন্ধান করে। তবে আসলে আপনার এ সমস্ত জানা দরকার নেই।
মার্টিজন পিটারস

1
@ চারলেস মেরেরিয়াম: তবে স্বয়ংক্রিয়ভাবে ইনস্ট্যানিয়েটেড ফাংশনsuper() হওয়ার খুব কাছে নেই , না।
মার্টিজন পিটারস

1
@ chris.leonard: মূল বাক্যটি হল সেলটি তৈরি করা হয় যদি আপনি সুপার () ব্যবহার __class__করেন বা আপনার পদ্ধতিতে ব্যবহার করেন । আপনি superআপনার ফাংশনে নামটি ব্যবহার করেছেন । সংকলক এটি দেখে এবং বন্ধটি যুক্ত করে __class__
মার্টিজন পিটারস

4
@ অ্যালেক্সা: এটি যথেষ্ট নয়বর্তমান টাইপ type(self)দেয় যা পদ্ধতিটি নির্ধারিত ধরণের মতো নয়। একটি বর্গ তাই পদ্ধতি সঙ্গে চাহিদা , কারণ এটি যেমন subclassed যেতে পারে যা পয়েন্ট, হয় এবং আপনি একটি অসীম লুপ দিতে হবে। আমার উত্তরে আমি যে পোস্টটি লিঙ্ক করেছি তা দেখুন: উত্সযুক্ত ক্লাসে সুপার () কল করার সময় আমি কী নিজের মধ্যে পাস করতে পারি? __ ক্লাস__? Foobazsuper(Foo, self).baz()class Ham(Foo):type(self)Hamsuper(type(self), self).baz()
মার্টিজন পিটারস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.