পাইথন 'ম্যাজিক পদ্ধতি' ব্যবহার করে কেন?


99

আমি সম্প্রতি পাইথনের সাথে ঘুরে বেড়াচ্ছি, এবং একটি বিষয় যা আমি কিছুটা অদ্ভুত খুঁজে পাচ্ছি তা হ'ল 'ম্যাজিক পদ্ধতিগুলি' এর ব্যাপক ব্যবহার, যেমন এর দৈর্ঘ্য উপলব্ধ করা, কোনও বস্তু একটি পদ্ধতি প্রয়োগ করে def __len__(self), এবং তারপরে এটি বলা হয় আপনি লিখুন len(obj)

আমি কেবল ভাবছিলাম যে কেন অবজেক্টগুলি কেবল কোনও len(self)পদ্ধতি সংজ্ঞায়িত করে না এবং এটি সরাসরি কোনও বস্তুর সদস্য হিসাবে ডাকে, যেমন obj.len()? আমি নিশ্চিত যে পাইথন যেভাবে এটি করে তা করার জন্য অবশ্যই যুক্তিসঙ্গত কারণ থাকতে হবে, তবে নবাগত হিসাবে আমি এখনও সেগুলি খুঁজে বের করতে পারি নি।


4
আমি মনে করি সাধারণ কারণ মত ক) ঐতিহাসিক ও খ) কিছু len()বা reversed()অবজেক্টের অনেক ধরনের ক্ষেত্রে প্রযোজ্য, কিন্তু একটি পদ্ধতি যেমন append()শুধুমাত্র ইত্যাদি সিকোয়েন্স ক্ষেত্রে প্রযোজ্য
গ্রান্ট পল

উত্তর:


64

আফাইক, lenএই ক্ষেত্রে বিশেষ এবং এর historicalতিহাসিক শিকড় রয়েছে।

এফএকিউ এর একটি উদ্ধৃতি এখানে :

পাইথন কিছু কার্যকারিতার জন্য যেমন পদ্ধতিগুলি ব্যবহার করে (যেমন list.index ()) তবে অন্যান্য (যেমন লেন (তালিকা)) এর জন্য কাজ করে?

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

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

অন্যান্য "যাদুকরী পদ্ধতি" ( পাইথন ফোকলোরগুলিতে প্রকৃতপক্ষে বিশেষ পদ্ধতি বলা হয় ) প্রচুর অর্থবোধ করে এবং একই রকম কার্যকারিতা অন্যান্য ভাষায়ও বিদ্যমান। এগুলি বেশিরভাগ কোডের জন্য ব্যবহৃত হয় যা বিশেষ সিনট্যাক্স ব্যবহার করা হলে স্পষ্টভাবে কল হয়।

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

  • অতিরিক্ত লোড অপারেটর (সি ++ এবং অন্যদের মধ্যে বিদ্যমান)
  • নির্মাণকারী / ধ্বংসকারী
  • বৈশিষ্ট্য অ্যাক্সেস জন্য হুক
  • রূপক জন্য সরঞ্জাম

এবং তাই ...


4
পাইথন এবং ন্যূনতম বিস্ময়ের মূল নীতিটি পাইথনকে এইভাবে রাখার কিছু সুবিধাগুলির জন্য ভাল পড়া (যদিও আমি ইংরেজদের কাজের প্রয়োজন বলে স্বীকার করি)। বেসিক পয়েন্ট: এটি স্ট্যান্ডার্ড লাইব্রেরিকে এমন এক টন কোড প্রয়োগ করতে দেয় যা খুব, খুব পুনরায় ব্যবহারযোগ্য তবে তবুও ওভার্রাইডেবল হয়ে যায়।
jpmc26

20

পাইথনের জেন থেকে:

অস্পষ্টতার মুখে অনুমান করার প্রলোভনটিকে অস্বীকার করুন।
এটির জন্য একটি - এবং অগ্রাধিকার কেবল একটিই - প্রকাশ্য উপায় থাকতে হবে।

