কেন একটি ক্লাসে একটি ডেস্ক্রিপ্টর সেট করে বিবরণকারীকে ওভাররাইট করে?


10

সরল তিরস্কার:

class VocalDescriptor(object):
    def __get__(self, obj, objtype):
        print('__get__, obj={}, objtype={}'.format(obj, objtype))
    def __set__(self, obj, val):
        print('__set__')

class B(object):
    v = VocalDescriptor()

B.v # prints "__get__, obj=None, objtype=<class '__main__.B'>"
B.v = 3 # does not print "__set__", evidently does not trigger descriptor
B.v # does not print anything, we overwrote the descriptor

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

আমি __getattribute__বর্ণনাকারীদের প্রয়োগের আচরণের উপর প্রচুর কালি ছিটকে দেখেছি , উদাহরণস্বরূপ অনুসন্ধানের নজরে। পাইথন snippet মধ্যে "আবাহন বর্ণনাকারী" শুধু নিচের For classes, the machinery is in type.__getattribute__()...মোটামুটিভাবে আমার মনের মধ্যে কি আমি বিশ্বাস করি সংশ্লিষ্ট সঙ্গে একমত CPython উৎস মধ্যে type_getattro, যা আমি এ খুঁজছেন দ্বারা নিচে ট্র্যাক "tp_slots" তারপর যেখানে tp_getattro জনবহুল হয় । এবং B.vপ্রাথমিকভাবে মুদ্রণের বিষয়টি __get__, obj=None, objtype=<class '__main__.B'>আমার কাছে বোধগম্য।

আমি যা বুঝতে পারি না তা হ'ল অ্যাসাইনমেন্টটি B.v = 3ট্রিগার করার পরিবর্তে অন্ধভাবে বর্ণনাকারীকে ওভাররাইট করে v.__set__? আমি "টিপি_স্লটস" থেকে আরও একবার শুরু করে সিপিথন কলটি সনাক্ত করার চেষ্টা করেছি , তারপরে tp_setattro কোথায় জনবসতিযুক্ত তা সন্ধান করে , তারপরে টাইপ_সেট্ট্রোর দিকে তাকিয়ে আছিtype_setattro উপস্থিত হতে পারে কাছাকাছি একটি পাতলা মোড়কের _PyObject_GenericSetAttrWithDict । এবং আমার বিভ্রান্তির শিষ্টাচারটি এখানে _PyObject_GenericSetAttrWithDictউপস্থিত রয়েছে : এমন যুক্তি রয়েছে যা কোনও বর্ণনাকারীর __set__পদ্ধতিকে প্রাধান্য দেয় !! এটিকে মনে রেখে, আমি ট্রিগার করার চেয়ে B.v = 3অন্ধভাবে কেন ওভাররাইট করে তা বুঝতে পারি না ।vv.__set__

দাবি পরিত্যাগী 1: আমি printfs সঙ্গে উৎস থেকে পাইথন পুনর্নির্মাণের করা হয়নি, তাই আমি সম্পূর্ণরূপে নিশ্চিত নই type_setattroকি সময় বলা হচ্ছে হয় B.v = 3

দাবি অস্বীকার 2: VocalDescriptor"আদর্শ" বা "প্রস্তাবিত" বর্ণনাকারী সংজ্ঞাটির উদাহরণ হিসাবে নয় mp পদ্ধতিগুলি কখন ডাকা হচ্ছে তা আমাকে বলার জন্য এটি একটি ভার্জোজ নো-অপশন।


1
আমার জন্য এটি শেষ লাইনে 3 টি প্রিন্ট করে ... কোডটি
জব

3
বর্ণনাকারীরা কোনও উদাহরণ থেকে বৈশিষ্ট্য অ্যাক্সেস করার সময় প্রয়োগ করেন, বর্গ নিজেই নয়। আমার কাছে রহস্যটি কেন __get__এলো __set__না কেন তার চেয়েও কেন কাজ করেছিল।
জেসনহার্পার

1
@ জ্যাব ওপি আশা করছেন যে এখনও __get__পদ্ধতিটি চালু করা উচিত। B.v = 3কার্যকরভাবে একটি দিয়ে গুণকে ওভাররাইট করেছে int
r.ook ১

2
@ জেসনহার্পার অ্যাট্রিবিউট অ্যাক্সেস নির্ধারিত হয় কিনা ডাকা __get__হয় object.__getattribute__এবং কোনও উদাহরণ বা শ্রেণি ব্যবহারের সময় ডিফল্ট রূপায়ণ এবং আবেদন করা হয় । মাধ্যমে অ্যাসাইন করা কেবল উদাহরণস্বরূপ। type.__getattribute____get____set__
চিপনার

@ জেসনহার্পার, আমি বিশ্বাস করি যে শ্রেণিবদ্ধ হওয়ার আগেই বর্ণনাকারীদের __get__পদ্ধতিগুলি ট্রিগার হওয়ার কথা। গাইড ক্লাস অনুসারে এভাবেই ক্লাসমেডোডস এবং @ স্ট্যাটিকমেডসগুলি কার্যকর করা হয় । @ জ্যাব আমি ভাবছি কেন B.v = 3ক্লাস বর্ণনাকারকে ওভাররাইট করতে সক্ষম? CPython বাস্তবায়ন উপর ভিত্তি করে, আমি আশা B.v = 3এছাড়াও ট্রিগার __set__
মাইকেল ক্যারিলি

