2009-02-26 12 views
8

क्या एक सजावट लिखने का कोई तरीका है जैसे कि निम्नलिखित काम करेगा?क्या मैं पाइथन में किसी फ़ंक्शन के स्थानीय दायरे को बदलने के लिए सजावट का उपयोग कर सकता हूं?

assert 'z' not in globals() 

@my_decorator 
def func(x, y): 
    print z 

संपादित करें: वाक्य रचना चीनी/सूखी: हॉप की "? क्यों" करने के लिए anwser

से चले गए जवाब में।

यह कैशिंग के बारे में नहीं है, यह x & y के मानों के आधार पर z (और z1, z2, z3, ...) की गणना करने के बारे में है।

मैं कार्य करता है जो संबंधित बातें करते हैं के बहुत सारे है, और मैं ऐसा नहीं करना चाहता हर एक समारोह की शुरुआत में

z1, z2, z3=calculate_from(x, y) 

लिखने के लिए है - क्या मैं कहीं गलत यह मिल जाएगा। अगर यह सी था तो मैं इसे सीपीपी के साथ करूँगा (अगर यह लापरवाह था, तो मैं मैक्रोज़ के साथ ऐसा करूँगा ...), लेकिन मैं देखना चाहता था कि सजावटी एक ही काम कर सकते हैं या नहीं।

यदि यह मदद करता है, तो मैं लगभग निश्चित रूप से सजावटी "precalculate_z" को कॉल करता हूं, और यह निश्चित रूप से किसी भी सार्वजनिक एपीआई का हिस्सा नहीं होगा।

मैं शायद के साथ-साथ विश्वस्तरीय अधोसंरचना का उपयोग करने से एक समान प्रभाव हो सकता है, लेकिन मैं यह देखने के लिए अगर यह कच्चे कार्यों के साथ संभव था चाहता था।

+0

मुझे यकीन नहीं है कि आप यहां क्या करने की कोशिश कर रहे हैं - यदि 'z' न तो वैश्विक है और न ही कोई फ़ंक्शन तर्क है, तो यह कहां से आता है? या आप 'z' स्थिर बनाना चाहते हैं? पायथन सी-शैली स्थिर चर का समर्थन नहीं करता है, लेकिन आप अपने कार्य को कक्षा में डालकर एक ही चीज़ को पूरा कर सकते हैं। –

+0

मुझे विश्वास है कि वह पूछ रहा है कि 'my_decorator' स्थानीय चर को उस समारोह के शरीर में इंजेक्ट कर सकता है जो इसे सजा रहा है। – Aaron

उत्तर

11

गूंज हॉप के जवाब

  1. ऐसा मत करो।
  2. गंभीरता से, ऐसा मत करो। लिस्प और रूबी अपने स्वयं के कस्टम वाक्यविन्यास लिखने के लिए अधिक उपयुक्त भाषाएं हैं। उनमें से एक का प्रयोग करें। या यह
  3. करने के लिए एक क्लीनर तरीका ढूंढें यदि आपको जरूरी है, तो आप गतिशील स्कॉप्ड वेरिएबल्स चाहते हैं, न कि स्पष्ट रूप से स्कॉप्ड।

पायथन में गतिशील रूप से स्केल किए गए चर नहीं हैं, लेकिन आप इसे अनुकरण कर सकते हैं। यहाँ एक उदाहरण है कि यह एक वैश्विक बाध्यकारी बनाने के द्वारा simulates है, लेकिन बाहर निकलने पर पिछले मान पुनर्स्थापित करता है:

http://codepad.org/6vAY8Leh

def adds_dynamic_z_decorator(f): 
    def replacement(*arg,**karg): 
    # create a new 'z' binding in globals, saving previous 
    if 'z' in globals(): 
     oldZ = (globals()['z'],) 
    else: 
     oldZ = None 
    try: 
     globals()['z'] = None 
     #invoke the original function 
     res = f(*arg, **karg) 
    finally: 
     #restore any old bindings 
     if oldZ: 
     globals()['z'] = oldZ[0] 
     else: 
     del(globals()['z']) 
    return res 
    return replacement 

