"অবজেক্ট" শ্রেণীর উদাহরণ হিসাবে অ্যাট্রিবিউট সেট করতে পারে না


88

সুতরাং, আমি এই প্রশ্নের উত্তর দেওয়ার সময় পাইথনের সাথে ঘুরছিলাম এবং আমি আবিষ্কার করেছি যে এটি বৈধ নয়:

o = object()
o.attr = 'hello'

কারণে একটি AttributeError: 'object' object has no attribute 'attr'। যাইহোক, অবজেক্ট থেকে উত্তরাধিকার সূত্রে প্রাপ্ত কোনও শ্রেণীর সাথে এটি বৈধ:

class Sub(object):
    pass

s = Sub()
s.attr = 'hello'

মুদ্রণ s.attrপ্রত্যাশিত হিসাবে 'হ্যালো' প্রদর্শন করে। কেন এই ক্ষেত্রে? পাইথন ল্যাঙ্গুয়েজ স্পেসিফিকেশনের মধ্যে কী এমনটি সুনির্দিষ্ট করে যে আপনি ভ্যানিলা অবজেক্টের জন্য অ্যাট্রিবিউট বরাদ্দ করতে পারবেন না?


খাঁটি অনুমান: ধরণটি objectঅপরিবর্তনীয় এবং নতুন বৈশিষ্ট্য যুক্ত করা যায় না? এটি সর্বাধিক বোধ করবে বলে মনে হচ্ছে।
ক্রিস লুটজ

4
@ এস.লোট: এই প্রশ্নের প্রথম লাইনটি দেখুন। খাঁটি কৌতূহল।
স্মিশেরি

4
আপনার শিরোনাম বিভ্রান্তিমূলক, আপনি objectক্লাসে নয় ক্লাসের উদাহরণগুলিতে অ্যাট্রিবিউট সেট করার চেষ্টা করছেন object

উত্তর:


130

স্বেচ্ছাচারিত বৈশিষ্ট্য অ্যাসাইনমেন্ট সমর্থন করার জন্য, একটি বস্তুর একটি প্রয়োজন __dict__: অবজেক্টের সাথে যুক্ত একটি ডিক, যেখানে স্বেচ্ছাসেবী বৈশিষ্ট্যগুলি সংরক্ষণ করা যায়। তা না হলে, কোথাও এর করা নতুন বৈশিষ্ট্যাবলী।

উদাহরণটি একটিটিকে ঘিরে objectরাখে না__dict__ - যদি এটি ঘটে থাকে , ভয়াবহ বিজ্ঞপ্তি নির্ভরতা সমস্যার আগে (যেহেতু dict, অন্যান্য সমস্ত কিছুর মতো object;-) থেকে উত্তরাধিকার সূত্রে প্রাপ্ত হয় , এটি পাইথনের প্রতিটি বস্তুকে একটি ডিক দিয়ে কাটায়, যার অর্থ ওভারহেড হবে এর অনেক বস্তু যা বর্তমানে নেই বা অভি প্রয়োজন প্রতি বাইট (মূলত, সমস্ত বস্তু আছে না যে ইচ্ছামত হস্তান্তরযোগ্য বৈশিষ্ট্যাবলী হবে না বা অভি প্রয়োজন)।

উদাহরণস্বরূপ, দুর্দান্ত pymplerপ্রকল্পটি ব্যবহার করে (আপনি এখান থেকে এসএনএন এর মাধ্যমে এটি পেতে পারেন ), আমরা কিছু পরিমাপ করতে পারি ...:

>>> from pympler import asizeof
>>> asizeof.asizeof({})
144
>>> asizeof.asizeof(23)
16

আপনি চাইবেন না যে প্রত্যেকে intকেবল ১ 16 এর পরিবর্তে ১৪৪ বাইট তুলবে , তাই না? -)

এখন, আপনি যখন ক্লাস করেন (যা কিছু থেকে উত্তরাধিকারী হয়), জিনিসগুলি পরিবর্তন হয় ...:

>>> class dint(int): pass
... 
>>> asizeof.asizeof(dint(23))
184

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

তাহলে আপনি যদি intকেবল একটি অতিরিক্ত বৈশিষ্ট্যটি চান foobar...? এটি একটি বিরল প্রয়োজন, তবে পাইথন এই উদ্দেশ্যে একটি বিশেষ প্রক্রিয়া সরবরাহ করে ...

>>> class fint(int):
...   __slots__ = 'foobar',
...   def __init__(self, x): self.foobar=x+100
... 
>>> asizeof.asizeof(fint(23))
80

... না বেশ একটি হিসাবে ছোট হিসাবে int, আপনি মন! (বা এমনকি দুটি intগুলি, একটি selfএবং একটি self.foobar- দ্বিতীয়টি পুনরায় নিয়োগ দেওয়া যেতে পারে), তবে অবশ্যই এ এর ​​চেয়ে অনেক ভাল dint

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

হারানো নমনীয়তার বিনিময়ে, আপনি উদাহরণস্বরূপ প্রচুর বাইট অর্জন করেন (সম্ভবত আপনার যদি অর্থাত্ লক্ষ লক্ষ ঘটনা উদ্রেক করা হয় তবে এর জন্য ব্যবহারের কেস রয়েছে)।


4
এটি কীভাবে প্রক্রিয়া বাস্তবায়িত হয় তা ব্যাখ্যা করে তবে কেন এটি এভাবে বাস্তবায়িত করা হয় তা ব্যাখ্যা করে না। আমি উড়ে উড়ে ডিক যুক্ত করার কমপক্ষে দুটি বা তিনটি উপায়ের কথা ভাবতে পারি যার ওভারহেড ডাউনডাইজ হবে না তবে কিছু সরলতা যুক্ত করবে।
20 19

