2012-05-03 9 views
8

आमतौर पर पायथन डिस्क्रिप्टर को वर्ग विशेषताओं के रूप में परिभाषित किया जाता है। लेकिन मेरे मामले में, मैं चाहता हूं कि प्रत्येक ऑब्जेक्ट इंस्टेंस में अलग-अलग सेट डिस्क्रिप्टर हों जो इनपुट पर निर्भर करता है। उदाहरण के लिए:प्रति-आवृत्ति संपत्ति वर्णनकर्ता बनाएं?

class MyClass(object): 
    def __init__(self, **kwargs): 
    for attr, val in kwargs.items(): 
     self.__dict__[attr] = MyDescriptor(val) 

प्रत्येक वस्तु विशेषताओं इन्स्टेन्शियशन समय में निर्णय लिया जाता है के विभिन्न सेट है कर रहे हैं। चूंकि ये एक-ऑफ ऑब्जेक्ट्स हैं, इसलिए पहले उन्हें उप-वर्ग करना सुविधाजनक नहीं है।

tv = MyClass(type="tv", size="30") 
smartphone = MyClass(type="phone", os="android") 

tv.size # do something smart with the descriptor 

ऑब्जेक्ट को डिस्क्रिप्टर असाइन करना काम नहीं लगता है। अगर मैं विशेषता तक पहुंचने का प्रयास करता हूं, तो मुझे

<property at 0x4067cf0> 

क्या आपको पता है कि यह क्यों काम नहीं कर रहा है? क्या कोई काम आसपास है?

+0

अतिसंवेदनशील वर्णनकर्ताओं के साथ MyClass के विभिन्न उप-वर्गों का उपयोग क्यों नहीं करते? – KurzedMetal

+0

अधिक उदाहरण जोड़ने के लिए संपादित किया गया। मुझे लगता है कि प्रति-उदाहरण वर्णनकर्ता बस नहीं किया जा सकता है। मैंने __getattr__ का उपयोग कर इसके आसपास काम किया है। फिर भी अंतर्निहित भाषा बाधा को समझ में नहीं आता है। –

+0

वर्णनकर्ता केवल कक्षा स्तर पर काम करते हैं, क्षमा करें। –

उत्तर

2

यह काम नहीं कर रहा है क्योंकि आपको ऑब्जेक्ट के वर्ग में वर्णक असाइन करना होगा।

