আমি অসীম পুনরাবৃত্তি ত্রুটি না করে কীভাবে __getattribute__ প্রয়োগ করব?


104

আমি ক্লাসে একটি ভেরিয়েবলের অ্যাক্সেসকে ওভাররাইড করতে চাই, তবে অন্য সবগুলিকে সাধারণত ফিরে আসি। আমি কীভাবে এটি সম্পাদন করব __getattribute__?

আমি নিম্নলিখিতগুলি চেষ্টা করেছিলাম (যা আমি কী করতে চাইছি তাও বোঝানো উচিত) তবে আমি পুনরাবৃত্তি ত্রুটি পেয়েছি:

class D(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self,name):
        if name=='test':
            return 0.
        else:
            return self.__dict__[name]

>>> print D().test
0.0
>>> print D().test2
...
RuntimeError: maximum recursion depth exceeded in cmp

উত্তর:


130

কারণ অ্যাক্সেস করতে আপনার প্রচেষ্টাটি আপনি একটি পুনরাবৃত্তির ভুল পান self.__dict__অ্যাট্রিবিউট ভিতরে __getattribute__আপনার ডাকে __getattribute__আবার। আপনি যদি objectএর __getattribute__পরিবর্তে ব্যবহার করেন তবে এটি কাজ করে:

class D(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self,name):
        if name=='test':
            return 0.
        else:
            return object.__getattribute__(self, name)

এটি কাজ করে কারণ object(এই উদাহরণে) বেস ক্লাস। আপনার বেস সংস্করণে কল করে __getattribute__আপনি পূর্বে যে পুনরাবৃত্তি হচ্ছিল তা এড়াতে পারেন।

Foo.py এ কোড সহ আইপাইথন আউটপুট:

In [1]: from foo import *

In [2]: d = D()

In [3]: d.test
Out[3]: 0.0

In [4]: d.test2
Out[4]: 21

হালনাগাদ:

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


4
মজাদার. তাহলে আপনি সেখানে কি করছেন? আমার ভেরিয়েবলগুলি কেন আপত্তি করবে?
গ্রেগ

4
.. এবং আমি কি সর্বদা অবজেক্টটি ব্যবহার করতে চাই? আমি অন্য শ্রেণি থেকে উত্তরাধিকারী যদি?
গ্রেগ

4
হ্যাঁ, প্রতিবার যখন আপনি একটি ক্লাস তৈরি করেন এবং আপনি নিজের লেখেন না, আপনি বস্তুর দ্বারা সরবরাহিত গেটট্রিবিউট ব্যবহার করেন ।
ডিম

20
সুপার () ব্যবহার করা ভাল নয় এবং এভাবে আপনার বেস ক্লাসগুলিতে পাওয়া প্রথম গেটট্রিবিউট পদ্ধতিটি পাইথন ব্যবহার করুন ? -super(D, self).__getattribute__(name)
জিপেটিনো

10
অথবা আপনি কেবল super().__getattribute__(name)পাইথন 3 এ ব্যবহার করতে পারেন
jeromej

26

আসলে, আমি বিশ্বাস করি আপনি এর __getattr__পরিবর্তে বিশেষ পদ্ধতিটি ব্যবহার করতে চান ।

পাইথন ডক্সের উদ্ধৃতি:

__getattr__( self, name)

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

দ্রষ্টব্য: এটি কাজ করার জন্য, উদাহরণটির কোনও বৈশিষ্ট্য থাকা উচিত নয়test , তাই লাইনটি self.test=20সরানো উচিত।


4
বাস্তবিক, অপ এর কোড প্রকৃতি অনুযায়ী, ওভার-রাইড __getattr__জন্য testবেহুদা, হতে থেকে এটা সবসময় এটি "স্বাভাবিক স্থানে" খুঁজে যাবে।
কেসি কুবাল

4
প্রাসঙ্গিক পাইথন ডক্সের বর্তমান লিঙ্ক (উত্তরটি উল্লেখ করা থেকে আলাদা বলে মনে হচ্ছে): ডকস.পিথথন.আর
/

18