এই কারনে এক - কাস্টম পদ্ধতি, ডেভেলপারদের একটি ভিন্ন পদ্ধতি নাম, মত পছন্দ করে নিন মুক্ত হবে getLength(), length(), getlength()বা সবটা। পাইথন কঠোর নামকরণ কার্যকর করে যাতে সাধারণ ফাংশনটি len()ব্যবহার করা যায়।

সমস্ত ক্রিয়াকলাপ যা বিভিন্ন ধরণের অবজেক্টের জন্য সাধারণ, যাদুর পদ্ধতিতে যেমন __nonzero__, __len__বা করা হয় __repr__। যদিও তারা বেশিরভাগই alচ্ছিক।

অপারেটর ওভারলোডিং ম্যাজিক পদ্ধতিতেও করা হয় (উদাঃ __le__), সুতরাং এগুলি অন্যান্য সাধারণ ক্রিয়াকলাপের জন্যও ব্যবহার করা বোধগম্য।


এটি একটি বাধ্যতামূলক যুক্তি। আরও সন্তোষজনক যে "গাইডো ওওতে সত্যই বিশ্বাস করেনি" .... (যেমন আমি অন্য কোথাও দাবি করে দেখেছি)।
অ্যান্ডি হেডেন

15

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

নিম্নলিখিত উদাহরণ বিবেচনা করুন:

dict1 = {1 : "ABC"}
dict2 = {2 : "EFG"}

dict1 + dict2
Traceback (most recent call last):
  File "python", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict' and 'dict'

এটি একটি ত্রুটি দেয়, কারণ অভিধানের প্রকারটি সমর্থন করে না। এখন, আসুন অভিধানের ক্লাসটি বাড়ানো যাক এবং "__add__" ম্যাজিক পদ্ধতি যুক্ত করুন:

class AddableDict(dict):

    def __add__(self, otherObj):
        self.update(otherObj)
        return AddableDict(self)


dict1 = AddableDict({1 : "ABC"})
dict2 = AddableDict({2 : "EFG"})

print (dict1 + dict2)

এখন, এটি নিম্নলিখিত আউটপুট দেয়।

{1: 'ABC', 2: 'EFG'}

এই পদ্ধতিটি যুক্ত করে হঠাৎ যাদু ঘটেছে এবং আপনি যে ত্রুটিটি আগে পেয়েছিলেন তা চলে গেছে has

আমি আশা করি, এটি আপনার কাছে বিষয়গুলি পরিষ্কার করে দেয়। আরও তথ্যের জন্য, দেখুন:

পাইথনের যাদু পদ্ধতিগুলির একটি গাইড (রাফা কেটলার, ২০১২)


9

এর মধ্যে কয়েকটি ফাংশন একক পদ্ধতির চেয়েও বেশি কিছু প্রয়োগ করে (সুপার ক্লাসে বিমূর্ত পদ্ধতি ছাড়াই) প্রয়োগ করতে সক্ষম হয়। উদাহরণস্বরূপ bool()এই জাতীয় ধরণের কাজ করে:

def bool(obj):
    if hasattr(obj, '__nonzero__'):
        return bool(obj.__nonzero__())
    elif hasattr(obj, '__len__'):
        if obj.__len__():
            return True
        else:
            return False
    return True

আপনি 100% নিশ্চিত হতে পারেন যে bool()সর্বদা সত্য বা মিথ্যা ফিরে আসবে; আপনি যদি কোনও পদ্ধতির উপর নির্ভর করেন তবে আপনি কী ফিরে পাবেন তা পুরোপুরি নিশ্চিত হতে পারবেন না।

