সেই ফাংশনের মধ্যে থেকেই ফাংশনের নাম নির্ধারণ করুন (ট্রেসব্যাক ব্যবহার না করে)


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 পুনরায় ইনস্টল করুন মনিকাসেলিও

উত্তর:


198

পাইথনের ক্রিয়াকলাপটি অ্যাক্সেস করতে বা তার নামটির মধ্যেই এর বৈশিষ্ট্য নেই। এটি প্রস্তাবিত হলেও প্রত্যাখ্যান করা হয়েছে । আপনি যদি স্ট্যাকটি নিজে খেলতে না চান তবে আপনার উচিত হয় ব্যবহার করা উচিত "bar"বা bar.__name__প্রসঙ্গে on

প্রদত্ত প্রত্যাখ্যান বিজ্ঞপ্তিটি হ'ল:

এই পিইপি প্রত্যাখ্যান করা হয়। এটি কীভাবে বাস্তবায়ন করা উচিত বা প্রান্তের ক্ষেত্রে সুনির্দিষ্ট শব্দার্থকগুলি কী হওয়া উচিত তা পরিষ্কার নয়, এবং যথেষ্ট গুরুত্বপূর্ণ ব্যবহারের কেস দেওয়া হয়নি। প্রতিক্রিয়া সেরা এলোমেলো হয়েছে।


17
inspect.currentframe()এটি একটি উপায়।
যুবাল

41
@ ইউওভালের @ লুকোঅ্যাকিমারনের উত্তরের "লুকানো" এবং সম্ভাব্য অবমূল্যায়ন পদ্ধতিগুলির পাশাপাশি @ নিউরো / @ আন্দ্রেজংয়ের জবাবের জন্য স্ট্যাকের সংখ্যাসূচক সূচিগুলি এড়ানো @ ক্যামহার্টের পদ্ধতির সাথে একত্রিত হওয়া:print(inspect.currentframe().f_code.co_name)
হাবস

2
কেন এটি প্রত্যাখ্যান করা হয়েছে তার সংক্ষিপ্তসারটি সম্ভব?
চার্লি পার্কার

1
কেন এটি নির্বাচিত উত্তর? প্রশ্নটি বর্তমান ফাংশন বা মডিউলটি নিজেই কেবল অ্যাক্সেস করার বিষয়ে নয়। এবং স্ট্যাকট্রেস / ডিবাগিং বৈশিষ্ট্যগুলির মধ্যে ইতিমধ্যে এই তথ্য রয়েছে।
নুরেটিন

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
দয়া করে নোট করুন: ইন্সপেক্ট.স্ট্যাক () ভারী পারফরম্যান্সের ওভারহেড নিতে পারে তাই অল্প পরিমাণে ব্যবহার করুন! আমার আর্ম বক্সে এটি 240 মিমি নিয়েছে (কোনও কারণে)
গারধড়

আমার কাছে মনে হচ্ছে পাইথন রিকার্সন মেশিনারে উপস্থিত এমন কোনও কিছু সম্ভবত আরও দক্ষতার সাথে এটি করার জন্য নিযুক্ত করা যেতে পারে
টম রাসেল

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()মৃত্যুদন্ড কার্যকর করার সময় এবং ব্যক্তিগত সদস্যদের ব্যবহারের মধ্যে একটি ভাল বাণিজ্য বলে মনে হচ্ছে
ফ্যাবিয়ানআান্ড্রে

1
@mbdevpl আমার সংখ্যাগুলি 1.25 মিমি, 1.24 মিমি, 0.5us, 0.16us নরমাল (নপিপথোনিক :)) সেকেন্ড অনুসারে (উইন 7 এক্স 64, পাইথন 3.5.1)
অ্যান্টনি হ্যাচকিনস

ঠিক তেমন কেউ @ এমবিদেপলকে পাগল মনে করে না :) - আমি তৃতীয় রানের আউটপুটটির জন্য একটি সম্পাদনা জমা দিয়েছি, কারণ এটি কোনও অর্থবোধ করে না। ফলাফলটি 0.100 usecবা 0.199 usecঅন্য কোনওভাবে হওয়া উচিত কিনা ধারণা নেই - বিকল্প 1 এবং 2 এর চেয়ে কয়েকগুণ দ্রুত, অপশন 4 এর সাথে তুলনাযোগ্য (যদিও অ্যান্টনি হ্যাচকিন্স অপশন 4 এর চেয়ে তিনগুণ দ্রুত বিকল্প পেয়েছে)।
ডোয়ান্ডারসন

