আমি কেন বস্তুর উদাহরণের __class__ বৈশিষ্ট্যটি পরিবর্তন করতে পারি না?


10
class A(object):
    pass

class B(A):
    pass

o = object()
a = A()
b = B()

আমি যখন পরিবর্তন করতে পারি তখনও আমি এটি a.__class__দিয়ে কিছু করতে পারি না o.__class__(এটি একটি TypeErrorত্রুটি ছুড়ে দেয় )। কেন?

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

isinstance(a, A) # True
isinstance(a, B) # False
a.__class__ = B
isinstance(a, A) # True
isinstance(a, B) # True

isinstance(o, object) # True
isinstance(o, A) # False
o.__class__ = A # This fails and throws a TypeError
# isinstance(o, object)
# isinstance(o, A)

আমি জানি এটি সাধারণত একটি ভাল ধারণা নয়, কারণ এটি যদি ভুলভাবে পরিচালনা করা হয় তবে এটি কিছু অদ্ভুত আচরণের দিকে পরিচালিত করতে পারে। এটি কেবল কৌতুহলের খাতিরে।


3
দক্ষতার কারণে বিল্ট-ইন টাইপগুলি ব্যবহারকারী-সংজ্ঞায়িত প্রকারের গতিশীলতা ত্যাগ করে। দ্রষ্টব্য, অন্য alচ্ছিক অপ্টিমাইজেশন হ'ল স্লট, যা একইভাবে এটি প্রতিরোধ করবে।
juanpa.arrivillaga

উত্তর:


6

CPython একটি মন্তব্য আছে অবজেক্টস / typeobject.c এই বিষয়ে:

সিপিথনের সংস্করণগুলিতে ৩.৫ এর পূর্বে, compatible_for_assignmentনন-হেপটাইপী ক্লাসগুলির জন্য মেমরি লেআউট / স্লট / ইত্যাদি সামঞ্জস্যতা সঠিকভাবে যাচাই করার জন্য কোডটি সেট আপ করা হয়নি, সুতরাং আমরা কেবল __class__হ্যাপটাইপ -> হ্যাপটাইপ নয় - এমন কোনও ক্ষেত্রে অ্যাসাইনমেন্টটি বাতিল করে দিয়েছি।

৩.৫ বিকাশের চক্র চলাকালীন, আমরা compatible_for_assignmentনির্বিচারে ধরণেরগুলির মধ্যে সামঞ্জস্যতা সঠিকভাবে পরীক্ষা করার জন্য কোডটি ঠিক করেছিলাম __class__এবং পুরানো এবং নতুন ধরণের প্রকৃতপক্ষে সামঞ্জস্যপূর্ণ স্লট এবং মেমরি লেআউট রয়েছে এমন সমস্ত ক্ষেত্রে অ্যাসাইনমেন্টের অনুমতি দেওয়া শুরু করে (সেগুলি হ্যাপটাইপিসি হিসাবে প্রয়োগ করা হয়েছিল কিনা তা বিবেচনা না করে) অথবা না).

৩.৩ প্রকাশের ঠিক আগে, যদিও আমরা আবিষ্কার করেছি যে এর ফলে অবিরত প্রকারের মতো সমস্যা রয়েছে যার ফলে ইন্টারপ্রেটারি ধরে নেয় যে তারা পরিবর্তনযোগ্য এবং কিছু মানকে অন্তর্ভুক্ত করে। পূর্বে এটি কোনও সমস্যা ছিল না, কারণ তারা সত্যই অপরিবর্তনীয় ছিল - বিশেষত, দোভাষী যে জাতীয় প্রকারের অভ্যন্তরীণ কৌশলটি ব্যবহার করেছিলেন সেগুলিও স্থিতিশীলভাবে বরাদ্দ করা হয়েছিল, সুতরাং পুরানো শপথের নিয়মগুলি "দুর্ঘটনাক্রমে" __class__নিয়োগের অনুমতি দেওয়া থেকে বিরত ছিল । কিন্তু __class__অ্যাসাইনমেন্টের পরিবর্তনগুলির সাথে , আমরা কোডের মতো অনুমতি দেওয়া শুরু করি

