উদাহরণ স্তরে একটি পদ্ধতি ওভাররাইড করুন


87

পাইথনে কি কোনও স্তরের উদাহরণ স্তরে কোনও শ্রেণি পদ্ধতিকে ওভাররাইড করার উপায় আছে? উদাহরণ স্বরূপ:

class Dog:
    def bark(self):
        print "WOOF"

boby = Dog()
boby.bark() # WOOF
# METHOD OVERRIDE
boby.bark() # WoOoOoF!!

উত্তর:


10

প্রদর্শিত হিসাবে এটি করবেন না দয়া করে। শ্রেণি থেকে আলাদা হওয়ার জন্য আপনি কোনও উদাহরণটি বানরক্ষেত্রের সময় আপনার কোডটি অপঠনযোগ্য হয়ে যায়।

আপনি বানরপ্যাচড কোডটি ডিবাগ করতে পারবেন না।

আপনি যখন কোনও বাগ খুঁজে পান bobyএবং print type(boby)আপনি দেখতে পাবেন যে (ক) এটি একটি কুকুর, তবে (খ) কিছু অস্পষ্ট কারণে এটি সঠিকভাবে ছাঁটাই না। এটি দুঃস্বপ্ন। এটি করবেন না.

পরিবর্তে এটি করুন।

class Dog:
    def bark(self):
        print "WOOF"

class BobyDog( Dog ):
    def bark( self ):
        print "WoOoOoF!!"

otherDog= Dog()
otherDog.bark() # WOOF

boby = BobyDog()
boby.bark() # WoOoOoF!!

9
@ অ্যারিভেরো: আমি ভেবেছিলাম "দয়া করে এটি প্রদর্শিত হিসাবে করবেন না" পুরোপুরি পরিষ্কার হয়ে গেছে। আপনি আরও কী কী বা ভিন্ন শব্দ দেখতে চান এটি আরও পরিষ্কার করে দেখতে যে এটি জিজ্ঞাসা করা প্রশ্নের উত্তর দিচ্ছে না, তবে কেন এটি একটি খারাপ ধারণা?
এস্লট লট

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

13
@ আরিভেরো: এটা আমার প্রশ্নের উত্তর দেয়নি।
এস .লট

9
@ এস.লট আমার মনে হয় আপনার সত্যিকারের উত্তরের সাথে "দেখানো" লিঙ্ক করা উচিত, এটি গ্রহণযোগ্য উত্তর হবার সাথে আমার আসলেই সমস্যা নেই তবে কিছু পরিস্থিতিতে এবং আমার স্কিম পড়া থেকে আপনাকে বানর প্যাচ দেওয়ার দরকারের কারণ রয়েছে are আপনি আলাদা আলাদা উত্তর না দিয়ে আপনি কী প্রদর্শন করছেন তা বোঝাতে আমি "প্রদর্শিত হিসাবে" নিয়েছি।
ড্যানিয়েল চ্যাটফিল্ড

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

169

হ্যাঁ এটা সম্ভব:

class Dog:
    def bark(self):
        print "Woof"

def new_bark(self):
    print "Woof Woof"

foo = Dog()

funcType = type(Dog.bark)

# "Woof"
foo.bark()

# replace bark with new_bark for this object only
foo.bark = funcType(new_bark, foo, Dog)

foo.bark()
# "Woof Woof"

4
একটি ছোট মন্তব্য, যখন আপনি ফানটাইপ করেন (নতুন_বার্ক, ফু, কুকুর) এর নামটি যোগ করে == ছাল এবং দৃষ্টান্ত পদ্ধতি কুকুর.নু_বার্ক foo __। ডিক__ ঠিক? সুতরাং, যখন আপনি এটি পুনরায় কল করবেন উদাহরণস্বরূপ অভিধানে এটি প্রথম অনুসন্ধান এবং তার জন্য কল করুন
জেমস

11
funcTypeএটি কী করে বিশেষত কী করে এবং কেন এটি প্রয়োজনীয় তা ব্যাখ্যা করুন ।
আলেকসান্দ্র ডাবিনস্কি

4
আমি মনে করি এর পরিবর্তে funcType = types.MethodType(আমদানির পরে types) ব্যবহার করে এটিকে কিছুটা সহজ এবং আরও স্পষ্ট করা যায় funcType = type(Dog.bark)
ইলিয়াস জামারিয়া

