'উত্সাহী নোটলিপ্লেমেন্টড এরির' কখন ব্যবহার করবেন?


102

ক্লাসটি সঠিকভাবে প্রয়োগ করতে নিজেকে এবং আপনার দলকে মনে করিয়ে দেওয়া কি? আমি পুরোপুরি এর মতো বিমূর্ত শ্রেণির ব্যবহার পাই না:

class RectangularRoom(object):
    def __init__(self, width, height):
        raise NotImplementedError

    def cleanTileAtPosition(self, pos):
        raise NotImplementedError

    def isTileCleaned(self, m, n):
        raise NotImplementedError

4
ক্রস-সাইট
ডুপ

4
আমি বলব: এটি যখন "সর্বনিম্ন বিস্ময়ের মূলনীতিটি" সন্তুষ্ট করে ।
এমসিফার্ট

4
এটি একটি দরকারী প্রশ্ন, যেমনটি ডক্স অনুসারে উরিলের স্পষ্ট উত্তর এবং জেরুমের দ্বারা অ্যাবস্ট্রাক্ট বেস ক্লাস সম্পর্কিত মান-যুক্ত উত্তর দ্বারা প্রমাণিত।
দাভোস

এটি বোঝাতেও ব্যবহার করা যেতে পারে যে উদ্ভূত শ্রেণি উদ্দেশ্যমূলকভাবে কোনও বেস শ্রেণীর বিমূর্ত পদ্ধতি বাস্তবায়িত করে না, যা দ্বি-মুখী সুরক্ষা সরবরাহ করতে পারে। নীচে দেখুন
pfabri

উত্তর:


78

ডকুমেন্টেশনে যেমন [ডক্স] বলা হয়েছে ,

ব্যবহারকারীর সংজ্ঞায়িত বেস ক্লাসগুলিতে, বিমূর্ত পদ্ধতিগুলি যখন এই পদ্ধতিটিকে ওভাররাইড করার জন্য উদ্ভূত শ্রেণীর প্রয়োজন হয় বা ক্লাসটি বিকাশ করা হয় তখন প্রকৃত বাস্তবায়নটি যুক্ত করার দরকার রয়েছে তা বোঝাতে হবে।

মনে রাখবেন যে মূলত উল্লিখিত ব্যবহারের ক্ষেত্রে এই ত্রুটিটি উত্তরাধিকার সূত্রে প্রাপ্ত শ্রেণীর উপর প্রয়োগ করা উচিত এমন বিমূর্ত পদ্ধতিগুলির ইঙ্গিত, আপনি চিহ্নিত করতে চাইলে আপনি যেভাবে এটি ব্যবহার করতে পারেন TODO


6
বিমূর্ত পদ্ধতিগুলির জন্য, আমি ব্যবহার করতে পছন্দ করি abc( আমার উত্তর দেখুন )।
জারুমে

@ জুরমে কেন দুটোই ব্যবহার করবেন না? সঙ্গে সজ্জিত করুন abstractmethodএবং এটি বাড়াতে দিন NotImplementedError। এটি উত্পন্ন ক্লাসগুলির super().method()বাস্তবায়নে নিষেধ করে method
টিম্বেজ

@ টিমজেগ আমি সুপার ()। পদ্ধতি () নিষিদ্ধ করার প্রয়োজন বোধ করি না।
জেরুমে

49

যেমন ইউরিয়েল বলেছেন , এটি একটি বিমূর্ত শ্রেণিতে এমন একটি পদ্ধতির জন্য যা শিশু শ্রেণিতে প্রয়োগ করা উচিত তবে এটি একটি টোডোও নির্দেশ করতে ব্যবহার করা যেতে পারে।

প্রথম ব্যবহারের ক্ষেত্রে বিকল্প রয়েছে: অ্যাবস্ট্রাক্ট বেস ক্লাস । এগুলি বিমূর্ত ক্লাস তৈরি করতে সহায়তা করে।

এখানে পাইথন 3 উদাহরণ রয়েছে:

class C(abc.ABC):
    @abstractmethod
    def my_abstract_method(self, ...):
        ...

