पायथन में फ़ंक्शन के मॉड्यूल को कॉल करने का __name__ प्राप्त करें


96

मान लीजिए myapp/foo.py:

def info(msg):
    caller_name = ????
    print '[%s] %s' % (caller_name, msg)

तथा myapp/bar.py इसमें शामिल हैं:

import foo
foo.info('Hello') # => [myapp.bar] Hello

मैं caller_nameसेट होना चाहता हूं__name__ इस मामले में कॉलिंग फ़ंक्शन के मॉड्यूल (जो 'myapp.foo' है) विशेषता पर । यह कैसे किया जा सकता है?


मान लें कि कुछ अन्य प्रविष्टि बिंदु स्क्रिप्ट bar.py .. को आमंत्रित करती है और इस प्रकार caller_nameनहीं हो सकती है__main__
श्रीधर रत्नाकुमार

जवाबों:


123

निरीक्षण मॉड्यूल देखें:

inspect.stack() स्टैक जानकारी वापस करेगा।

एक फ़ंक्शन के अंदर, inspect.stack()[1]आपके कॉलर का स्टैक वापस करेगा। वहां से, आप कॉलर के फ़ंक्शन नाम, मॉड्यूल आदि के बारे में अधिक जानकारी प्राप्त कर सकते हैं।

विवरण के लिए डॉक्स देखें:

http://docs.python.org/library/inspect.html

इसके अलावा, डौग हेलमैन ने अपनी PyMOTW श्रृंखला में निरीक्षण मॉड्यूल का एक अच्छा लेखन कार्य किया है:

http://pymotw.com/2/inspect/index.html#module-inspect

संपादित करें: यहाँ कुछ कोड है जो आपको चाहिए, मुझे लगता है:

def info(msg):
    frm = inspect.stack()[1]
    mod = inspect.getmodule(frm[0])
    print '[%s] %s' % (mod.__name__, msg)

1
तो आपको __name__मॉड्यूल का उपयोग करके इस मॉड्यूल की विशेषता कैसे मिलती है inspect? उदाहरण के लिए, मैं अपने उपरोक्त उदाहरण में कैसे वापस आऊं myapp.foo(नहीं myapp/foo.py)? मैंने पहले ही SO पर पोस्ट करने से पहले निरीक्षण मॉड्यूल का उपयोग करने की कोशिश की।
श्रीधर रत्नाकुमार

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

2
यह भी ध्यान दें कि स्टैक फ्रेम का संदर्भ रखने से पायथन की GC को सही तरीके से काम करने से रोका जा सकता है। यहां देखें चेतावनी: docs.python.org/library/inspect.html#the-interpreter-stack
कामिल

6
ध्यान दें कि यदि कॉलर फ़ंक्शन सजाया गया है (@ ...), तो आपको inspect.stack()[2]वास्तविक कॉलर के लिए एक्सेस करने की आवश्यकता है ।
अमीर अली अकबरी

यह भी ध्यान दें कि यह तर्क ठीक से काम करने में विफल रहता है जब आप अपने अजगर कोड को pyinstaller का उपयोग करके एक exe में संकलित करते हैं।
पैनोफिश

19

इसी तरह की समस्या से जूझते हुए , मैंने पाया है कि sys मॉड्यूल से sys._current_frames () में ऐसी रोचक जानकारी होती है जो आपकी मदद कर सकती है, निरीक्षण के आयात की आवश्यकता के बिना, कम से कम विशिष्ट उपयोग के मामलों में।

>>> sys._current_frames()
{4052: <frame object at 0x03200C98>}

फिर आप f_back का उपयोग करके "आगे बढ़ सकते हैं":

>>> f = sys._current_frames().values()[0]
>>> # for python3: f = list(sys._current_frames().values())[0]

>>> print f.f_back.f_globals['__file__']
'/base/data/home/apps/apricot/1.6456165165151/caller.py'

>>> print f.f_back.f_globals['__name__']
'__main__'

फ़ाइल नाम के लिए आप f.f_back.f_code.co_filename का भी उपयोग कर सकते हैं, जैसा कि ऊपर मार्क रोड्डी ने सुझाया है। मैं इस पद्धति की सीमा और गुहाओं के बारे में निश्चित नहीं हूं (कई धागे सबसे अधिक समस्या होगी), लेकिन मैं इसे अपने मामले में उपयोग करने का इरादा रखता हूं।


2
नोट: pyinstaller का उपयोग करने के लिए संकलन करने के बाद इंस्पेक्ट.स्टैक कोड कीलें, लेकिन sys._current_frames का उपयोग करके ठीक करें ... इसलिए यह मेरे लिए पसंदीदा तकनीक है।
पैनॉफिश

7
मुझे लगता है कि sys._getframe(1)कॉलिंग के बजाय पिछले फ्रेम को प्राप्त करना आसान है sys._current_frames()(btw जो हर थ्रेड के लिए एक फ्रेम मैपिंग लौटाता है)।
होउबलि

धन्यवाद hooblei, मैंने अभी तक इसका परीक्षण नहीं किया है, लेकिन बहु-थ्रेडेड स्थितियों के लिए बहुत उपयोगी लगता है।
लुई एलसी

मैं inspect.currentframe()इसके बजाय उपयोग करना पसंद करता हूं sys._current_frames().values()[0]
अरन-फे

3

मैं ऐसा करने की सलाह नहीं देता, लेकिन आप निम्न विधि से अपना लक्ष्य पूरा कर सकते हैं:

def caller_name():
    frame=inspect.currentframe()
    frame=frame.f_back.f_back
    code=frame.f_code
    return code.co_filename

फिर अपने मौजूदा तरीके को इस प्रकार अपडेट करें:

def info(msg):
    caller = caller_name()
    print '[%s] %s' % (caller, msg)

7
फ़ाइल नाम समान नहीं है__name__
श्रीधर रत्नाकुमार
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.