লেন () এবং .__ লেন __ () এর মধ্যে পার্থক্য?


104

কলিং এর মধ্যে কোন পার্থক্য আছে len([1,2,3])নাকি [1,2,3].__len__()?

যদি কোনও দৃশ্যমান পার্থক্য না থাকে তবে পর্দার আড়ালে আলাদাভাবে কী করা হয়?


উত্তর:


103

lenএকটি সংগ্রহ দৈর্ঘ্য পেতে একটি ফাংশন। এটি কোনও অবজেক্টের __len__পদ্ধতিতে কল করে কাজ করে । __something__বৈশিষ্ট্যগুলি বিশেষ এবং সাধারণত চোখের বেশি দেখা যায় এবং সাধারণত সরাসরি ডাকা উচিত নয়।

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


67

এটি প্রায়শই এমন হয় যে কোনও অন্তর্নির্মিত বা অপারেটরের "সাধারণ" আচরণটি __whatever__জড়িত অবজেক্টগুলিতে উপযুক্ত জাদু পদ্ধতিগুলি (যেমন নামগুলির সাথে থাকে ) কল করা হয়। প্রায়শই অন্তর্নির্মিত বা অপারেটরের "সংযোজিত মান" থাকে (এটি জড়িত বস্তুর উপর নির্ভর করে বিভিন্ন পাথ গ্রহণ করতে সক্ষম হয়) - lenবনামের ক্ষেত্রে __len__এটি বিল্ট-ইনটি থেকে নিখরচায় কিছুটা বিশুদ্ধতা যাচাই করে চলেছে যা অনুপস্থিত is যাদু পদ্ধতি:

>>> class bah(object):
...   def __len__(self): return "an inch"
... 
>>> bah().__len__()
'an inch'
>>> len(bah())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object cannot be interpreted as an integer

যখন আপনি lenঅন্তর্নির্মিতকে কোনও কল দেখেন , আপনি নিশ্চিত হন যে প্রোগ্রামটি যদি তার পরেও ব্যতিক্রম বাড়ানোর পরিবর্তে অব্যাহত থাকে, কলটি একটি পূর্ণসংখ্যা, অ-নেতিবাচক এবং 2 ** 31 এর চেয়ে কম ফিরিয়ে দেয় - কখন আপনি এই কলটি দেখতে পাচ্ছেন xxx.__len__(), আপনার কোনও নিশ্চিততা নেই (কোডটির লেখক পাইথনের সাথে অপরিচিত বা কোনও ভাল ;-) পর্যন্ত নয়।

অন্যান্য বিল্ট-ইনগুলি সাধারণ স্যানিটি চেক এবং পঠনযোগ্যতার বাইরে আরও বেশি যুক্ত মূল্য সরবরাহ করে। বিল্টিনগুলিতে কল এবং অপারেটরদের ব্যবহারের মাধ্যমে পাইথনের সমস্ত কাজকে অভিন্নভাবে ডিজাইনের মাধ্যমে, যাদু পদ্ধতিগুলির মাধ্যমে কল করার মাধ্যমে কখনই প্রোগ্রামাররা কোন ঘটনাটি মনে রাখার বোঝা থেকে রক্ষা পায় না। (কখনও কখনও ত্রুটি পিছলে যায়: 2.5 অবধি, আপনাকে কল করতে হয়েছিল foo.next()- 2.6 এ, এটি এখনও পিছনের সামঞ্জস্যের জন্য কাজ করে, আপনাকে কল করা উচিত next(foo), এবং 3.*ম্যাজিক পদ্ধতিটি __next__"ওফস-এ" এর পরিবর্তে সঠিকভাবে নামকরণ করা হয়েছে next! - )।

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


আমি শিক্ষানবিস পাইথন ব্যবহারকারী (শিক্ষানবিশ প্রোগ্রামার ভাবেননি) এবং আমি "আপনি যখন বিল্ট-ইন লেনটিতে কল দেখেন, তখন আপনি নিশ্চিত যে, যদি ব্যতিক্রম উত্থাপনের পরিবর্তে প্রোগ্রামটি যদি এর পরে অব্যাহত থাকে" তবে আমি নিশ্চিত নই। আমি এটি চেষ্টা করেছি: def len(x): return "I am a string." print(len(42)) print(len([1,2,3]))এবং এটি I am stringদুবার মুদ্রিত হয়েছিল। আপনি আরও ব্যাখ্যা করতে পারেন?
দারেক নডজা