পাইথন ভাষার উল্লেখ:

এই পদ্ধতিতে অসীম পুনরাবৃত্তি এড়ানোর জন্য, এর প্রয়োগকরণের সর্বদা প্রয়োজন নামের কোনও বৈশিষ্ট্য অ্যাক্সেস করার জন্য একই নামের সাথে বেস বর্গ পদ্ধতিটি কল করা উচিত, উদাহরণস্বরূপ object.__getattribute__(self, name),।

অর্থ:

def __getattribute__(self,name):
    ...
        return self.__dict__[name]

আপনি ডাকা একটি বৈশিষ্ট্য জন্য কল করছি __dict__। কারণ এটি একটি বৈশিষ্ট্য, __getattribute__অনুসন্ধানে __dict__কল হয় __getattribute__যা কল করে যেগুলি কল করে ... যাদা ইয়াদা ইয়াদা ada

return  object.__getattribute__(self, name)

বেস ক্লাসগুলি ব্যবহার করা __getattribute__আসল বৈশিষ্ট্যটি সন্ধান করতে সহায়তা করে।


13

আপনি কি ব্যবহারের বিষয়ে নিশ্চিত __getattribute__? আপনি আসলে কী অর্জন করার চেষ্টা করছেন?

আপনি যা চান তা করার সহজ উপায় হ'ল:

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21

    test = 0

বা:

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21

    @property
    def test(self):
        return 0

সম্পাদনা করুন: নোট করুন যে একটি উদাহরণের প্রতিটি ক্ষেত্রে Dআলাদা আলাদা মান থাকবে test। প্রথম ক্ষেত্রে d.test20 হবে, দ্বিতীয়টি এটি 0 হবে I'll আমি এটি কাজ করার জন্য এটি আপনার কাছে রেখে দেব।

সম্পাদনা 2: গ্রেগ নির্দেশ করেছেন যে উদাহরণ 2 ব্যর্থ হবে কারণ সম্পত্তিটি কেবল পঠিত হয় এবং __init__পদ্ধতিটি এটি 20 এ সেট করার চেষ্টা করেছিল that এর জন্য আরও একটি সম্পূর্ণ উদাহরণ হ'ল :

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21

    _test = 0

    def get_test(self):
        return self._test

    def set_test(self, value):
        self._test = value

    test = property(get_test, set_test)

স্পষ্টতই, একটি শ্রেণি হিসাবে এটি প্রায় সম্পূর্ণরূপে অকেজো, তবে এটি আপনাকে এগিয়ে যাওয়ার জন্য একটি ধারণা দেয়।


ওহ, আপনি ক্লাস চালানোর সময় নিরব কাজ করেন না, না? ফাইল "Script1.py", লাইন 5, মধ্যে Init self.test = 20 AttributeError: অ্যাট্রিবিউট সেট করতে পারে না
গ্রেগ

সত্য। আমি এটি তৃতীয় উদাহরণ হিসাবে ঠিক করব ভাল বিক্ষোভ.
একক

6

__getattribute__পদ্ধতিটি কীভাবে ব্যবহৃত হয়?

এটি সাধারণ ডটেড লুকআপের আগে ডাকা হয়। যদি এটি উত্থাপিত হয় AttributeError, তবে আমরা কল করি __getattr__

এই পদ্ধতির ব্যবহার বরং বিরল। স্ট্যান্ডার্ড লাইব্রেরিতে কেবল দুটি সংজ্ঞা রয়েছে:

$ grep -Erl  "def __getattribute__\(self" cpython/Lib | grep -v "/test/"
cpython/Lib/_threading_local.py
cpython/Lib/importlib/util.py

ভাল অভ্যাস

প্রোগ্রামটিমেটিকভাবে একটি একক বৈশিষ্ট্যে অ্যাক্সেস নিয়ন্ত্রণের সঠিক উপায়টি রয়েছে property। ক্লাসটি Dনিম্নরূপে লিখতে হবে (স্পষ্টতাত্ত্বিক আচরণের প্রতিলিপি তৈরির জন্য সেটার এবং মুছে ফেলার সাথে):

