2011-10-06 15 views
10

मैं पाइथन में रनटाइम पर गतिशील रूप से कक्षाएं बनाना चाहता हूं।रनटाइम पर कक्षाएं बनाते समय `exec` over` type() `का उपयोग करने में क्या फायदा है?

उदाहरण के लिए, मैं नीचे दिए गए कोड को दोहराने के लिए करना चाहते हैं:

>>> class RefObj(object): 
...  def __init__(self, ParentClassName): 
...   print "Created RefObj with ties to %s" % ParentClassName 
... class Foo1(object): 
...  ref_obj = RefObj("Foo1") 
... class Foo2(object): 
...  ref_obj = RefObj("Foo2") 
... 
Created RefObj with ties to Foo1 
Created RefObj with ties to Foo2 
>>> 

... लेकिन मैं Foo1, foo2, फू कक्षाएं डायनामिक रूप से तैयार किया जाना है (यानी हैं: निष्पादन के दौरान बजाय पहले-पास पर संकलन)।

एक तरह से इस लक्ष्य को हासिल करने के लिए, type() साथ है, इसलिए जैसे:

>>> class RefObj(object): 
...  def __init__(self, ParentClassName): 
...   print "Created RefObj with ties to %s" % ParentClassName 
... def make_foo_class(index): 
...  name = "Foo%s" % index 
...  return type(name, (object,), dict(ref_obj = RefObj(name))) 
... 
>>> Foo1 = make_foo_class(1) 
Created RefObj with ties to Foo1 
>>> Foo2 = make_foo_class(2) 
Created RefObj with ties to Foo2 
>>> type(Foo1()), type(Foo2()) 
(<class 'Foo1'>, <class 'Foo2'>) 

मैं भी exec साथ इसे प्राप्त कर सकते हैं ताकि तरह:

>>> class RefObj(object): 
...  def __init__(self, ParentClassName): 
...   print "Created RefObj with ties to %s" % ParentClassName 
... def make_foo_object(index): 
...  class_template = """class Foo%(index)d(object): 
...   ref_obj = RefObj("Foo%(index)d") 
...   """ % dict(index = index) 
...  global RefObj 
...  namespace = dict(RefObj = RefObj) 
...  exec class_template in namespace 
...  return namespace["Foo%d" % index] 
... 
>>> Foo1 = make_foo_object(1) 
Created RefObj with ties to Foo1 
>>> Foo2 = make_foo_object(2) 
Created RefObj with ties to Foo2 
>>> type(Foo1()), type(Foo2()) 
(<class 'Foo1'>, <class 'Foo2'>) 

exec के उपयोग अच्छी तरह से नहीं बैठता मेरे साथ (जैसा कि मुझे उम्मीद है कि यह बहुत से लोगों के साथ नहीं है जो इस प्रश्न को पढ़ते हैं) लेकिन execबिल्कुल कैसे पाइथन collections.namedtuple() कक्षा is implemented (this line देखें)। क्लास (रेमंड हेटिंगर) के निर्माता द्वारा exechere के इस उपयोग की रक्षा भी बहुत प्रासंगिक है। इस रक्षा में, यह कहा गया है कि "नामित टुपल्स के लिए यह एक प्रमुख विशेषता है कि वे एक हाथ से लिखित कक्षा" के बराबर हैं, जो कि यह संकेत दे सकता है कि type() का उपयोग exec का उपयोग करने के समान नहीं है ...

क्या कोई अंतर है? exec बनाम type() का उपयोग क्यों करें?

मैं उम्मीद जवाब हो सकता है कि दोनों तरीकों से ही कर रहे हैं और यह बस के माध्यम से यह peppered namedtuple चर का एक बहुत है कि namedtuple कार्यान्वयन है, और के साथ ऐसा करने गतिशील बंद उत्पन्न सभी तरीकों के लिए बने कोड बोझल मिल , लेकिन मैं जानना चाहता हूं कि इसके लिए कुछ और है या नहीं।

exec के साथ मेरी असुविधा के संबंध में, मुझे पता है कि अगर अविश्वासित पक्षों के लिए घृणास्पद कोड इंजेक्ट करने के लिए कोई रास्ता नहीं है, तो यह ठीक होना चाहिए ... यह केवल यह सुनिश्चित करना है कि मुझे परेशान करता है।

+1

