2012-08-01 49 views
9

टीएल; डॉ: संपत्ति सजावटी कक्षा-स्तर की फ़ंक्शन परिभाषाओं के साथ कैसे काम करते हैं, लेकिन मॉड्यूल-स्तरीय परिभाषाओं के साथ नहीं?संपत्ति सजावट केवल कक्षाओं के लिए परिभाषित क्यों है?

मैं कुछ मॉड्यूल-स्तरीय कार्यों के लिए संपत्ति सजावटी लगा रहा था, सोच रहा था कि वे मुझे केवल विशेषता लुकअप द्वारा विधियों को आमंत्रित करने की अनुमति देंगे।

यह विशेष रूप से आकर्षक था, क्योंकि मैं get_port तरह विन्यास कार्यों का एक सेट को परिभाषित किया गया था, get_hostname, आदि, जो सभी के अपने सरल, अधिक संक्षिप्त संपत्ति समकक्षों के साथ प्रतिस्थापित किया जा सकता था: port, hostname, आदि

इस प्रकार, config.get_port() सिर्फ होगा बहुत अच्छे config.port

मैं हैरान था जब मैं निम्नलिखित ट्रैसबैक पाया, साबित है कि यह एक व्यवहार्य विकल्प नहीं था:

TypeError: int() argument must be a string or a number, not 'property' 

मुझे पता था कि मैंने मॉड्यूल-स्तर पर संपत्ति जैसी कार्यक्षमता के लिए कुछ उदाहरण देखा था, क्योंकि मैंने इसे सुरुचिपूर्ण लेकिन हैकी pbs library का उपयोग करके शैल कमांड स्क्रिप्ट के लिए उपयोग किया था।

नीचे दिलचस्प दिलचस्प हैक pbs library source code में पाया जा सकता है। यह मॉड्यूल-स्तर पर संपत्ति-जैसी विशेषता लुकअप करने की क्षमता को सक्षम बनाता है, लेकिन यह बेहद खतरनाक हैकिश है।

# this is a thin wrapper around THIS module (we patch sys.modules[__name__]). 
# this is in the case that the user does a "from pbs import whatever" 
# in other words, they only want to import certain programs, not the whole 
# system PATH worth of commands. in this case, we just proxy the 
# import lookup to our Environment class 
class SelfWrapper(ModuleType): 
    def __init__(self, self_module): 
     # this is super ugly to have to copy attributes like this, 
     # but it seems to be the only way to make reload() behave 
     # nicely. if i make these attributes dynamic lookups in 
     # __getattr__, reload sometimes chokes in weird ways... 
     for attr in ["__builtins__", "__doc__", "__name__", "__package__"]: 
      setattr(self, attr, getattr(self_module, attr)) 

     self.self_module = self_module 
     self.env = Environment(globals()) 

    def __getattr__(self, name): 
     return self.env[name] 

नीचे आयात नेम स्पेस में इस वर्ग सम्मिलित करने के लिए कोड है। यह वास्तव में सीधे sys.modules पैच करता है!

# we're being run as a stand-alone script, fire up a REPL 
if __name__ == "__main__": 
    globs = globals() 
    f_globals = {} 
    for k in ["__builtins__", "__doc__", "__name__", "__package__"]: 
     f_globals[k] = globs[k] 
    env = Environment(f_globals) 
    run_repl(env) 

# we're being imported from somewhere 
else: 
    self = sys.modules[__name__] 
    sys.modules[__name__] = SelfWrapper(self) 

अब मैंने देखा है कि क्या लंबाई pbs माध्यम से जाना है, मैं सोच क्यों अजगर की इस सुविधा भाषा में सीधे नहीं ले सकता छोड़ रहा हूँ। विशेष रूप से property सजावटी ऐसी कार्यक्षमता जोड़ने के लिए एक प्राकृतिक जगह की तरह लगता है।

क्या कोई पक्षपातपूर्ण कारण या प्रेरणा है कि यह सीधे क्यों नहीं बनाया गया है?

+0

आसान खोज के लिए: अब एक मॉड्यूल है जिसे mprop कहा जाता है जो यह आपके लिए करता है https://pypi.python.org/pypi/mprop – AbdealiJK

उत्तर

7

यह दो कारकों के संयोजन से संबंधित है: पहला, कि गुण हैं descriptor protocol का उपयोग करके कार्यान्वित किया गया, और दूसरा यह है कि मॉड्यूल तत्काल कक्षाओं के बजाय हमेशा एक विशेष वर्ग के उदाहरण होते हैं।