@adds_dynamic_z_decorator 
def func(x,y): 
    print z 

def other_recurse(x): 
    global z 
    print 'x=%s, z=%s' %(x,z) 
    recurse(x+1) 
    print 'x=%s, z=%s' %(x,z) 

@adds_dynamic_z_decorator 
def recurse(x=0): 
    global z 
    z = x 
    if x < 3: 
    other_recurse(x) 

print 'calling func(1,2)' 
func(1,2) 

print 'calling recurse()' 
recurse() 

मैं उपयोगिता या इसके बाद के कोड के विवेक पर कोई वारंटी देते हैं। दरअसल, मैं वारंट करता हूं कि पागल है, और जब तक आप अपने पायथन सहकर्मियों से फ़्लॉगिंग नहीं करना चाहते हैं, तब तक इसका उपयोग करना चाहिए।

यह कोड eduffy और जॉन मॉन्टगोमेरी के कोड दोनों के समान है, लेकिन यह सुनिश्चित करता है कि 'z' बनाया गया है और स्थानीय चर के रूप में ठीक तरह से पुनर्स्थापित किया जाएगा - उदाहरण के लिए, ध्यान दें कि 'other_recurse' कैसे देख सकता है 'रिकर्स' के शरीर में निर्दिष्ट 'जेड' के लिए बाध्यकारी।

+1

धन्यवाद - यह वही करेगा जो मैं चाहता था; लेकिन मैं निश्चित रूप से इसका उपयोग नहीं करूँगा। लेकिन कम से कम मेरी जिज्ञासा अब संतुष्ट है! मैं था अभी भी एक तरह से मेरी कॉपी/पेस्ट मुद्दे से बचने के कुछ प्रकार पर प्राप्त करने के लिए है, लेकिन मुझे यकीन है कि कैसे अभी तक नहीं कर रहा हूँ की तरह - मैं कुछ और चारों ओर चलने लगेगा। –

+1

दिलचस्प है लेकिन मुझे आश्चर्य है कि इस ब्रेक का उपयोग पायथन में कुछ भी होगा? – smci

+0

यदि आप इसका उपयोग करने का निर्णय लेते हैं (हालांकि मैं "इसे न करें" कथन से सहमत हूं), इस कार्यान्वयन में मामूली बग है। यदि ज़ेड वैश्विक दायरे में मौजूद है, और गलत (गलत, कोई नहीं, खाली स्ट्रिंग इत्यादि) का मूल्यांकन करता है तो यह इस फ़ंक्शन द्वारा हटा दिया जाएगा। मैं यह निर्धारित करने के लिए एक अलग बुलियन ध्वज का उपयोग करूंगा कि 'z' को पुनर्स्थापित किया जाना चाहिए या नहीं। –

8

मुझे स्थानीय दायरे के बारे में पता नहीं है, लेकिन आप अस्थायी रूप से एक वैकल्पिक वैश्विक नाम स्थान प्रदान कर सकते हैं। की तरह कुछ:

 


import types 

def my_decorator(fn): 
    def decorated(*args,**kw): 
     my_globals={} 
     my_globals.update(globals()) 
     my_globals['z']='value of z' 
     call_fn=types.FunctionType(fn.func_code,my_globals) 
     return call_fn(*args,**kw) 
    return decorated 

@my_decorator 
def func(x, y): 
    print z 

func(0,1) 

 

कौन सा "Z का मान"

+0

हालांकि स्पष्ट रूप से यह "जादू" जैसा थोड़ा सा हो सकता है। –

+0

यह func परिभाषित समय पर globals की स्थिति में my_globals की स्थिति को जमा नहीं करेगा? – hop

+0

यह नहीं कि यह बहुत मायने रखता है ... – hop

7

प्रिंट चाहिए क) यह मत करो।