इस मुद्दे पर http://blog.ccpgames.com/kristjan/2011/05/28/namedtuple-and-exec/ पर भी अच्छी चर्चा है, और इसके बारे में एक और अच्छा ब्लॉग पोस्ट था मैं अब नहीं देखता आपने किसी भी कारण को प्रस्तुत नहीं किया है कि आपकी स्थिति में 'टाइप' समस्याग्रस्त क्यों है, इसलिए मुझे नहीं पता कि आप' exec 'से परेशान क्यों होंगे क्योंकि आप' प्रकार 'कार्यों को जानते हैं। (स्पष्ट रूप से जिज्ञासा के अलावा)। – agf

+0

@agf - बढ़िया लिंक, धन्यवाद! मुझे मूल रूप से 'टाइप' के साथ कोई समस्या नहीं थी, क्योंकि दोनों दृष्टिकोण काम करते हैं। मैं मतभेदों के बारे में उत्सुक था, और 'नाम' के भीतर 'निष्पादन' उपयोग के कारण को समझने की कोशिश कर रहा था। प्रस्तुत किए गए वर्ग/फ़ंक्शन हस्ताक्षर तर्क उत्कृष्ट हैं, हालांकि ... मेरे पास अक्सर सजावटी समस्याएं होती हैं जिन्हें [सजावट] (http://pypi.python.org/pypi/decorator) पैकेज के उपयोग की आवश्यकता होती है। – Russ

+0

क्या आप गतिशील वर्ग निर्माण की आवश्यकता के पीछे कारण दे सकते हैं या यह सिर्फ जिज्ञासा है? – dhill

उत्तर

2

निष्पादन पर प्रकार() का उपयोग करने का कोई नुकसान नहीं है। मुझे लगता है कि रेमंड की रक्षा थोड़ा रक्षात्मक है। आपको वह तकनीक चुननी है जिसे आप सबसे अधिक पठनीय और समझने योग्य पाते हैं। दोनों तरीकों भ्रमित कोड बनाते हैं।

आपको पहले से कक्षाएं बनाने वाले कोड से बचने के लिए वास्तव में कड़ी मेहनत करनी चाहिए, जो सबसे अच्छा होगा।

+0

@agfL क्षमा करें, मुझे यकीन नहीं है कि आप किस बात का जिक्र कर रहे हैं। –

+3

'सजावट' पुस्तकालय के लिए 'exec' के लिए तर्कों में से एक था सजाया गया कार्यों/विधियों के हस्ताक्षर को संरक्षित करना आसान था। मुझे लगता है कि यह 'नामांकित' के लिए भी एक तर्क था कि 'निष्पादन' के साथ कक्षाएं एक बार बनाई गई थीं, जैसे कि हाथ से कोडित किया गया था, जबकि 'प्रकार' के साथ वे अलग थे। – agf

+0

मैं निश्चित रूप से फ्लाई पर कक्षाएं बनाने से बचना चाहता हूं, लेकिन मुझे एक ऐसा मामला मिला है जहां मुझे वर्गों के आधार पर वर्ग विशेषताओं को बनाने की आवश्यकता है जिन्हें मैं कक्षा निर्माण से पहले इन-स्कोप में गारंटी नहीं दे सकता। गतिशील कक्षाएं इस समय सबसे सरल तरीके की तरह लगती हैं। – Russ

4

क्यों न केवल एक समारोह में कक्षा बनाते हैं?

def foo_factory(index): 
    name = 'Foo%d' % index 

    class Foo(object): 
     ref_obj = RefObj(name) 

    Foo.__name__ = name 
    return Foo 
+0

जब वास्तव में 'foo' के बारे में कुछ _dynamic_ है - आप इसे मूल रूप से हर बार बनाना नहीं चाहते हैं। – agf

+0

बेशक, यह सिर्फ एक कंकाल है। – yak

+0

कृपया दिखाएं कि आप इस तरह से 'नामांकित' या हस्ताक्षर-संरक्षित सजावट को कैसे कार्यान्वित करेंगे। यह कहकर कि "कोई भी कम लचीला नहीं है" सच नहीं है। – agf

7

मैं exec से अधिक की सिफारिश करता हूं।

वास्तव में, class बयान type के लिए एक कॉल के लिए बस वाक्यात्मक चीनी है: वर्ग शरीर की अपनी नाम स्थान है, जो तब metaclass, जो type को चूक करता है, तो कोई कस्टम metaclass निर्दिष्ट किया जाता है को दिया जाता है भीतर क्रियान्वित किया जाता।

यह दृष्टिकोण कम त्रुटिप्रणाली है क्योंकि रनटाइम पर कोड पार्स करने की कोई आवश्यकता नहीं है, और यहां तक ​​कि थोड़ा तेज़ भी हो सकता है।

+0

+1। -1 के लायक नहीं है। – agf

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

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