वर्णनकर्ता प्रोटोकॉल का यह हिस्सा object.__getattribute__ में लागू किया गया है (प्रासंगिक कोड PyObject_GenericGetAttr लाइन 1319 से शुरू होता है)।देखने नियम इस तरह जाना:

  1. एक प्रकार शब्दकोश है कि name
  2. पहले मिलान के आइटम एक डेटा की जानकारी देता है, तो के लिए वर्ग mro के माध्यम से खोज, अपने __get__ फोन और वापसी उसके परिणाम
  3. तो नाम अगर वहाँ वर्ग शब्दकोशों से मिलान के आइटम था और यह एक गैर डेटा वर्णनकर्ता था, उसके __get__ फोन और परिणाम
  4. वहाँ तो लौट उदाहरण शब्दकोश में, उसके संबंधित मूल्य
  5. वापसी ई क्लास शब्दकोशों से मिलान के आइटम, यह
  6. raise AttributeError

इस के लिए महत्वपूर्ण है लौटने 3 नंबर पर था - अगर nameउदाहरण शब्दकोश में पाया जाता है (क्योंकि यह मॉड्यूल के साथ हो जाएगा), तो अपने मूल्य अभी लौटे जाएगा - यह descriptorness के लिए परीक्षण नहीं किया जाएगा, और उसके __get__ बुलाया नहीं किया जाएगा। यह इस स्थिति (अजगर 3 का उपयोग) की ओर जाता है:

>>> class F: 
... def __getattribute__(self, attr): 
...  print('hi') 
...  return object.__getattribute__(self, attr) 
... 
>>> f = F() 
>>> f.blah = property(lambda: 5) 
>>> f.blah 
hi 
<property object at 0xbfa1b0> 

आप देख सकते हैं कि .__getattribute__ है लागू किया जा रहा है, लेकिन वर्णनकर्ता के रूप में f.blah इलाज नहीं है।

यह संभावना है कि इस तरह से संरचित किए जाने वाले नियमों का कारण उदाहरणों (और इसलिए, मॉड्यूल में) और अतिरिक्त कोड जटिलता के कारण वर्णनी को अनुमति देने की उपयोगिता के बीच एक स्पष्ट व्यापार है।

+0

यह वास्तव में सहायक है, धन्यवाद! – mvanveen

+1

गैर-डेटा वर्णनकर्ता से डेटा डिस्क्रिप्टर को क्या अंतर करता है? – mvanveen

+2

@mvanveen जवाब में 'वर्णनकर्ता प्रोटोकॉल' लिंक से:। "एक वस्तु को परिभाषित करता है, तो दोनों' __get __() 'और' __set __() ', यह एक डेटा वर्णनकर्ता माना जाता है वर्णनकर्ता है कि केवल परिभाषित' __get __() 'कहा जाता है गैर-डेटा वर्णनकर्ता "। – lvc

0

गुण कक्षाओं (विशेष रूप से नई शैली कक्षाओं) के लिए विशिष्ट विशेषता है, इसलिए विस्तार से संपत्ति सजावट केवल वर्ग विधियों पर लागू किया जा सकता है।

एक नई शैली के वर्ग एक है कि वस्तु से निकला है, यानी वर्ग फू (वस्तु):

आगे की जानकारी: Can modules have properties the same way that objects can?

+4

जो भी आप कहते हैं वह सत्य है, लेकिन स्पष्ट रूप से उल्लेख करना महत्वपूर्ण है कि मॉड्यूल कक्षाएं नहीं हैं । वे उदाहरण हैं ("मॉड्यूल" प्रकार)। – BrenBarn

+0

धन्यवाद, यह बहुत मदद करता है, लेकिन मैं अभी भी उलझन में हूँ! मैं समझता हूँ कि एक मॉड्यूल 'ModuleType' का एक उदाहरण है, लेकिन मैं अभी भी मुसीबत क्यों' property' बर्ताव करता है के रूप में यह होता है के लिए प्रेरणा लोभी हो रहा है। पढ़ना [इस] (http://www.cafepy.com/article/python_types_and_objects/python_types_and_objects.html#object-type-example) मददगार साबित हो रहा है, लेकिन तथ्य यह है कि मैं उपवर्ग कर सकते हैं 'ModuleType' यह संभव प्रतीत बनाता है ... यह तथ्य है कि आपको सीधे 'sys.modules' को पैच करना होगा और यह सबकुछ स्वयं करना होगा जो हैकिश लगता है। – mvanveen