13
আমি অনুমান করি এটি পাইথন 3 এর সাথে কাজ করে না I আমি একটি "TypeError: ফাংশন () যুক্তি 1 কোড হতে হবে, ফাংশন নয়" ত্রুটি। পাইথন 3 এর জন্য কোনও পরামর্শ?
Sait

4
আপনি __get__এটিকে উদাহরণের সাথে আবদ্ধ করতে ফাংশনটিতে কল করতে পারেন ।
ম্যাড পদার্থবিদ

41

আপনাকে মডিউলটি থেকে মেথডটাইপ ব্যবহার করতে হবে types। এর উদ্দেশ্য MethodTypeহ'ল উদাহরণ স্তরের পদ্ধতিগুলি ওভাররাইট করা (যাতে এটি selfওভাররাইট পদ্ধতিতে উপলব্ধ হতে পারে)।

নীচের উদাহরণ দেখুন।

import types

class Dog:
    def bark(self):
        print "WOOF"

boby = Dog()
boby.bark() # WOOF

def _bark(self):
    print "WoOoOoF!!"

boby.bark = types.MethodType(_bark, boby)

boby.bark() # WoOoOoF!!

32

@ কোডেলজিকের দুর্দান্ত উত্তরটি ব্যাখ্যা করতে, আমি আরও স্পষ্ট পদ্ধতির প্রস্তাব দিই। এটি একই কৌশলটি যা .অপারেটর কোনও শ্রেণি পদ্ধতিতে বাঁধতে সম্পূর্ণরূপে যায় যখন আপনি এটিকে উদাহরণ বৈশিষ্ট্য হিসাবে অ্যাক্সেস করেন তবে আপনার পদ্ধতিটি আসলে কোনও শ্রেণীর বাইরে সংজ্ঞায়িত একটি ফাংশন হবে।

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

ক্লাস কুকুর:
    ডিএফ বার্ক (স্ব):
        "ওওফ" মুদ্রণ করুন

Def new_bark (স্ব):
    "ওয়ুফ ওয়ুফ" মুদ্রণ

foo = কুকুর ()

# "ওওফ"
foo.bark ()

# কেবল এই বস্তুর জন্য বার্ককে নতুন_বার্কের সাথে প্রতিস্থাপন করুন
foo.bark = নতুন_বার্ক .__ পান __ (ফু, কুকুর)

foo.bark ()
# "বুনন বুনন"

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

এটি যেভাবে কাজ করে তার একমাত্র কারণ, এই উদাহরণটি অ-ডেটা বিবরণকারীকে ওভাররাইড করে । ডেটা বর্ণনাকারীদের __set__পদ্ধতি রয়েছে, কোন পদ্ধতিগুলি (সৌভাগ্যক্রমে আপনার জন্য) তা নয়। ক্লাসে ডেটা বর্ণনাকারীরা আসলে কোনও উদাহরণের বৈশিষ্ট্যের তুলনায় অগ্রাধিকার নেন। এজন্য আপনি কোনও সম্পত্তি বরাদ্দ করতে পারেন: __set__আপনি যখন কোনও অ্যাসাইনমেন্ট করার চেষ্টা করবেন তখন তাদের পদ্ধতিটি চাওয়া হয়। আমি ব্যক্তিগতভাবে এটিকে আরও একধাপ এগিয়ে নিয়ে যেতে চাইছি এবং উদাহরণের অন্তর্নিহিত গুণাবলীর প্রকৃত মানটি আড়াল করতে চাই __dict__, যেখানে সম্পত্তিটি এর ছায়া গোছায় তাই এটি স্বাভাবিক উপায়ে অ্যাক্সেসযোগ্য।

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


4
এটি গ্রহণযোগ্য উত্তর হওয়া উচিত: এটি পরিষ্কার এবং পাইথন 3 এ কাজ করে
ব্লেন্ডারবেন্ডার

@ ব্লেন্ডারবেন্ডার আমি আপনার সমর্থনের প্রশংসা করি
ম্যাড পদার্থবিদ

এই উত্তরটি এবং @ হর্ষাল ধুমাই থেকে আপনার উত্তরটির মধ্যে পার্থক্য কী?
1313e

4
@ 1313। কার্যত, খুব বেশি পার্থক্য থাকা উচিত নয়। আমি সন্দেহ করি যে উপরের উত্তরটি কলযোগ্যগুলির বিস্তৃত পরিসরকে ইনপুট হিসাবে গ্রহণ করতে পারে, তবে ডকগুলি না পড়ে এবং চারপাশে খেলা না করে, আমি নিশ্চিত নই।
ম্যাড পদার্থবিজ্ঞানী