class D(object):
    def __init__(self):
        self.test2=21

    @property
    def test(self):
        return 0.

    @test.setter
    def test(self, value):
        '''dummy function to avoid AttributeError on setting property'''

    @test.deleter
    def test(self):
        '''dummy function to avoid AttributeError on deleting property'''

এবং ব্যবহার:

>>> o = D()
>>> o.test
0.0
>>> o.test = 'foo'
>>> o.test
0.0
>>> del o.test
>>> o.test
0.0

একটি সম্পত্তি হ'ল ডেটা বর্ণনাকারী, সুতরাং সাধারণ বিন্দুযুক্ত লুকোচুরি অ্যালগরিদমে এটি প্রথম জিনিসটির সন্ধান করা হয়।

জন্য বিকল্প __getattribute__

আপনার একেবারে প্রতিটি অ্যাট্রিবিউটের মাধ্যমে অনুসন্ধানের বাস্তবায়ন করতে হবে যদি আপনি বেশ কয়েকটি বিকল্প __getattribute__

  • উত্থাপন AttributeError, __getattr__ডেকে আনা কারণ (যদি প্রয়োগ করা হয়)
  • এটি থেকে কিছু ফিরে
    • superপিতামাতাকে (সম্ভবত objectএর) বাস্তবায়ন কল করতে ব্যবহার করে
    • কলিং __getattr__
    • আপনার নিজের বিন্দুযুক্ত অনুসন্ধানের অ্যালগরিদমটি কোনওভাবে বাস্তবায়ন করা হচ্ছে

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

class NoisyAttributes(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self, name):
        print('getting: ' + name)
        try:
            return super(NoisyAttributes, self).__getattribute__(name)
        except AttributeError:
            print('oh no, AttributeError caught and reraising')
            raise
    def __getattr__(self, name):
        """Called if __getattribute__ raises AttributeError"""
        return 'close but no ' + name    


>>> n = NoisyAttributes()
>>> nfoo = n.foo
getting: foo
oh no, AttributeError caught and reraising
>>> nfoo
'close but no foo'
>>> n.test
getting: test
20

আপনি মূলত যা চেয়েছিলেন

এবং এই উদাহরণটি দেখায় যে আপনি কী করতে পারেন মূলত:

class D(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self,name):
        if name=='test':
            return 0.
        else:
            return super(D, self).__getattribute__(name)

এবং এইরকম আচরণ করবে:

>>> o = D()
>>> o.test = 'foo'
>>> o.test
0.0
>>> del o.test
>>> o.test
0.0
>>> del o.test

Traceback (most recent call last):
  File "<pyshell#216>", line 1, in <module>
    del o.test
AttributeError: test

কোড পূনর্বিবেচনা

মন্তব্য সহ আপনার কোড। আপনার নিজের মধ্যে বিন্দু চেহারা আছে __getattribute__। এই কারণেই আপনি পুনরাবৃত্তি ত্রুটি পান। আপনি নামটি কিনা তা পরীক্ষা করে দেখতে পারেন "__dict__"এবং এই ব্যবহারটি ব্যবহার superকরতে পারেন তবে এটি কভার করে না __slots__। আমি পাঠকের কাছে অনুশীলন হিসাবে রেখে দেব।

class D(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self,name):
        if name=='test':
            return 0.
        else:      #   v--- Dotted lookup on self in __getattribute__
            return self.__dict__[name]

>>> print D().test
0.0
>>> print D().test2
...
RuntimeError: maximum recursion depth exceeded in cmp

5

এখানে একটি আরও নির্ভরযোগ্য সংস্করণ:

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21
    def __getattribute__(self, name):
        if name == 'test':
            return 0.
        else:
            return super(D, self).__getattribute__(name)

এটি অভিভাবক শ্রেণীর কাছ থেকে __ getattribute __ পদ্ধতি কল করে , অবশেষে আপত্তিতে ফিরে যায়। অন্যান্য পূর্বপুরুষ যদি এটিকে ওভাররাইড না করে তবে __ getattribute __ পদ্ধতি।

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