4
@ দারেকনাডজা এর উপরোক্ত সাথে কিছু করার নেই, যা বিল্টিন লেন সম্পর্কে। আপনি কেবল আপনার লেন ফাংশনটি সংজ্ঞায়িত করেছেন, এটি অবশ্যই আপনি যা চান তা ফিরিয়ে দিতে পারে। ওপি বিল্টিন লেন সম্পর্কে কথা বলেছেন, যা বিবেচনাধীন অবজেক্টটিতে __len__বিশেষ পদ্ধতি (ফাংশন নয়) বলে।
ভিকি

@Veky আমি নিশ্চিত যে আমি আহ্বান করছি কেমন করে হতে পারে বিল্ট-ইন ফাংশন lenনা (আমার উদাহরণে মত) কিছু অন্যান্য ফাংশন যা একই নাম ঘটেছে - len। "আপনি অন্তর্নির্মিত ফাংশন লেনটিকে পুনরায় সংজ্ঞায়িত করছেন" বা এর মতো কোনও সতর্কতা নেই। আমার মতে, অ্যালেক্স তার উত্তরে যা বলেছিল তা সম্পর্কে আমি নিশ্চিত হতে পারি না।
দারেক নডজা

4
অ্যালেক্স স্পষ্টভাবে বলেছিল যে আপনি যদি বিল্টিনকে কল করছেন, তবে আপনি অবশ্যই ..._ _ আপনি বিল্টিন বলেছিলেন তা নিশ্চিত হওয়ার বিষয়ে তিনি কিছুই বলেননি। কিন্তু যদি আপনি যে জানতে চাই, আপনি পারেন: len in vars(__builtins__).values()
ভিকি

4
দুঃখের বিষয়, পাইথনের বস্তুর জন্য সাধারণ বেস শ্রেণির অভাবের এটি আরেকটি উদাহরণ। সিনট্যাকটিক প্রসঙ্গে স্যুইচিং সবসময় বাদাম হয়েছে। কিছু ক্ষেত্রে আন্ডারস্কোর পদ্ধতি ব্যবহার করা সাধারণ রীতিমত হ'ল অন্য কারও ক্ষেত্রে অনেকগুলি অবজেক্টের জন্য সাধারণ কিছু করার জন্য কোনও ফাংশনের মতো কিছু ব্যবহার করা উচিত। এটিও অদ্ভুত কারণ লেনের জন্য অনেকগুলি অবজেক্টের কোনও শব্দার্থ ব্যবহার নেই। কখনও কখনও অবজেক্ট মডেলটি আরও সি ​​++ এর মতো, রান্নাঘরের সিনকি ..
উছুগাকা

28

আপনি লেন () প্রায় সমতুল্য হিসাবে ভাবতে পারেন

def len(x):
    return x.__len__()

একটি সুবিধা হ'ল এটি আপনাকে পছন্দ মতো জিনিস লেখার অনুমতি দেয়

somelist = [[1], [2, 3], [4, 5, 6]]
map(len, somelist) 

পরিবর্তে

map(list.__len__, somelist)

বা

map(operator.methodcaller('__len__'), somelist)

যদিও কিছুটা আলাদা আচরণ আছে। উদাহরণস্বরূপ ints ক্ষেত্রে

>>> (1).__len__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute '__len__'
>>> len(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'int' has no len()

4
আমি আপনার operator.methodcallerপরিবর্তে মানে ধরে নিচ্ছি operator.attrgetter
এলাজার

5

আপনি পাইথন্ড ডক্স পরীক্ষা করতে পারেন :

>>> class Meta(type):
...    def __getattribute__(*args):
...       print "Metaclass getattribute invoked"
...       return type.__getattribute__(*args)
...
>>> class C(object):
...     __metaclass__ = Meta
...     def __len__(self):
...         return 10
...     def __getattribute__(*args):
...         print "Class getattribute invoked"
...         return object.__getattribute__(*args)
...
>>> c = C()
>>> c.__len__()                 # Explicit lookup via instance
Class getattribute invoked
10
>>> type(c).__len__(c)          # Explicit lookup via type
Metaclass getattribute invoked
10
>>> len(c)                      # Implicit lookup
10
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.