পাইথন এটির জন্য 2 ডক্স: ডকস.পিথন.আর. / 2 / হোতো / ডিজিস্কোর.ইচটিএমএল । সুতরাং তাত্ত্বিকভাবে এটি @ হর্ষাল ধুমাইয়ের উত্তরের মতো।
রক্যালাইট

26
class Dog:
    def bark(self):
        print "WOOF"

boby = Dog()
boby.bark() # WOOF

# METHOD OVERRIDE
def new_bark():
    print "WoOoOoF!!"
boby.bark = new_bark

boby.bark() # WoOoOoF!!

bobyআপনার প্রয়োজন হলে আপনি ফাংশনের অভ্যন্তরে পরিবর্তনশীলটি ব্যবহার করতে পারেন । যেহেতু আপনি কেবলমাত্র এই এক উদাহরণের জন্য পদ্ধতিটিকে ওভাররাইড করছেন তাই এই উপায়টি সহজ এবং ব্যবহারের মতো ঠিক একই প্রভাব ফেলে self


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

4
কেন এটি গৃহীত উত্তর নয় তা আমি বুঝতে পারি না। একে বলা হয় patchingএবং এটি করার সঠিক উপায় এটি (যেমন boby = Dog()এবং boby.bark = new_bark)। এটি নিয়ন্ত্রণের জন্য ইউনিট পরীক্ষায় অবিশ্বাস্যভাবে কার্যকর । আরও ব্যাখ্যার জন্য দেখুন tryolabs.com/blog/2013/07/05/run-time-method-patching-python (উদাহরণ) - না আমি লিঙ্কযুক্ত সাইট বা লেখকের সাথে অনুমোদিত নই।
জিওফ

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

3

যেহেতু functools.partialএখানে কেউ উল্লেখ করছে না:

from functools import partial

class Dog:
    name = "aaa"
    def bark(self):
        print("WOOF")

boby = Dog()
boby.bark() # WOOF

def _bark(self):
    print("WoOoOoF!!")

boby.bark = partial(_bark, boby)
boby.bark() # WoOoOoF!!

1

যেহেতু ফাংশন পাইথনে প্রথম শ্রেণীর অবজেক্ট হয় আপনি নিজের শ্রেণি অবজেক্টটি শুরু করার সময় সেগুলি পাস করতে পারেন বা প্রদত্ত শ্রেণীর উদাহরণের জন্য যে কোনও সময় ওভাররাইড করতে পারেন:

class Dog:
    def __init__(self,  barkmethod=None):
        self.bark=self.barkp
        if barkmethod:
           self.bark=barkmethod
    def barkp(self):
        print "woof"

d=Dog()
print "calling original bark"
d.bark()

def barknew():
    print "wooOOOoof"

d1=Dog(barknew)
print "calling the new bark"
d1.bark()

def barknew1():
    print "nowoof"

d1.bark=barknew1
print "calling another new"
d1.bark()

এবং ফলাফল হয়

calling original bark
woof
calling the new bark
wooOOOoof
calling another new
nowoof

-4

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

class Dog:
    def __init__(self, barkmethod=None):
        self.bark=self.barkp
        if barkmethod:
           self.bark=barkmethod
    def barkp(self):
        """original bark"""
        print "woof"

d=Dog()
print "calling original bark"
d.bark()
print "that was %s\n" % d.bark.__doc__

def barknew():
    """a new type of bark"""
    print "wooOOOoof"

d1=Dog(barknew)
print "calling the new bark"
d1.bark()
print "that was %s\n" % d1.bark.__doc__

def barknew1():
    """another type of new bark"""
    print "nowoof"

d1.bark=barknew1
print "another new"
d1.bark()
print "that was %s\n" % d1.bark.__doc__

এবং আউটপুটটি হ'ল:

calling original bark
woof
that was original bark

calling the new bark
wooOOOoof
that was a new type of bark

another new
nowoof
that was another type of new bark

4
যদি এটি "পরিচালিত" হওয়া দরকার, তবে - আমার কাছে - কিছু ভুল। বিশেষত যখন প্রথম শ্রেণির ভাষার বৈশিষ্ট্য থাকে যা ইতিমধ্যে কাজ করে does
এস.লোট

-4

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


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