আমি ব্যবহার sys._getframe().f_code.co_nameউপর inspect.currentframe().f_code.co_nameকারণ আমি ইতিমধ্যে আমদানি করেছি sysমডিউল। এটা কি যুক্তিসঙ্গত সিদ্ধান্ত? (গতি বিবেচনা করে বেশ অনুরূপ প্রদর্শিত হয়)
প্যাট্রিক

47

আপনি নামটি পেতে পারেন যে এটি @ আন্দ্রেয়াস জং দেখায় এমন পদ্ধতির সাহায্যে সংজ্ঞায়িত হয়েছিল তবে ফাংশনটি যে নামটির সাথে ডাকা হয়েছিল এটি সেই নাম নাও হতে পারে:

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
কিসের সাথে গতি জড়িত? এমন কোনও পরিস্থিতি আছে যেখানে আপনার হার্ড রিয়েলটাইম পরিস্থিতিতে বা অন্য কিছুতে এই তথ্য থাকা দরকার?
বিজিপিটার

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

আমি একটি খুব অনুরূপ জিনিস চেয়েছিলাম কারণ আমি ফাংশনটির নামটি একটি লগ স্ট্রিংয়ে রাখতে চেয়েছিলাম যা আমার কোডে বেশ কয়েকটি জায়গায় গেছে। সম্ভবত এটি করার সর্বোত্তম উপায় নয়, তবে বর্তমান ফাংশনটির নাম পাওয়ার একটি উপায় এখানে।


2
সম্পূর্ণরূপে কাজ করছেন, কেবল
সি

আমার উত্তর দেখুন
নার্ডফাইভার.কম

1
@ নার্ডফাইভার.কম আমার সমস্যাটি কোনও ফাংশন তৈরি করার কথা নয়, সেই ফাংশনের ভিতরে কী রাখবেন তা মনে রাখবেন না। মনে রাখা সহজ নয় তাই এটিকে আবার তৈরি করতে আমার সর্বদা কিছু নোট দেখতে হবে। আমি fফ্রেম এবং coকোড জন্য মনে রাখা চেষ্টা করব । আমি এত কিছু ব্যবহার করি না যদি আমি কিছু স্নিপেটে এটি সংরক্ষণ করি :-)
এম 3 এন্ডা

24

আমি এই সুবিধাজনক উপযোগটি কাছাকাছি রাখি:

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

ব্যবহার:

myself()

1
এখানে প্রস্তাবিত বিকল্পের সাথে এটি কীভাবে হবে? কাজ নেই (আউটপুট কি ভাবে "<ল্যামডা>"; আমি মনে করি কারণ ফলাফলের সংজ্ঞা সময়ে নির্ধারিত হয়, না পরে কল সময়ে হুম: "। sys._getframe () f_code.co_name নিজেকে ল্যামডা
NYCeyes

2
@ prismalytics.io: আপনি যদি নিজেকে (নিজেকে ()) কল করেন এবং কেবল তার মান (নিজেই) ব্যবহার না করেন তবে আপনি যা খুঁজছেন তা পেয়ে যাবেন।
ijw

এনওয়াইসিয়েস ঠিকই ছিল, নামটি ল্যাম্বদার ভিতরে সমাধান করা হয়েছে এবং ফলস্বরূপ <লম্বদা>। 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
ডেকোরেটর নুব হিসাবে, আমি অবাক হয়েছি যে আমার_ফানকি_নামের প্রসঙ্গে (name নাম__) আমার ফাঙ্কি_নামের প্রসঙ্গে (যাতে আমি এর মানটি উদ্ধার করতে এবং এটি আমার_ফানকি_নামের অভ্যন্তরে ব্যবহার করতে পারি)
কাওবার্ট

আমার_ফানকি_নামের ফাংশনের ভিতরে সেটি করার উপায় my_funky_name.__name__। আপনি নতুন পরামিতি হিসাবে ফাংশনটিতে ফান .__ নাম__ পাস করতে পারেন। ফানক (* আরগস, ** কোয়ার্গস, আমার_নাম = ফানক __ নাম__)। আপনার ফাংশনটির অভ্যন্তর থেকে আপনার সাজসজ্জার নাম পেতে, আমি মনে করি এটির জন্য পরিদর্শন করা প্রয়োজন। তবে ফাংশনটির নামটি আমার চলমান ফাংশনটির মধ্যে আমার ফাংশনটিকে নিয়ন্ত্রণ করছে ... ভাল যে এটি কেবল একটি সুন্দর
মেমের

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

ইন্সপেক্ট.স্ট্যাক () ব্যবহার করে এই সংস্করণটির সম্ভবত সম্ভাব্য সুবিধাটি হ'ল এটি কয়েক হাজারগুণ দ্রুত হওয়া উচিত [অ্যালেক্স মেলিহফের পোস্ট এবং সাইন._জেটফ্রেম () বনাম ইন্সপেক্ট.স্ট্যাক () ব্যবহার করে সম্পর্কিত সময়গুলি]।



11

এখানে একটি ভবিষ্যত-প্রমাণ পদ্ধতির।

@ রোশঅক্সিমারনের স্বীকৃত উত্তরের সাথে @ ক্যামহার্ট এবং @ ইউভালের পরামর্শগুলি একত্রিত করার এড়ানোর সুবিধা রয়েছে:

  • _hidden এবং সম্ভাব্য হ্রাস পদ্ধতি
  • স্ট্যাকের সাথে ইনডেক্সিং (যা ভবিষ্যতের অজগরগুলিতে পুনরায় সাজানো যেতে পারে)

সুতরাং আমি মনে করি এটি ভবিষ্যতের অজগর সংস্করণগুলির সাথে দুর্দান্ত খেলছে (২.7.৩ এবং ৩.৩.২ এ পরীক্ষিত):

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))

