2009-11-14 1 views
25

में क्लास-स्तरीय रीड-ओनली प्रॉपर्टीज Python में क्लास-स्तरीय रीड-ओनली प्रॉपर्टी बनाने का कोई तरीका है?पायथन

x = Foo.CLASS_PROPERTY 

लेकिन कहने से किसी को रोकने के: उदाहरण के लिए, अगर मैं एक वर्ग Foo है, मैं कहना चाहता हूँ

Foo.CLASS_PROPERTY = y 

संपादित करें: मैं Alex Martelli's solution की सादगी पसंद है, लेकिन नहीं वाक्यविन्यास है कि इसकी आवश्यकता है। दोनों अपने और ~unutbu's answer रों निम्नलिखित समाधान है, जो करीब की भावना करने के लिए है कि मैं क्या तलाश कर रहा था प्रेरित:

class const_value (object): 
    def __init__(self, value): 
     self.__value = value 

    def make_property(self): 
     return property(lambda cls: self.__value) 

class ROType(type): 
    def __new__(mcl,classname,bases,classdict): 
     class UniqeROType (mcl): 
      pass 

     for attr, value in classdict.items(): 
      if isinstance(value, const_value): 
       setattr(UniqeROType, attr, value.make_property()) 
       classdict[attr] = value.make_property() 

     return type.__new__(UniqeROType,classname,bases,classdict) 

class Foo(object): 
    __metaclass__=ROType 
    BAR = const_value(1) 
    BAZ = 2 

class Bit(object): 
    __metaclass__=ROType 
    BOO = const_value(3) 
    BAN = 4 

अब, मैं मिलता है:

Foo.BAR 
# 1 
Foo.BAZ 
# 2 
Foo.BAR=2 
# Traceback (most recent call last): 
# File "<stdin>", line 1, in <module> 
# AttributeError: can't set attribute 
Foo.BAZ=3 
# 

मैं इस समाधान क्योंकि पसंद करते हैं:

  • सदस्यों इस तथ्य के बाद के बजाय इनलाइन घोषित करने के साथ के रूप में, type(X).foo = ...
  • सदस्यों के मान मेटाक्लास के कोड के विपरीत वास्तविक वर्ग के कोड में सेट हैं।

    • मैं के लिए const_value वस्तुओं को सही ढंग से व्याख्या की जा करने के लिए __metaclass__ सेट करने के लिए:

    यह क्योंकि अभी भी नहीं आदर्श है।

  • const_value एस सादा मूल्यों की तरह "व्यवहार" नहीं करते हैं। उदाहरण के लिए, मैं कक्षा में किसी विधि के पैरामीटर के लिए इसे डिफ़ॉल्ट मान के रूप में उपयोग नहीं कर सका।
+2

कोई भी कभी भी Foo.CLASS_PROPERTY सेट करने का प्रयास क्यों करेगा? यह सैद्धांतिक उदाहरण को रोकने के लिए योजना पर सादगी चुनने के लिए पाइथन में सामान्य शैली है जहां कोई बेवकूफ कुछ करता है। लोगों को अपने कोड के साथ बेवकूफ सामान करने से रोकने के लिए आप कुछ भी नहीं कर सकते हैं। –

+0

@ माइक: आप सही हैं; सामान्य ज्ञान लोगों को इन गुणों को संशोधित नहीं करने के लिए कहता है। और फिर भी, कभी-कभी, वे संशोधित हो जाते हैं। यही कारण है कि मैं इसे वर्तनी के लिए पसंद करता हूं (सभी कैप्स के मुकाबले अधिक स्पष्ट रूप से)। निजी सदस्यों का उपयोग करने के समान ही तर्क। स्पष्ट इंटरफेस अच्छे हैं। मुझे गलत मत समझो: मुझे सादगी भी पसंद है। अगर मैं इसके लिए कुछ अंतर्निहित सुविधा (जैसे @classproperty सजावट या कुछ) की तरह था तो मैं बहुत पसंद करूंगा। जैसा कि है, मुझे यह भी यकीन नहीं है कि मैं उपर्युक्त समाधान का उपयोग करूंगा यदि इसे हर बार '__metaclass__' सेट करने की आवश्यकता होती है। ऑल-कैप्स अब के लिए जीत सकते हैं। भविष्य से लोगों को – mjumbewu

+2

नोट: आधुनिक अजगर संस्करण 'उपयोग कर सकते हैं नई शैली की कक्षाओं में @ property': http://docs.python.org/library/functions.html#property –

उत्तर

1

ActiveState पर इस मिला:

# simple read only attributes with meta-class programming 

# method factory for an attribute get method 
def getmethod(attrname): 
    def _getmethod(self): 
     return self.__readonly__[attrname] 

    return _getmethod 