উত্তর:


6

আপনি সঠিক যে B.v = 3কেবল একটি পূর্ণসংখ্যার (যেমনটি হওয়া উচিত) দিয়ে বিবরণকারীকে ওভাররাইট করে।

জন্য B.v = 3একটি বর্ণনাকারী ডাকা, বর্ণনাকারী ক্লাসের অধীনে একটি ক্লাস, অর্থাত্ উপর সংজ্ঞায়িত করা উচিত ছিল type(B)

>>> class BMeta(type): 
...     v = VocalDescriptor() 
... 
>>> class B(metaclass=BMeta): 
...     pass 
... 
>>> B.v = 3 
__set__

বর্ণনাকারীকে অনুরোধ করার জন্য B, আপনি একটি উদাহরণ ব্যবহার B().v = 3করবেন: এটি করবে।

B.vগ্রাহককে অনুরোধ করার কারণটি হ'ল বর্ণনাকারী দৃষ্টান্তটি নিজেই ফেরত দেওয়া। ক্লাস অবজেক্টের মাধ্যমে বর্ণনাকারীর অ্যাক্সেসের অনুমতি দেওয়ার জন্য আপনি সাধারণত তা করতেন:

class VocalDescriptor(object):
    def __get__(self, obj, objtype):
        if obj is None:
            return self
        print('__get__, obj={}, objtype={}'.format(obj, objtype))
    def __set__(self, obj, val):
        print('__set__')

এখন B.vএমন কিছু উদাহরণ ফিরে আসবে <mymodule.VocalDescriptor object at 0xdeadbeef>যার সাথে আপনি ইন্টারঅ্যাক্ট করতে পারেন। এটি আক্ষরিক অর্থে বর্ণনাকারী অবজেক্ট, শ্রেণীর বৈশিষ্ট্য হিসাবে সংজ্ঞায়িত এবং এর রাজ্যটি B.v.__dict__সমস্ত দৃষ্টান্তের মধ্যে ভাগ করা হয় B

অবশ্যই তারা কী করতে চায় তা নির্ধারণ করার জন্য ব্যবহারকারীর কোড অবধি B.v, ফিরে আসা selfকেবল সাধারণ প্যাটার্ন।


1
এই উত্তরটি সম্পূর্ণ করার জন্য আমি যুক্ত করব যে __get__এটি উদাহরণ বৈশিষ্ট্য বা শ্রেণি বৈশিষ্ট্য হিসাবে ডাকা হয়েছে, তবে __set__কেবল উদাহরণ বৈশিষ্ট্য হিসাবে ডাকা হয়েছে। এবং প্রাসঙ্গিক ডক্স: docs.python.org/3/references/datamodel.html#object.__get__
সান্য্যাশ

@ উইম ম্যাগনিফিকেন্ট !! সমান্তরালে আমি আবার টাইপ_সেট্ট্রো কল চেইনে তাকিয়ে ছিলাম। আমি দেখতে পেলাম যে _PyObject_GenericSetAttrWithDict এ কলটি সরবরাহ করে (এই ক্ষেত্রে B, আমার ক্ষেত্রে) supplies
মাইকেল ক্যারিলি

মধ্যে _PyObject_GenericSetAttrWithDict, এটা বি এর Py_TYPE pulls হিসাবে tp, যা খ এর ক্লাসের অধীনে একটি ক্লাস আছে ( typeআমার ক্ষেত্রে), তারপর এটা ক্লাসের অধীনে একটি ক্লাস tp যে চিকিত্সা করা হয় বর্ণনাকারী শর্ট-সার্কিট যুক্তিবিজ্ঞান । সুতরাং বর্ণনাকারী সরাসরি সংজ্ঞাসমূহ B নয় যে স্বল্প-পরিক্রমার যুক্তিবিজ্ঞান দ্বারা দেখা (অতএব আমার মূল কোডে __set__বলা হয় না), কিন্তু একটি বর্ণনাকারী ক্লাসের অধীনে একটি ক্লাস সংজ্ঞাসমূহ হয় শর্ট-সার্কিট যুক্তিবিজ্ঞান দ্বারা দেখা।
মাইকেল ক্যারিলি

অতএব, আপনার ক্ষেত্রে যেখানে ক্লাসের অধীনে একটি ক্লাস একটি বর্ণনাকারী রয়েছে এ, __set__যে বর্ণনাকারী পদ্ধতি হয় বলা হয়।
মাইকেল ক্যারিলি

@ সানিয়াশ সরাসরি সম্পাদনা করতে নির্দ্বিধায় মনে হয়।
উইম

3

কোনও ওভাররাইড ছাড়া, B.vসমতূল্য type.__getattribute__(B, "v"), যখন b = B(); b.vসমতূল্য object.__getattribute__(b, "v")। উভয় সংজ্ঞা __get__সংজ্ঞায়িত হলে ফলাফলের পদ্ধতিটি প্রার্থনা করে ।

দ্রষ্টব্য, চিন্তা, __get__প্রতিটি ক্ষেত্রে কল পৃথক। প্রথম আর্গুমেন্ট হিসাবে B.vপাস Noneহয়, যখন B().vউদাহরণটি নিজেই পাস করে। উভয় ক্ষেত্রেই Bদ্বিতীয় যুক্তি হিসাবে পাস করা হয়।

B.v = 3অন্যদিকে, সমান type.__setattr__(B, "v", 3), যা প্রার্থনা করে না__set__

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