class Descriptor: 

    def __get__(...): 
     # this is called when the value is got 

    def __set__(... 
    def __del__(... 

अगर आप

obj.attr 
=> type(obj).__getattribute__(obj, 'attr') is called 
=> obj.__dict__['attr'] is returned if there else: 
=> type(obj).__dict__['attr'] is looked up 
if this contains a descriptor object then this is used. 

बारे में तो यह क्योंकि प्रकार dictionairy वर्णनकर्ता के लिए ऊपर देखा और न वस्तु dictionairy है काम नहीं करता।

  1. वर्ग में वर्णनकर्ता रखा है और उसे जैसे का उपयोग करें:

    संभव काम arounds देखते हैं मूल्य स्टोर करने के लिए obj.xxxattr। यदि यह केवल एक वर्णक व्यवहार है तो यह काम करता है।

  2. setattr और getattr और delattr के ऊपर लिख discriptors पर प्रतिक्रिया के लिए।

  3. कक्षा में एक वर्णक डाल दिया जो ऑब्जेक्ट डिक्शनरी में संग्रहीत वर्णनकर्ताओं का जवाब देता है।

2

आप गलत तरीके से वर्णनकर्ताओं का उपयोग कर रहे हैं।

वर्णनकर्ता एक उदाहरण स्तर पर समझ में नहीं आता है। सभी __get__/__set__ विधियों के बाद कक्षा के instance तक पहुंच प्रदान करें।

यह जानने के बिना कि आप वास्तव में क्या करना चाहते हैं, मैं सुझाव देता हूं कि आप प्रति कॉलर तर्क को __set__ विधि के अंदर तर्क दें, "कॉलर/इंस्टेंस" कौन है और उसके अनुसार कार्य करें।

अन्यथा हमें बताएं कि आप क्या हासिल करने की कोशिश कर रहे हैं, ताकि हम वैकल्पिक समाधान का प्रस्ताव दे सकें।

1

कारण यह काम नहीं कर रहा है, क्योंकि अजगर वर्णनकर्ता के लिए केवल चेकों जब तक गुण वर्ग पर देख, उदाहरण पर नहीं करने के लिए एक यूज़-केस की तरह दिखता है; सवाल में तरीके हैं:

यह आदेश उदाहरणों के साथ ही वर्गों पर descriptor protocol को लागू करने में अपनी कक्षा पर उन तरीकों को ओवरराइड करने के लिए संभव है:

# do not use in production, example code only, needs more checks 
class ClassAllowingInstanceDescriptors(object): 
    def __delattr__(self, name): 
     res = self.__dict__.get(name) 
     for method in ('__get__', '__set__', '__delete__'): 
      if hasattr(res, method): 
       # we have a descriptor, use it 
       res = res.__delete__(name) 
       break 
     else: 
      res = object.__delattr__(self, name) 
     return res 
    def __getattribute__(self, *args): 
     res = object.__getattribute__(self, *args) 
     for method in ('__get__', '__set__', '__delete__'): 
      if hasattr(res, method): 
       # we have a descriptor, call it 
       res = res.__get__(self, self.__class__) 
     return res 
    def __setattr__(self, name, val): 
     # check if object already exists 
     res = self.__dict__.get(name) 
     for method in ('__get__', '__set__', '__delete__'): 
      if hasattr(res, method): 
       # we have a descriptor, use it 
       res = res.__set__(self, val) 
       break 
     else: 
      res = object.__setattr__(self, name, val) 
     return res 
    @property 
    def world(self): 
     return 'hello!' 

जब ऊपर वर्ग नीचे के रूप में प्रयोग किया जाता है:

huh = ClassAllowingInstanceDescriptors() 
print(huh.world) 
huh.uni = 'BIG' 
print(huh.uni) 
huh.huh = property(lambda *a: 'really?') 
print(huh.huh) 
print('*' * 50) 
try: 
    del huh.world 
except Exception, e: 
    print(e) 
print(huh.world) 
print('*' * 50) 
try: 
    del huh.huh 
except Exception, e: 
    print(e) 
print(huh.huh) 

परिणाम हैं:

हैलो!

बिग

वास्तव में?


विशेषता

हैलो को नष्ट नहीं कर सकते हैं!


विशेषता नहीं हटा सकते

वास्तव में?

1

मैं गतिशील रूप से exec द्वारा बनाई गई कक्षा में उदाहरण बनाते हैं। यह आपके उपयोग के मामले के अनुरूप हो सकता है।

def make_myclass(**kwargs): 

    class MyDescriptor(object): 
     def __init__(self, val): 
      self.val = val 

     def __get__(self, obj, cls): 
      return self.val 

     def __set__(self, obj, val): 
      self.val = val 

    cls = 'class MyClass(object):\n{}'.format('\n'.join(' {0} = MyDescriptor({0})'.format(k) for k in kwargs)) 

    #check if names in kwargs collide with local names 
    for key in kwargs: 
     if key in locals(): 
      raise Exception('name "{}" collides with local name'.format(key)) 

    kwargs.update(locals()) 
    exec(cls, kwargs, locals()) 
    return MyClass() 

टेस्ट;

In [577]: tv = make_myclass(type="tv", size="30") 

In [578]: tv.type 
Out[578]: 'tv' 

In [579]: tv.size 
Out[579]: '30' 

In [580]: tv.__dict__ 
Out[580]: {} 

लेकिन उदाहरण अलग-अलग वर्ग के हैं।

In [581]: phone = make_myclass(type='phone') 

In [582]: phone.type 
Out[582]: 'phone' 

In [583]: tv.type 
Out[583]: 'tv' 

In [584]: isinstance(tv,type(phone)) 
Out[584]: False 

In [585]: isinstance(phone,type(tv)) 
Out[585]: False 

In [586]: type(tv) 
Out[586]: MyClass 

In [587]: type(phone) 
Out[587]: MyClass 

In [588]: type(phone) is type(tv) 
Out[588]: False 
+0

अच्छी तरफ, प्रदर्शन [मेरे उत्तर] से बेहतर होगा (http://stackoverflow.com/a/35657853/208880); नीचे की तरफ, उदाहरण एक ही कक्षा नहीं हैं, और भ्रम हो सकता है क्योंकि उनके सभी का एक ही वर्ग का नाम है। फिर भी, उचित परिस्थितियों में एक अच्छा समाधान। –

संबंधित मुद्दे