उस फ़ंक्शन के भीतर से फ़ंक्शन का नाम निर्धारित करें (ट्रेसबैक का उपयोग किए बिना)


479

पायथन में, tracebackमॉड्यूल का उपयोग किए बिना , क्या उस फ़ंक्शन के भीतर से फ़ंक्शन का नाम निर्धारित करने का एक तरीका है?

मान लें कि मेरे पास एक फ़ंक्शन बार के साथ एक मॉड्यूल फू है। निष्पादित करते समय foo.bar(), बार के नाम को जानने के लिए बार के लिए एक रास्ता है? या बेहतर अभी तक, foo.barनाम?

#foo.py  
def bar():
    print "my name is", __myname__ # <== how do I calculate this at runtime?

6
मुझे समझ में नहीं आता है कि स्वीकृत उत्तर एंड्रियास यंग (या कोई अन्य जो यह दिखाता है कि यह कैसे करना है) से नहीं है। इसके बजाय, स्वीकृत उत्तर "आप ऐसा नहीं कर सकते", जो गलत लगता है; ओपी द्वारा केवल आवश्यकता का उपयोग नहीं किया गया था traceback। जवाब और टिप्पणियों का समय भी नहीं लगता है।
sancho.s ReinstateMonicaCellio

जवाबों:


198

पायथन में फ़ंक्शन या इसके नाम को फ़ंक्शन के भीतर ही एक्सेस करने की सुविधा नहीं है। यह प्रस्तावित किया गया है लेकिन अस्वीकार कर दिया गया है। आप ढेर के साथ खुद को खेलने के लिए नहीं करना चाहते हैं, तो आप या तो उपयोग करना चाहिए "bar"या bar.__name__संदर्भ के आधार पर।

दी गई अस्वीकृति सूचना है:

यह पीईपी खारिज कर दिया जाता है। यह स्पष्ट नहीं है कि इसे कैसे लागू किया जाना चाहिए या किनारे के मामलों में सटीक शब्दार्थ क्या होना चाहिए, और दिए गए महत्वपूर्ण उपयोग के मामले नहीं हैं। प्रतिक्रिया गुनगुना रही है।


17
inspect.currentframe()ऐसा ही एक तरीका है।
युवावस्था

41
@ युवल के "छुपाने" से "कैमहार्ट के दृष्टिकोण" को छिपाते हुए और संभावित रूप से @ RoshOxymoron के उत्तर में संभावित रूप से पदावनत विधियों के साथ-साथ @ न्यूरो / @ AndreasJung के उत्तर के लिए स्टैक में संख्यात्मक अनुक्रमण:print(inspect.currentframe().f_code.co_name)
हब्स

2
क्या यह संक्षेप में संभव है कि इसे अस्वीकार क्यों किया गया?
चार्ली पार्कर

1
यह चुना हुआ जवाब क्यों है? प्रश्न केवल वर्तमान फ़ंक्शन या मॉड्यूल को एक्सेस करने के बारे में नहीं है, बस नाम है। और स्टैकट्रेस / डीबगिंग सुविधाओं में पहले से ही यह जानकारी है।
nurettin

409
import inspect

def foo():
   print(inspect.stack()[0][3])
   print(inspect.stack()[1][3]) #will give the caller of foos name, if something called foo

47
यह बहुत अच्छा है क्योंकि आप [1][3]कॉलर का नाम लेने के लिए भी कर सकते हैं ।
कोस

57
आप यह भी उपयोग कर सकते हैं: print(inspect.currentframe().f_code.co_name)या कॉलर का नाम पाने के लिए print(inspect.currentframe().f_back.f_code.co_name):। मुझे लगता है कि यह तेजी से होना चाहिए क्योंकि आप सभी स्टैक फ़्रेमों की सूची प्राप्त नहीं करते हैं inspect.stack()
माइकल

7
inspect.currentframe().f_back.f_code.co_nameजबकि एक सजाया विधि के साथ काम नहीं inspect.stack()[0][3]करता है ...
डस्टिन व्याट

4
कृपया ध्यान दें: निरीक्षण.स्टैक () भारी प्रदर्शन को उकसा सकता है इसलिए संयम से प्रयोग करें! मेरे हाथ के बॉक्स पर इसे 240ms तक ले जाना पड़ा (किसी कारण से)
gardarh

मुझे लगता है जैसे अजगर पुनरावृत्ति मशीनरी में मौजूद कुछ और अधिक कुशलता से ऐसा करने के लिए नियोजित किया जा सकता है
टॉम रसेल