অন্যান্য বেশ কয়েকটি ফাংশন যে অপেক্ষাকৃত জটিল বাস্তবায়ন (অন্তর্নিহিত যাদু পদ্ধতি চেয়েও বেশি জটিল সম্ভবত হতে হয়) হয় iter()এবং cmp(), এবং সমস্ত বৈশিষ্ট্য পদ্ধতি ( getattr, setattrএবং delattr)। intজবরদস্তি করার সময় যাদু পদ্ধতিগুলি অ্যাক্সেস করার মতো জিনিস (আপনি প্রয়োগ করতে পারেন __int__) তবে ডাবল ডিউটি ​​ধরণের হিসাবে করুন। len(obj)আসলে এটি এমন একটি ক্ষেত্রে যেখানে আমি বিশ্বাস করি না যে এটি কখনও ভিন্ন obj.__len__()


4
পরিবর্তে hasattr()আমি ব্যবহার করব try:/ except AttributeError:এবং পরিবর্তে if obj.__len__(): return True else: return Falseআমি কেবল বলব return obj.__len__() > 0তবে সেগুলি কেবল স্টাইলিস্টিক জিনিস।
ক্রিস লুটজ

পাইথন ২.6-এ (যা বিটিডব্লিউ bool(x)উল্লেখ করা হয়েছে x.__nonzero__()), আপনার পদ্ধতিটি কাজ করবে না। বুল দৃষ্টান্তগুলির একটি পদ্ধতি আছে __nonzero__()এবং আপনার কোডটি একবার কল করতে থাকবে যখন আপত্তিটি একটি বুল ছিল। সম্ভবত আপনি bool(obj.__bool__())যেমন আচরণ করেছিলেন তেমন আচরণ করা উচিত __len__? (বা এই কোডটি আসলে পাইথন 3 এর জন্য কাজ করে?)
পঙ্কডুডল

সংজ্ঞার অদ্ভুতভাবে বিজ্ঞপ্তি প্রকৃতির প্রতিফলিত করার জন্য বুলের বিজ্ঞপ্তি প্রকৃতি কিছুটা ইচ্ছাকৃতভাবে অযৌক্তিক ছিল। এটি একটি আদিম বিবেচনা করা উচিত যে একটি যুক্তি আছে।
আয়ান বাইকিং

শুধু পার্থক্য (বর্তমানে) মধ্যে len(x)এবং x.__len__()যে সাবেক লেন্থ যে অতিক্রম জন্য OverflowError বাড়াতে হবে sys.maxsize, যখন আধুনিক সাধারণত জন্য ধরনের পাইথন বাস্তবায়িত করা হবে না। এটি কোনও বৈশিষ্ট্যের চেয়েও একটি বাগ, যদিও (উদাহরণস্বরূপ পাইথন ৩.২ এর পরিসীমা অবজেক্টটি বেশিরভাগ নির্বিচারে বৃহত পরিসীমা পরিচালনা lenকরতে পারে তবে তাদের সাথে ব্যবহার ব্যর্থ হতে পারে Their তাদের __len__ব্যর্থতা যদিও, পাইথনের পরিবর্তে সি তে প্রয়োগ করা হয়েছে)
এনকোঘলান

4

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


1

কারণটি বেশিরভাগ historicতিহাসিক হলেও পাইথনের কিছু অদ্ভুততা রয়েছে lenযা কোনও পদ্ধতির পরিবর্তে কোনও ফাংশনটির ব্যবহারকে উপযুক্ত করে তোলে।