ইনস্ট্যান্ট করার সময় C, আপনি একটি ত্রুটি পাবেন কারণ my_abstract_methodএটি বিমূর্ত। আপনার এটি একটি শিশু শ্রেণিতে প্রয়োগ করা দরকার।

TypeError: Can't instantiate abstract class C with abstract methods my_abstract_method

সাবক্লাস Cএবং বাস্তবায়ন my_abstract_method

class D(C):
    def my_abstract_method(self, ...):
        ...

এখন আপনি তাত্ক্ষণিক করতে পারেন D

C.my_abstract_methodখালি থাকতে হবে না। এটি Dব্যবহার করে বলা যেতে পারে super()

এর ওপরে একটি সুবিধা NotImplementedErrorহ'ল আপনি Exceptionইনস্ট্যান্টেশন সময়ে একটি স্পষ্ট পাবেন , পদ্ধতি কল সময়ে নয়।


4
পাইথন ২.6+ তেও উপলব্ধ। from abc import ABCMeta, abstractmethodআপনার এবিসিকে কেবল এবং সংজ্ঞায়িত করুন __metaclass__ = ABCMeta। দস্তাবেজ: docs.python.org/2/library/abc.html
বল্টজম্যান

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

26

পরিবর্তে এটি ছিল কিনা বিবেচনা করুন:

class RectangularRoom(object):
    def __init__(self, width, height):
        pass

    def cleanTileAtPosition(self, pos):
        pass

    def isTileCleaned(self, m, n):
        pass

এবং আপনি সাবক্লাস এবং এটি কীভাবে isTileCleaned()বা সম্ভবত সম্ভবত এটি টাইপ করুন তা বলতে ভুলে যান isTileCLeaned()। তারপরে আপনার কোডে, আপনি Noneযখন কল করবেন তখন আপনি একটি পেয়ে যাবেন ।

  • আপনি যে ওভাররাইড ফাংশনটি চেয়েছিলেন তা কি পাবেন? অবশ্যই না.
  • কি Noneবৈধ আউটপুট? কে জানে.
  • এটা কি উদ্দেশ্যপূর্ণ আচরণ? প্রায় অবশ্যই না।
  • আপনি একটি ত্রুটি পাবেন? এটা নির্ভর করে.

raise NotImplmentedError বাহিনী আপনি এটা বাস্তবায়ন, যেমন হবে যখন আপনি এটি চালানোর জন্য যতক্ষণ না আপনি তা করতে চেষ্টা ব্যতিক্রম নিক্ষেপ করা। এটি প্রচুর নীরব ত্রুটিগুলি সরিয়ে দেয়। এটি একটি খালি ব্যতীত প্রায় কখনই একটি ভাল ধারণা না কেন এটি অনুরূপ : কারণ লোকেরা ভুল করে এবং এটি নিশ্চিত করে যে তারা গালিচায় নিচে ছড়িয়ে পড়ে না।

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


11

একটি শিশু- শৃঙ্খলাবদ্ধ বেস ক্লাস পদ্ধতিতে শিশু পদ্ধতির raise NotImplementedError() অভ্যন্তরেও একটি করতে পারে @abstractmethod


পরিমাপ মডিউল (শারীরিক ডিভাইস) এর পরিবারের জন্য একটি নিয়ন্ত্রণ স্ক্রিপ্ট লেখার কল্পনা করুন। প্রতিটি মডিউলটির কার্যকারিতা সংক্ষিপ্তভাবে সংজ্ঞায়িত করা হয়, কেবল একটি ডেডিকেটেড ফাংশন বাস্তবায়ন করে: একটি রিলে অ্যারের হতে পারে, অন্যটি একটি মাল্টি-চ্যানেল ডিএসি বা এডিসি, অন্য একটি এমমিটার ইত্যাদি could

ব্যবহৃত নিম্ন-স্তরের কমান্ডগুলির বেশিরভাগ মডিউলগুলির মধ্যে ভাগ করা হবে উদাহরণস্বরূপ তাদের আইডি নম্বরগুলি পড়তে বা তাদের কাছে একটি আদেশ প্রেরণ করার জন্য। এই মুহুর্তে আমাদের কী আছে তা দেখুন:

বেস ক্লাস

from abc import ABC, abstractmethod  #< we'll make use of these later

class Generic(ABC):
    ''' Base class for all measurement modules. '''

    # Shared functions
    def __init__(self):
        # do what you must...

    def _read_ID(self):
        # same for all the modules

    def _send_command(self, value):
        # same for all the modules

ভাগ করা ক্রিয়া

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

  • get(channel)

  • রিলে: রিলে অন ​​/ অফ স্ট্যাটাস পানchannel

  • ড্যাক: পেতে আউটপুট উপর ভোল্টেজchannel

  • এডিসি: পেতে ইনপুট উপর ভোল্টেজchannel

  • enable(channel)

  • রিলে: রিলে ব্যবহার সক্ষম করুনchannel

  • ড্যাক: চালু আউটপুট চ্যানেলের ব্যবহার সক্ষম করুনchannel

  • এডিসি: ইনপুট চ্যানেলটি চালু করতে সক্ষম করুনchannel

  • set(channel)

  • রিলে: রিলে channelচালু / বন্ধ করুন

  • ড্যাক: সেট আউটপুট উপর ভোল্টেজchannel

  • এডিসি: হুম ... যৌক্তিক কিছু মনে আসে না।


ভাগ করা ক্রিয়াগুলি কার্যকর ক্রিয়া হয়ে ওঠে

আমি যুক্তি দিয়েছি যে উপরোক্ত ক্রিয়াগুলি মডিউলগুলিতে ভাগ করার জন্য একটি শক্তিশালী কেস রয়েছে কারণ আমরা দেখেছি যে তাদের প্রতিটিটির প্রতিটির অর্থ স্পষ্ট। আমি আমার বেস ক্লাসটি Genericএভাবে লিখতে থাকি :

class Generic(ABC):  # ...continued
    
    @abstractmethod
    def get(self, channel):
        pass

    @abstractmethod
    def enable(self, channel):
        pass

    @abstractmethod
    def set(self, channel):
        pass

সাবক্ল্যাস

আমরা এখন জানি যে আমাদের সাবক্লাসগুলি সমস্তকে এই পদ্ধতিগুলি সংজ্ঞায়িত করতে হবে। এটি ADC মডিউলটির জন্য দেখতে কেমন তা দেখতে দিন:

class ADC(Generic):

    def __init__(self):
        super().__init__()  #< applies to all modules
        # more init code specific to the ADC module
    
    def get(self, channel):
        # returns the input voltage measured on the given 'channel'

    def enable(self, channel):
        # enables accessing the given 'channel'

আপনি এখন ভাবছেন:

তবে এটি এডিসি মডিউলের জন্য কাজ করবে না setকারণ সেখানে এটি কোনও তাত্পর্যপূর্ণ নয় কারণ আমরা কেবল এটি উপরে দেখেছি!

আপনি ঠিক বলেছেন: বাস্তবায়ন setনা করা কোনও বিকল্প নয় কারণ পাইথন তারপরে নীচে ত্রুটিটি ছড়িয়ে দেবে যখন আপনি আপনার এডিসি অবজেক্টটি ইনস্ট্যান্ট করার চেষ্টা করেছিলেন।

TypeError: Can't instantiate abstract class 'ADC' with abstract methods 'set'

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

NotImplementedError the Rescue

এডিসি ক্লাস এভাবে শেষ করে:

class ADC(Generic): # ...continued

    def set(self, channel):
        raise NotImplementedError("Can't use 'set' on an ADC!")

আপনি একবারে তিনটি খুব ভাল কাজ করছেন:

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

-1

আপনি @propertyডেকরেটার ব্যবহার করতে চান ,

>>> class Foo():
...     @property
...     def todo(self):
...             raise NotImplementedError("To be implemented")
... 
>>> f = Foo()
>>> f.todo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in todo
NotImplementedError: To be implemented

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