160

समान परिणाम प्राप्त करने के कुछ तरीके हैं:

from __future__ import print_function
import sys
import inspect

def what_is_my_name():
    print(inspect.stack()[0][0].f_code.co_name)
    print(inspect.stack()[0][3])
    print(inspect.currentframe().f_code.co_name)
    print(sys._getframe().f_code.co_name)

ध्यान दें कि inspect.stackकॉल विकल्प की तुलना में हजारों गुना धीमी हैं:

$ python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][0].f_code.co_name'
1000 loops, best of 3: 499 usec per loop
$ python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][3]'
1000 loops, best of 3: 497 usec per loop
$ python -m timeit -s 'import inspect, sys' 'inspect.currentframe().f_code.co_name'
10000000 loops, best of 3: 0.1 usec per loop
$ python -m timeit -s 'import inspect, sys' 'sys._getframe().f_code.co_name'
10000000 loops, best of 3: 0.135 usec per loop

5
inspect.currentframe()निजी सदस्यों के निष्पादन समय और उपयोग के बीच एक अच्छा व्यापार है
FabienAndre

1
@mbdevpl मेरी संख्या 1.25ms, 1.24ms, 0.5us, 0.16us सामान्य (nonpythonic :)) सेकंड के अनुसार है (win7x64, python3.5.1)
एंटनी हैचकिंस

बस कोई भी ऐसा नहीं सोचता है @ mbdevpl पागल है :) - मैंने 3 रन के आउटपुट के लिए एक संपादन प्रस्तुत किया, क्योंकि इससे कोई मतलब नहीं था। कोई विचार नहीं अगर परिणाम 0.100 usecया 0.199 usecतो होना चाहिए था, लेकिन विकल्प 1 और 2 की तुलना में सैकड़ों गुना तेजी से, विकल्प 4 के साथ तुलनीय (हालांकि एंटनी हैचकिंस ने विकल्प 3 को विकल्प 4 की तुलना में 3 गुना तेज पाया)।
16

मैं उपयोग sys._getframe().f_code.co_nameसे अधिक inspect.currentframe().f_code.co_nameबस क्योंकि मैं पहले से ही आयात किया है sysमॉड्यूल। क्या यह उचित निर्णय है? (गति को देखते हुए काफी समान है)
पैट्रिक

47

आप उस नाम को प्राप्त कर सकते हैं जिसे उस दृष्टिकोण का उपयोग करके परिभाषित किया गया था जो @Andreas जंग दिखाता है , लेकिन यह वह नाम नहीं हो सकता है जिसे फ़ंक्शन के साथ बुलाया गया था:

import inspect

def Foo():
   print inspect.stack()[0][3]

Foo2 = Foo

>>> Foo()
Foo

>>> Foo2()
Foo

चाहे वह अंतर आपके लिए महत्वपूर्ण हो या नहीं, मैं नहीं कह सकता।


3
साथ ही स्थिति .func_name। पायथन में वर्ग के नाम और समारोह के नाम को याद रखना एक बात है और चर उन का जिक्र है।
कोस

कभी-कभी आप Foo2()प्रिंट करना चाह सकते हैं Foo। उदाहरण के लिए Foo2 = function_dict['Foo']; Foo2():। इस मामले में, Foo2 शायद कमांड लाइन पार्सर के लिए एक फ़ंक्शन पॉइंटर है।
हार्वे

यह किस तरह का गति निहितार्थ है?
राबर्ट सी। बर्थ

2
किसके संबंध में गति निहितार्थ? क्या कोई ऐसी स्थिति है जहाँ आपको इस जानकारी को एक वास्तविक रीयलटाइम स्थिति या कुछ और करने की आवश्यकता होगी?
bgporter

44
functionNameAsString = sys._getframe().f_code.co_name

मैं एक बहुत ही समान चीज चाहता था क्योंकि मैं फ़ंक्शन नाम को एक लॉग स्ट्रिंग में रखना चाहता था जो मेरे कोड में कई स्थानों पर गया था। शायद ऐसा करने का सबसे अच्छा तरीका नहीं है, लेकिन यहां वर्तमान फ़ंक्शन का नाम प्राप्त करने का एक तरीका है।


2
पूरी तरह से काम, बस sys का उपयोग कर, अधिक मॉड्यूल लोड करने की जरूरत नहीं है, लेकिन इसे याद रखना इतना आसान नहीं है: V
m3nda