পাইথনের কিছু অপারেশন পদ্ধতি হিসাবে প্রয়োগ করা হয়, উদাহরণস্বরূপ list.indexএবং dict.appendঅন্যগুলি কলযোগ্য এবং যাদু পদ্ধতি হিসাবে প্রয়োগ করা হয়, উদাহরণস্বরূপ strএবং iterএবং reversed। দুটি গ্রুপ যথেষ্ট পার্থক্য তাই বিভিন্ন পদ্ধতির ন্যায্যতা:

  1. তারা সাধারণ।
  2. str, intএবং বন্ধুদের ধরনের হয়। কনস্ট্রাক্টরকে কল করতে এটি আরও অর্থবোধ করে।
  3. বাস্তবায়ন ফাংশন কল থেকে পৃথক। উদাহরণস্বরূপ, যদি না পাওয়া যায় তবে iterকল করতে পারে এবং কোনও পদ্ধতিতে কল করা না এমন অতিরিক্ত যুক্তিগুলি সমর্থন করে। একই কারণে পাইথনের সাম্প্রতিক সংস্করণগুলিতে পরিবর্তন করা হয়েছে - এটি আরও অর্থবোধ করে।__getitem____iter__it.next()next(it)
  4. এর মধ্যে কয়েকটি অপারেটরের নিকটাত্মীয়। কল করার জন্য সিনট্যাক্স রয়েছে __iter__এবং __next__- এটিকে forলুপ বলা হয় । ধারাবাহিকতার জন্য, একটি ফাংশন আরও ভাল। এবং এটি নির্দিষ্ট অপটিমাইজেশনের জন্য এটি আরও ভাল করে তোলে।
  5. কিছু ফাংশন অন্যভাবে কিছুটা উপায়ের সাথে খুব একই রকম হয় - reprযেমনটি কাজ strকরে। রয়ে str(x)বনাম x.repr()বিভ্রান্তিকর হতে পারে।
  6. তাদের মধ্যে কিছু খুব কমই প্রকৃত বাস্তবায়ন পদ্ধতি ব্যবহার করে, উদাহরণস্বরূপ isinstance
  7. তাদের মধ্যে কিছু প্রকৃত অপারেটর, getattr(x, 'a')এটি করার একটি অন্য উপায় x.aএবং getattrপূর্বোক্ত গুণাবলীর অনেকগুলি ভাগ করে নেওয়া।

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

এটি বলার পরে, lenদ্বিতীয় গ্রুপে ঠিক ফিট হয় না। এটি প্রথমটির মধ্যে অপারেশনের আরও কাছাকাছি, একমাত্র পার্থক্যের সাথে এটি প্রায় কোনওটির চেয়ে বেশি সাধারণ। তবে কেবল এটিই কল করছে __len__এবং এটি খুব কাছে L.index। যাইহোক, কিছু পার্থক্য আছে। উদাহরণস্বরূপ, __len__অন্যান্য বৈশিষ্ট্যগুলি বাস্তবায়নের জন্য ডাকা হতে পারে, যেমন bool, যদি পদ্ধতিটি বলা হয় তবে lenআপনাকে bool(x)কাস্টম lenপদ্ধতিতে ভেঙে যেতে পারে যা সম্পূর্ণ ভিন্ন জিনিস করে।

সংক্ষেপে, আপনার কাছে খুব সাধারণ বৈশিষ্ট্যগুলির একটি সেট রয়েছে যা ক্লাসগুলি প্রয়োগ করতে পারে যা কোনও অপারেটরের মাধ্যমে, কোনও বিশেষ ক্রিয়াকলাপের মাধ্যমে (যা সাধারণত কোনও অপারেটর হিসাবে প্রয়োগকরণের চেয়ে বেশি কিছু করে), অবজেক্ট নির্মাণের সময় এবং তাদের সকলের দ্বারা অ্যাক্সেস করা যেতে পারে them কিছু সাধারণ বৈশিষ্ট্য ভাগ করুন। বাকি সব একটি পদ্ধতি is এবং lenএই নিয়মের কিছুটা ব্যতিক্রম।


0

উপরের দুটি পোস্টে যোগ করার মতো অনেক কিছুই নেই তবে সমস্ত "যাদু" ফাংশন আসলেই যাদু নয়। এগুলি __ বিল্টিন__ মডিউলের একটি অংশ যা দোভাষী শুরু করার পরে স্পষ্ট / স্বয়ংক্রিয়ভাবে আমদানি করা হয়। অর্থাৎ:

from __builtins__ import *

আপনার প্রোগ্রাম শুরুর আগে প্রতিবার ঘটে।

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

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