class MyInt(int):
#   ...
# Modifies the type of *all* instances of 1 in the whole program,
# including future instances (!), because the 1 object is interned.
 (1).__class__ = MyInt

( https://bugs.python.org/issue24912 দেখুন )।

তাত্ত্বিকভাবে সঠিক __class__সমাধানটি হ'ল কোন শ্রেণি এই আক্রমণকারীটির উপর নির্ভর করে এবং কেবলমাত্র তাদের জন্য অ্যাসাইনমেন্টটি অস্বীকার করবে, সম্ভবত কোনও নতুন পিটিপিপিএফএলএজিএস_আইএমটিউবল পতাকা ("ব্ল্যাকলিস্টিং" পদ্ধতির) মতো কোনও প্রক্রিয়া মাধ্যমে via তবে বাস্তবে, যেহেতু 3.5 টি আরসি চক্রের মধ্যে এই সমস্যাটি দেরিতে লক্ষ্য করা যায় নি, তাই আমরা রক্ষণশীল পন্থা নিচ্ছি এবং একই হ্যাপটাইপ>> হ্যাপটাইপই চেকটি পুনরায় ফিরিয়ে আনছি যা আমাদের কাছে ছিল, পাশাপাশি একটি "শ্বেতলিস্ট"। আপাতত, শ্বেতলিস্টটি কেবলমাত্র মডিউলটাইপ সাব টাইপগুলি নিয়ে গঠিত, যেহেতু প্যাচগুলি প্রথম স্থানে অনুপ্রাণিত করে - https://bugs.python.org/issue22986 দেখুন - এবং যেহেতু মডিউল অবজেক্টগুলি পারস্পরিক পরিবর্তনযোগ্য তাই আমরা নিশ্চিত হতে পারি যে তারা অবশ্যই অভ্যন্তরীণ করা হচ্ছে না। সুতরাং এখন আমরা হ্যাপটাইপ-> হেপটাইপ বা অনুমতি দিই মডিউলটাইপ সাব টাইপ -> মডিউল টাইপ সাব টাইপ।

যতদূর আমরা জানি, নিম্নলিখিত 'if' স্টেটমেন্টের বাইরে থাকা সমস্ত কোড সঠিকভাবে নন-হেপটাইপিই ক্লাস পরিচালনা করবে এবং হেপটাইপিই চেক কেবল নন-হ্যাপটাইপ ক্লাসের সাবসেটটি রক্ষা করতে হবে যার জন্য অনুবাদক অনুমান করে বেক করেছেন সমস্ত দৃষ্টান্ত সত্যই পরিবর্তনযোগ্য।

ব্যাখ্যা:

সিপথন দুটি উপায়ে বস্তু সঞ্চয় করে:

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

অন্তর্ভুক্ত / অবজেক্ট । এ মন্তব্য থেকে তথ্য ।

আপনি যখন একটি নতুন মান সেট করার চেষ্টা করছেন some_obj.__class__, তখন object_set_classফাংশনটি বলা হয়। এটি পাইব্যাসঅবজেক্ট_ টাইপ থেকে উত্তরাধিকার সূত্রে প্রাপ্ত , /* tp_getset */ক্ষেত্রটি দেখুন। এই ফাংশনটি পরীক্ষা করে : নতুন টাইপটি কি পুরানো প্রকারকে প্রতিস্থাপন করতে পারে some_obj?

আপনার উদাহরণ নিন:

class A:
    pass

class B:
    pass

o = object()
a = A() 
b = B() 

প্রথম কেস:

a.__class__ = B 

ধরণ aঅবজেক্ট A, গাদা ধরন, কারণ এটি পরিবর্তনশীল বরাদ্দ করা হয়। পাশাপাশি Baএর ধরনের একটি সমস্যা ছাড়া পরিবর্তিত হয়।

দ্বিতীয় মামলা:

o.__class__ = B

প্রকারটি oহ'ল বিল্ট-ইন টাইপ object( PyBaseObject_Type)। এটি হিপ প্রকার নয়, তাই TypeErrorউত্থাপিত হয়:

TypeError: __class__ assignment only supported for heap types or ModuleType subclasses.

4

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

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