@ erm3nda मेरा जवाब देखें।
nerdfever.com

1
@ nerdfever.com मेरी समस्या फ़ंक्शन बनाने के बारे में नहीं है, यह याद नहीं रखना है कि उस फ़ंक्शन के अंदर क्या रखा जाए। याद रखना आसान नहीं है इसलिए मुझे फिर से निर्माण के लिए कुछ नोट देखने की आवश्यकता होगी। मैं fफ्रेम के लिए और coकोड के लिए ध्यान में रखने की कोशिश करूंगा । मैं इसे इतना बेहतर उपयोग नहीं करते हैं, अगर मैं बस कुछ स्निपेट में बचा
लेता हूं

24

मैं इस उपयोगी उपयोगिता को पास में रखता हूँ:

import inspect
myself = lambda: inspect.stack()[1][3]

उपयोग:

myself()

1
यहां प्रस्तावित विकल्प के साथ यह कैसे किया जाएगा? "खुद = लैंबडा: sys._getframe ()। f_code.co_name" काम नहीं करता है (आउटपुट "<लैम्ब्डा>" है; मुझे लगता है क्योंकि परिणाम परिभाषा समय पर निर्धारित होता है, बाद में कॉल समय पर नहीं। हम्म
NYCeyes

2
@ prismalytics.io: यदि आप खुद को (अपने आप को) बुलाते हैं और केवल अपने मूल्य (खुद) का उपयोग नहीं करते हैं, तो आपको वह मिलेगा जो आप खोज रहे हैं।
19

NYCeyes सही था, नाम को लैम्ब्डा के अंदर हल किया गया है और इस प्रकार परिणाम <lambda> है। Sys._getframe () और inspect.currentframe () विधियों को उस फ़ंक्शन के अंदर सीधे निष्पादित किया जाना चाहिए जिसका आप नाम प्राप्त करना चाहते हैं। इंस्पेक्ट.स्टैक () विधि काम करती है क्योंकि आप इंडेक्स 1 निर्दिष्ट कर सकते हैं, निरीक्षण कर रहे हैं। स्टैक () [0] [3] पैदावार <lambda> भी करते हैं।
kikones34

20

मुझे लगता inspectहै कि ऐसा करने का सबसे अच्छा तरीका है। उदाहरण के लिए:

import inspect
def bar():
    print("My name is", inspect.stack()[0][3])

17

मुझे एक रैपर मिला जो फ़ंक्शन नाम लिखेगा

from functools import wraps

def tmp_wrap(func):
    @wraps(func)
    def tmp(*args, **kwargs):
        print func.__name__
        return func(*args, **kwargs)
    return tmp

@tmp_wrap
def my_funky_name():
    print "STUB"

my_funky_name()

यह छपेगा

my_funky_name

ठूंठ


1
डेकोरेटर नोब के रूप में, मुझे आश्चर्य होता है कि क्या fun_ एक्सेस करने का कोई तरीका है। _ name__ my_funky_name के संदर्भ में (इसलिए मैं इसके मूल्य को पुनः प्राप्त कर सकता हूं और इसे my_funky_name के अंदर उपयोग कर सकता हूं)
काउबर्ड

My_funky_name फ़ंक्शन के अंदर ऐसा करने का तरीका है my_funky_name.__name__। आप नए पैरामीटर के रूप में फंक .__ name__ को फंक्शन में पास कर सकते हैं। func (* args, ** kwargs, my_name = func .__ name__)। अपने सज्जाकार का नाम अपने कार्य के अंदर से प्राप्त करने के लिए, मुझे लगता है कि निरीक्षण का उपयोग करने की आवश्यकता होगी। लेकिन मेरे चल समारोह के भीतर मेरे फंक्शन को नियंत्रित करने वाले फ़ंक्शन का नाम प्राप्त करना ... अच्छी तरह से यह सिर्फ एक खूबसूरत मेम की शुरुआत की तरह लगता है :)
Cad106uk

15

यह वास्तव में प्रश्न के अन्य उत्तरों से लिया गया है।

यहाँ मेरा ले लो:

import sys

# for current func name, specify 0 or no argument.
# for name of caller of current func, specify 1.
# for name of caller of caller of current func, specify 2. etc.
currentFuncName = lambda n=0: sys._getframe(n + 1).f_code.co_name


def testFunction():
    print "You are in function:", currentFuncName()
    print "This function's caller was:", currentFuncName(1)    


def invokeTest():
    testFunction()


invokeTest()

# end of file