সম্ভবত আপনি এর বাইরে সিস মডিউলটির ব্যক্তিগত ফাংশন ব্যবহার করছেন। সাধারণভাবে এটি একটি খারাপ অভ্যাস হিসাবে বিবেচিত হয়, তাই না?
টিকেজ

@ তবুও, ব্যবহারটি এখানে বর্ণিত সর্বোত্তম অনুশীলনের সাথে একমত: ডকস.কিউনটিফাইড কোড
আর

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'

পোস্টারের প্রশ্নের উত্তর কীভাবে দিচ্ছে? ফাংশনটির মধ্য থেকে কীভাবে ফাংশনটির নাম জানা যায় তার একটি উদাহরণ অন্তর্ভুক্ত করতে আপনি এটি প্রসারিত করতে পারেন?
পারভাস

@ পারভাস: আমার উত্তরটি যেমন একটি উদাহরণ যা
ওপির

ঠিক আছে, আমার_ফানশনটি ওপির এলোমেলো ব্যবহারকারীর ফাংশন। আমার সজ্জকারদের বোঝার অভাবকে দোষ দিন। @ কোথায়? এটি এমন ফাংশনগুলির জন্য কীভাবে কাজ করবে যার যুক্তিগুলি আপনি মানিয়ে নিতে চান না? আমি কীভাবে আপনার সমাধানটি বুঝতে পারি: যখন আমি ফাংশনটির নাম জানতে চাই, আমাকে এটি @get_function_name দিয়ে যুক্ত করতে হবে এবং নামের যুক্তি যুক্ত করতে হবে, আশা করে এটি অন্য কোনও উদ্দেশ্যে ইতিমধ্যে নেই। আমি সম্ভবত কিছু অনুপস্থিত, এর জন্য দুঃখিত।
পারভাস

একটি মন্তব্য ভিতরে আমার নিজস্ব পাইথন কোর্স শুরু না করে: 1. ফাংশন অবজেক্টস; ২. আপনি ফাংশনটির সাথে একটি নামের বৈশিষ্ট্য সংযুক্ত করতে পারেন, নামটি মুদ্রণ / লগ করতে পারেন বা সাজসজ্জার ভিতরে "নাম" দিয়ে যেকোন কিছু করতে পারেন; ৩. সাজসজ্জারগুলি একাধিক উপায়ে সংযুক্ত করা যায় (যেমন @ বা আমার উদাহরণে); ৪. সাজসজ্জাবিদরা @ wraps ব্যবহার করতে পারেন এবং / অথবা নিজেরাই ক্লাস হতে পারেন; ৫. আমি যেতে পারলাম, তবে, খুশি প্রোগ্রামিং!
ডগলাস ডেনহার্টোগ

এটি কেবল __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')
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.