class metaClass(type): 
    def __new__(cls,classname,bases,classdict): 
     readonly = classdict.get('__readonly__',{}) 
     for name,default in readonly.items(): 
      classdict[name] = property(getmethod(name)) 

     return type.__new__(cls,classname,bases,classdict) 

class ROClass(object): 
    __metaclass__ = metaClass 
    __readonly__ = {'a':1,'b':'text'} 


if __name__ == '__main__': 
    def test1(): 
     t = ROClass() 
     print t.a 
     print t.b 

    def test2(): 
     t = ROClass() 
     t.a = 2 

    test1() 

ध्यान दें कि अगर आप केवल पढ़ने के लिए विशेषता सेट करने का प्रयास (t.a = 2) अजगर एक AttributeError बढ़ा देंगे।

+0

इस उदाहरण स्तर संपत्तियों के लिए काम करता है, लेकिन नहीं वर्ग-स्तर (यानी मैं अभी भी यह नहीं कह सकता 'ROClass.a' और उम्मीद मान' होने की 1')। – mjumbewu

4

ActiveState solution कि Pynt संदर्भ ROClass के उदाहरणों को केवल-पढ़ने योग्य गुण हैं। आपका प्रश्न यह पूछता है कि कक्षा में केवल पढ़ने-योग्य गुण हो सकते हैं या नहीं।

यहाँ पर Raymond Hettinger's comment आधारित एक तरीका है,: विचार पहले रेमंड Hettinger के समाधान:

class Bar(object): 
    CLASS_PROPERTY = property(lambda self: 1) 
bar=Bar() 
bar.CLASS_PROPERTY=2 

यह बार एक पढ़ा देने के लिए एक अपेक्षाकृत सरल रास्ता दिखाता है

#!/usr/bin/env python 
def readonly(value): 
    return property(lambda self: value) 

class ROType(type): 
    CLASS_PROPERTY = readonly(1) 

class Foo(object): 
    __metaclass__=ROType 

print(Foo.CLASS_PROPERTY) 
# 1 

Foo.CLASS_PROPERTY=2 
# AttributeError: can't set attribute 

विचार यह है केवल संपत्ति

ध्यान दें कि आपको बार की कक्षा की परिभाषा के लिए CLASS_PROPERTY = property(lambda self: 1) लाइन जोड़नी है, न कि खुद को बार।

तो, यदि आप केवल पढ़ने योग्य संपत्ति रखने के लिए Foo कक्षा चाहते हैं, तो Foo के मूल वर्ग को CLASS_PROPERTY = property(lambda self: 1) परिभाषित किया जाना चाहिए।

कक्षा का मूल वर्ग एक मेटाक्लास है।

class ROType(type): 
    CLASS_PROPERTY = readonly(1) 

फिर हम फू की मूल वर्ग ROType हो बनाने: इसलिए हम metaclass रूप ROType परिभाषित

class Foo(object): 
    __metaclass__=ROType 
+0

अब मैं टिप्पणियों को ध्यान से पढ़ने के लिए मूर्ख नहीं हूं>। < –

8

मौजूदा समाधान थोड़ा जटिल हैं - क्या सिर्फ यह सुनिश्चित करने के बारे में है कि एक निश्चित में प्रत्येक वर्ग समूह में एक अद्वितीय मेटाक्लास है, फिर कस्टम मेटाक्लास पर सामान्य पढ़ने-योग्य संपत्ति सेट करना। अर्थात्:

>>> class Meta(type): 
... def __new__(mcl, *a, **k): 
...  uniquemcl = type('Uniq', (mcl,), {}) 
...  return type.__new__(uniquemcl, *a, **k) 
... 
>>> class X: __metaclass__ = Meta 
... 
>>> class Y: __metaclass__ = Meta 
... 
>>> type(X).foo = property(lambda *_: 23) 
>>> type(Y).foo = property(lambda *_: 45) 
>>> X.foo 
23 
>>> Y.foo 
45 
>>> 

यह वास्तव में बहुत सरल है, क्योंकि यह तथ्य यह है कि जब आप प्राप्त एक उदाहरण के गुण वर्णनकर्ता निश्चित रूप से (ताकि वर्ग पर देखा जाता है जब आप एक वर्ग के गुण वर्णनकर्ता हैं पाने से ज्यादा कुछ नहीं पर आधारित है मेटाक्लास पर देखा), और वर्ग/मेटाक्लास अद्वितीय बनाना बहुत मुश्किल नहीं है।

ओह, और निश्चित रूप से:

>>> X.foo = 67 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: can't set attribute 

बस केवल पढ़ने के लिए यह वास्तव में है पुष्टि करने के लिए!