इंस्पेक्ट.स्टैक () का उपयोग करके इस संस्करण का संभावित लाभ यह है कि यह हजारों गुना तेज होना चाहिए [एलेक्स मेलहॉफ की पोस्ट देखें और sys._getframe () बनाम इंस्पेक्ट.स्टैक () का उपयोग करने के संबंध में समय।



11

यहाँ एक भविष्य-प्रूफ दृष्टिकोण है।

@ RoshOxymoron के स्वीकृत उत्तर के साथ @ CamHart's और @ युवल के सुझावों के संयोजन से बचने का लाभ है:

  • _hidden और संभावित रूप से हटाए गए तरीके
  • स्टैक में अनुक्रमण (जो भविष्य के अजगर में फिर से व्यवस्थित हो सकता है)

इसलिए मुझे लगता है कि यह भविष्य के अजगर संस्करणों (2.7.3 और 3.3.2 पर परीक्षण) के साथ अच्छा खेलता है:

from __future__ import print_function
import inspect

def bar():
    print("my name is '{}'".format(inspect.currentframe().f_code.co_name))

11
import sys

def func_name():
    """
    :return: name of caller
    """
    return sys._getframe(1).f_code.co_name

class A(object):
    def __init__(self):
        pass
    def test_class_func_name(self):
        print(func_name())

def test_func_name():
    print(func_name())

परीक्षा:

a = A()
a.test_class_func_name()
test_func_name()

आउटपुट:

test_class_func_name
test_func_name

11

मुझे यकीन नहीं है कि लोग इसे जटिल क्यों बनाते हैं:

import sys 
print("%s/%s" %(sys._getframe().f_code.co_filename, sys._getframe().f_code.co_name))

हो सकता है क्योंकि आप sys मॉड्यूल के निजी फ़ंक्शन का उपयोग कर रहे हैं, इसके बाहर। सामान्य तौर पर इसे एक बुरा अभ्यास माना जाता है, है ना?
tikej

@tikej, उपयोग यहां बताए गए सर्वोत्तम अभ्यास से सहमत है: docs.quantifiedcode.com/python-ant-patterns/correctness/…
karthik r

10
import inspect

def whoami():
    return inspect.stack()[1][3]

def whosdaddy():
    return inspect.stack()[2][3]

def foo():
    print "hello, I'm %s, daddy is %s" % (whoami(), whosdaddy())
    bar()

def bar():
    print "hello, I'm %s, daddy is %s" % (whoami(), whosdaddy())

foo()
bar()

आईडीई में कोड आउटपुट

हैलो, मैं फू हूं, डैडी है

हैलो, मैं बार हूँ, डैडी फू है

हैलो, मैं बार हूँ, डैडी है


8

आप एक डेकोरेटर का उपयोग कर सकते हैं:

def my_function(name=None):
    return name

def get_function_name(function):
    return function(name=function.__name__)

>>> get_function_name(my_function)
'my_function'

कैसे है कि पोस्टर के सवाल का जवाब दे रहा है? क्या आप इसका विस्तार कर सकते हैं कि एक उदाहरण कैसे शामिल किया जाए कि फ़ंक्शन का नाम फ़ंक्शन के भीतर से कैसे जाना जाता है?
परवस

@ अपर: मेरा जवाब जैसा कि एक उदाहरण है, जो ओपी के सवाल के जवाब को प्रदर्शित करता है
डगलस डेन्हर्टोग

ठीक है, my_function ओपी का यादृच्छिक उपयोगकर्ता कार्य है। इसे दोषियों की समझ की कमी के लिए जिम्मेदार ठहराते हैं। जहां @? यह उन कार्यों के लिए कैसे काम करेगा जिनके तर्क आप अनुकूलित नहीं करना चाहते हैं? मैं आपके समाधान को कैसे समझता हूं: जब मैं फ़ंक्शन नाम जानना चाहता हूं, तो मुझे इसे @get_function_name के साथ जोड़ना होगा, और नाम तर्क जोड़ना होगा, उम्मीद है कि यह पहले से ही किसी अन्य उद्देश्य के लिए नहीं है। मुझे कुछ याद आ रहा है, इसके लिए क्षमा करें।
परवस

एक टिप्पणी के अंदर अपना स्वयं का अजगर पाठ्यक्रम शुरू करने के बिना: 1. कार्य ऑब्जेक्ट हैं; 2. आप फ़ंक्शन को एक नाम विशेषता संलग्न कर सकते हैं, नाम प्रिंट / लॉग इन कर सकते हैं, या डेकोरेटर के अंदर "नाम" के साथ किसी भी संख्या में कर सकते हैं; 3. डेकोरेटर्स को कई तरीकों से जोड़ा जा सकता है (जैसे @ या मेरे उदाहरण में); 4. डेकोरेटर @wraps और / या खुद क्लास कर सकते हैं; 5. मैं जा सकता था, लेकिन, खुश प्रोग्रामिंग!
डगलस डेन्हार्तोग

यह सिर्फ __name__एक फ़ंक्शन की विशेषता को प्राप्त करने के लिए एक जटिल तरीके की तरह दिखता है । उपयोग के लिए उस चीज़ को जानना आवश्यक है जिसे आप प्राप्त करने की कोशिश कर रहे हैं, जो मुझे साधारण मामलों में बहुत उपयोगी नहीं लगती है जहाँ फ़ंक्शंस को मक्खी पर परिभाषित नहीं किया गया है।
एवी

3

मैं अपने स्वयं के दृष्टिकोण का उपयोग कई विरासत परिदृश्य के अंदर सुरक्षा के साथ सुपर को कॉल करने के लिए करता हूं (मैंने सभी कोड डाल दिए हैं)

def safe_super(_class, _inst):
    """safe super call"""
    try:
        return getattr(super(_class, _inst), _inst.__fname__)
    except:
        return (lambda *x,**kx: None)


def with_name(function):
    def wrap(self, *args, **kwargs):
        self.__fname__ = function.__name__
        return function(self, *args, **kwargs)
return wrap

नमूना उपयोग:

class A(object):

    def __init__():
        super(A, self).__init__()

    @with_name
    def test(self):
        print 'called from A\n'
        safe_super(A, self)()

class B(object):

    def __init__():
        super(B, self).__init__()

    @with_name
    def test(self):
        print 'called from B\n'
        safe_super(B, self)()

class C(A, B):

    def __init__():
        super(C, self).__init__()

    @with_name
    def test(self):
        print 'called from C\n'
        safe_super(C, self)()

इसका परीक्षण:

a = C()
a.test()

उत्पादन:

called from C
called from A
called from B

प्रत्येक @with_name सजाया विधि के अंदर आप वर्तमान समारोह के नाम के रूप में स्वयं .__ fname__ तक पहुंच रखते हैं।


3

मैंने हाल ही में उस फ़ंक्शन के संदर्भ से किसी फ़ंक्शन के डॉकस्ट्रिंग तक पहुंचने के लिए उपरोक्त उत्तरों का उपयोग करने की कोशिश की, लेकिन जैसा कि उपरोक्त प्रश्न केवल नाम स्ट्रिंग लौटा रहे थे, यह काम नहीं करता था।

सौभाग्य से मुझे एक सरल समाधान मिला। अगर मेरी तरह, आप फ़ंक्शन को संदर्भित करना चाहते हैं, तो केवल उस स्ट्रिंग का नाम प्राप्त करें, जिसे आप फ़ंक्शन नाम के स्ट्रिंग में eval () लागू कर सकते हैं।

import sys
def foo():
    """foo docstring"""
    print(eval(sys._getframe().f_code.co_name).__doc__)

3

मेरा सुझाव है कि स्टैक तत्वों पर भरोसा न करें। यदि कोई आपके कोड का उपयोग विभिन्न संदर्भों (उदाहरण के लिए अजगर इंटरप्रेटर) के भीतर करता है, तो आपका स्टैक बदल जाएगा और आपके सूचकांक को तोड़ देगा ([0] [3])।

मैं आपको कुछ इस तरह का सुझाव देता हूं:

class MyClass:

    def __init__(self):
        self.function_name = None

    def _Handler(self, **kwargs):
        print('Calling function {} with parameters {}'.format(self.function_name, kwargs))
        self.function_name = None

    def __getattr__(self, attr):
        self.function_name = attr
        return self._Handler


mc = MyClass()
mc.test(FirstParam='my', SecondParam='test')
mc.foobar(OtherParam='foobar')

0

यह एक डेकोरेटर के साथ पूरा करने के लिए बहुत आसान है।

>>> from functools import wraps

>>> def named(func):
...     @wraps(func)
...     def _(*args, **kwargs):
...         return func(func.__name__, *args, **kwargs)
...     return _
... 

>>> @named
... def my_func(name, something_else):
...     return name, something_else
... 

>>> my_func('hello, world')
('my_func', 'hello, world')
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.