बी) गंभीरता से, आप ऐसा क्यों करेंगे?

सी) आप अपने सजावटी के भीतर जेड को ग्लोबल घोषित कर सकते हैं, इसलिए जब तक पहली बार सजावटी को बुलाया नहीं जाता है, तो ज़ेड ग्लोबल्स() में नहीं होगा, इसलिए जोर नहीं लगेगा।

डी) क्यों ???

+0

+1: यदि आप एक ऐसा फ़ंक्शन चाहते हैं जिसमें "मेमोरी" या "कैश" है, तो कॉल करने योग्य ऑब्जेक्ट को परिभाषित करें, __call___ विधि का उपयोग करें। –

+0

गंभीरता से, आप क्यों चाहेंगे? आप सामान्य लिस्प और भाषा का विस्तार करने की क्षमता चाहते हैं। या शायद रूबी यह कर सकते हैं।पाइथन कई चीजों के लिए अच्छा है, लेकिन यह नहीं। – Aaron

+0

यदि आप वैश्विक जेड घोषित होने के बाद उस कोड को फिर से लोड करते हैं, तो जोर सही तोड़ देगा? – smci

1

मैं शायद के साथ-साथ विश्वस्तरीय अधोसंरचना का उपयोग करने से एक समान प्रभाव हो सकता है, लेकिन मैं यह देखने के लिए अगर यह कच्चे कार्यों के साथ संभव था चाहता था।

खैर, पायथन एक ऑब्जेक्ट उन्मुख भाषा है। आपको मेरी राय में कक्षा में ऐसा करना चाहिए। एक अच्छा वर्ग इंटरफ़ेस बनाना निश्चित रूप से आपकी समस्या को सरल बना देगा। यह नहीं है जो सजावटी के लिए बनाया गया था।

2

मैं पहली बार "कृपया मत" गूंज प्रयास करेंगे, लेकिन तुम्हारी पसंद है। यहाँ आप के लिए एक समाधान है:

assert 'z' not in globals() 

class my_dec: 
    def __init__ (self, f): 
     self.f = f 
    def __call__ (self,x,y): 
     z = x+y 
     self.f(x,y,z) 

@my_dec 
def func (x,y,z): 
    print z 

func (1,3) 

यह औपचारिक पैरामीटर में z की आवश्यकता होती है, लेकिन वास्तविक नहीं।

1

स्पष्ट से स्पष्ट स्पष्ट है।

क्या यह पर्याप्त है?

def provide_value(f): 
    f.foo = "Bar" 
    return f 

@provide_value 
def g(x): 
    print g.foo 

(तुम सच में बुराई चाहते हैं, f.func_globals को बताए मज़ा लगता है।)

+1

मैं कहाँ शुरू कर दिया, मोटे तौर पर है कि - लेकिन अगर मैं दस कार्यों में ऐसा करते हैं, (जिनमें से प्रत्येक एक अलग नाम है) तो मेरे foo g.foo, h.foo, i.foo नाम पर है, ... में प्रत्येक समारोह। मैं सिर्फ foo के बारे में बात करना चाहता हूँ। –

0

दूसरों एक काम डेकोरेटर बनाने का कुछ तरीके दे दिया है, कई ऐसा न करने की सलाह दी है, क्योंकि यह शैलीगत अलग है सामान्य पायथन व्यवहार से यह वास्तव में कोड को समझने की कोशिश कर रहे किसी को भी भ्रमित करेगा।

यदि आपको चीजों को फिर से समझने की आवश्यकता है, तो क्या उन्हें किसी ऑब्जेक्ट में उन्हें समूहित करने का अर्थ होगा? कन्स्ट्रक्टर z1 ... कन्स्ट्रक्टर में जेएनएन, तो इन मानों का उपयोग करने वाले फ़ंक्शंस उदाहरण के हिस्से के रूप में पूर्व-गणना वाले उत्तरों तक पहुंच सकते हैं।

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

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