লক্ষ্য করুন খালি নয় এমন __slots__যেমন পরিবর্তনশীল দৈর্ঘ্যের ধরনের সঙ্গে কাজ করে না str, tupleএবং পাইথন 3 এছাড়া int
arekolek


এটা তোলে উত্তর না কেন (অথবা কিভাবে) একটি দুর্দান্ত ব্যাখ্যা, কিন্তু এখনও Subআছে __dict__অ্যাট্রিবিউটে বস্তু হচ্ছে না, Subউত্তরাধিকারী থেকে object, কিভাবে যে অ্যাট্রিবিউট (এবং মত অন্যদের হয় __module__) উত্তরাধিকার যোগ? এটি হতে পারে এটি একটি নতুন প্রশ্ন হতে পারে
রদ্রিগো ই। প্রিন্সিপ

4
কোনও বস্তুর __dict__কেবলমাত্র এটির প্রয়োজন প্রথমবার তৈরি করা হয়, সুতরাং asizeofআউটপুট এটি চেহারা হিসাবে মেমরির ব্যয় পরিস্থিতি এতটা সহজ নয় simple ( asizeofএড়াতে জানেন কিভাবে না __dict__বাস্তবায়ন।) আপনি অভি পর্যন্ত প্রয়োজন রূপায়িত পেয়ে দেখতে পারে না এই উদাহরণে , এবং আপনি কোড পাথ জন্য দায়ী এক দেখতে পারেন __dict__বাস্তবায়ন এখানে
ব্যবহারকারী 2357112 মনিকা

17

অন্যান্য উত্তরদাতারা যেমন বলেছেন, একটিতে একটি objectনেই __dict__। বা সহ সকল প্রকারের objectবেস শ্রেণি । সুতরাং যা কিছু সরবরাহ করা হবে তা তাদের জন্যও বোঝা হয়ে উঠবে। এমনকি একটি বিকল্প হিসাবে সাধারণ কিছু প্রতিটি মানের জন্য একটি অতিরিক্ত পয়েন্টার প্রয়োজন হবে; এটি সিস্টেমের প্রতিটি বস্তুর জন্য খুব সীমিত ইউটিলিটির জন্য অতিরিক্ত 4-8 বাইট মেমরি নষ্ট করবে।intstrobject __dict__


পাইথন ৩.৩++ তে ডামি ক্লাসের উদাহরণ না দিয়ে আপনি এর জন্য (এবং হওয়া উচিত) ব্যবহার করতে পারেন types.SimpleNamespace


4

এটি কেবল অপ্টিমাইজেশনের কারণে।

ডিক্টস তুলনামূলকভাবে বড়।

>>> import sys
>>> sys.getsizeof((lambda:1).__dict__)
140

সিতে সংজ্ঞায়িত বেশিরভাগ (সম্ভবত সমস্ত) শ্রেণিতে অনুকূলিতকরণের জন্য ডিক নেই।

আপনি যদি সোর্স কোডটি দেখেন তবে আপনি দেখতে পাবেন যে সেখানে অনেকগুলি চেক আছে যা দেখতে অবজেক্টটির ডিক আছে কি না।


1

সুতরাং, আমার নিজের প্রশ্নটি অনুসন্ধান করে আমি পাইথন ভাষা সম্পর্কে এটি আবিষ্কার করেছি: আপনি ইনট জাতীয় জিনিস থেকে উত্তরাধিকারী হতে পারেন এবং আপনি একই আচরণ দেখতে পান:

>>> class MyInt(int):
       pass

>>> x = MyInt()
>>> print x
0
>>> x.hello = 4
>>> print x.hello
4
>>> x = x + 1
>>> print x
1
>>> print x.hello
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
AttributeError: 'int' object has no attribute 'hello'

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


0

এর কারণ বস্তু একটি "প্রকার", শ্রেণি নয়। সাধারণভাবে, সি এক্সটেনশনে সংজ্ঞায়িত সমস্ত শ্রেণি (যেমন ডেটাটাইপগুলিতে অন্তর্নির্মিত সমস্ত উপাদান এবং নমপি অ্যারেগুলির মতো স্টাফ) স্বেচ্ছাচারিত গুণাবলী যুক্ত করার অনুমতি দেয় না।


তবে অবজেক্ট () একটি অবজেক্ট, ঠিক যেমন সাব () একটি অবজেক্ট। আমার উপলব্ধি হ'ল উভয় ও ও উভয়ই বস্তু। সুতরাং ও ও এর মধ্যে মৌলিক পার্থক্য কি? এটি কি একটি তাত্ক্ষণিক ধরণের এবং অন্যটি তাত্ক্ষণিক শ্রেণি?
স্ম্যাসেরি

বিঙ্গো ঠিক এটাই ইস্যু।
রায়ান

4
পাইথন 3 এ, ধরণ এবং শ্রেণীর মধ্যে পার্থক্যটি আসলেই বিদ্যমান নেই। সুতরাং "টাইপ" এবং "শ্রেণি" এখন মোটামুটি সমার্থক শব্দ। তবে আপনি এখনও __dict__অ্যালেক্স মার্তেলির কারণে যে ক্লাসগুলির একটি নেই সেগুলিতে গুণাবলী যুক্ত করতে পারবেন না ।
পিএম 2 রিং


-2

এটি (আইএমও) পাইথনের অন্যতম মৌলিক সীমাবদ্ধতা - আপনি আবার ক্লাস খুলতে পারবেন না। আমি বিশ্বাস করি যে আসল সমস্যাটি এই কারণে ঘটেছিল যে সি তে প্রয়োগ করা ক্লাসগুলি রানটাইম সময়ে সংশোধন করা যায় না ... সাবক্লাসগুলি করতে পারে তবে বেস ক্লাসগুলি নয়।

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