मैं पायथन फ़ंक्शन का स्रोत कोड कैसे प्राप्त कर सकता हूं?


406

मान लीजिए मेरे पास पायथन फ़ंक्शन है जैसा कि नीचे परिभाषित किया गया है:

def foo(arg1,arg2):
    #do something with args
    a = arg1 + arg2
    return a

मैं फ़ंक्शन का उपयोग करके नाम प्राप्त कर सकता हूं foo.func_name। जैसा कि मैंने ऊपर लिखा है, मैं प्रोग्रामिक रूप से इसका स्रोत कोड कैसे प्राप्त कर सकता हूं?



1
ध्यान दें, पायथन 3 में आप foo.__name__
मिकी

आप बहुत सी अन्य चीजें भी प्राप्त कर सकते हैं ।
not2qubit

जवाबों:


541

यदि फ़ंक्शन फ़ाइल सिस्टम पर उपलब्ध स्रोत फ़ाइल से है, तो inspect.getsource(foo)मदद हो सकती है:

यदि fooइसे इस प्रकार परिभाषित किया जाए:

def foo(arg1,arg2):         
    #do something with args 
    a = arg1 + arg2         
    return a  

फिर:

import inspect
lines = inspect.getsource(foo)
print(lines)

यह दिखाता है:

def foo(arg1,arg2):         
    #do something with args 
    a = arg1 + arg2         
    return a                

लेकिन मेरा मानना ​​है कि यदि फ़ंक्शन एक स्ट्रिंग से संकलित किया गया है, या संकलित फ़ाइल से आयात किया गया है, तो आप इसके स्रोत कोड को पुनः प्राप्त नहीं कर सकते।


2
टपल लौटाता है; tuple [0] स्रोत कोड की रेखाओं का प्रतिनिधित्व करने वाले तारों की सूची है, और tuple [1] निष्पादन के संदर्भ में लाइन नंबर है जहां इसे चलाया गया था। IPython में; यह समग्र नोटबुक नहीं सेल के भीतर लाइन नंबर है
लाल मटर

12
यह उत्तर स्पष्ट रूप से इसका उल्लेख नहीं करता है, लेकिन निरीक्षण करता है। स्रोत (foo) स्रोत को एक एकल स्ट्रिंग में टपल के बजाय लौटाता है जहां ट्यूपल [0] लाइनों की एक सूची है। यदि आप repl में झांकने के लिए की जरूरत है getsource अधिक उपयोगी हो सकता है
Whaley

यह उदाहरण के लिए फ़ंक्शन के साथ काम नहीं करता है len। मुझे lenफ़ंक्शन के लिए स्रोत कोड कहां मिल सकता है?
ओकलैंडर114

1
याinspect.getsourcelines(foo)
स्लावोमिर लेनार्ट

1
@ oaklander113 निरीक्षण करता है। स्रोत पुस्तकालय के अधिकांश कार्यों की तरह बिल्ट-इन के साथ काम नहीं करता है। आप उनकी वेबसाइट या उनके Github
निकोलस एब्रिल

183

निरीक्षण मॉड्यूल अजगर वस्तुओं से स्रोत कोड को पुन: प्राप्त करने के लिए तरीके हैं। हालांकि यह तब ही काम करता है जब स्रोत किसी फ़ाइल में स्थित हो। यदि आपको लगता है कि मुझे लगता है कि आपको ऑब्जेक्ट से स्रोत प्राप्त करने की आवश्यकता नहीं है।


3
हां, यह केवल एक फाइल में परिभाषित वस्तुओं के लिए काम करता है। दुभाषिया में परिभाषित लोगों के लिए नहीं।
सस्तानिन

3
मेरे आश्चर्य के लिए, यह Ipython / Jupyter नोटबुक में भी काम करता है
डॉ। गोलू

1
मैंने एक python 3.5.3दुभाषिया में निरीक्षण का उपयोग करने की कोशिश की। import inspect+ inspect.getsource(foo)ठीक काम किया।
एंड्रे सी। एंडरसन

@ AndréChristofferAndersen हाँ, लेकिन यह दुभाषिया में परिभाषित कार्यों के लिए काम नहीं करना चाहिए
कोई

86

dis यदि स्रोत कोड उपलब्ध नहीं है तो आपका मित्र है:

>>> import dis
>>> def foo(arg1,arg2):
...     #do something with args
...     a = arg1 + arg2
...     return a
...
>>> dis.dis(foo)
  3           0 LOAD_FAST                0 (arg1)
              3 LOAD_FAST                1 (arg2)
              6 BINARY_ADD
              7 STORE_FAST               2 (a)

  4          10 LOAD_FAST                2 (a)
             13 RETURN_VALUE

1
बिलिन के लिए एक टाइपरोर फेंकता है।
नूमेनन

8
@ नौमेनन, क्योंकि उनके पास आमतौर पर पायथन में कोई स्रोत कोड नहीं है, वे C
schlamar

83

यदि आप IPython का उपयोग कर रहे हैं, तो आपको "foo ??" टाइप करना होगा।

In [19]: foo??
Signature: foo(arg1, arg2)
Source:
def foo(arg1,arg2):
    #do something with args
    a = arg1 + arg2
    return a

File:      ~/Desktop/<ipython-input-18-3174e3126506>
Type:      function

9
IPython और Jupyter नोटबुक में बहुत उपयोगी है अगर / जब आप गलती से एक सेल से अधिक हटा दें जिसमें ऐसे कार्य शामिल हैं जिन्हें आपने अभी दिन बनाने और परीक्षण के लिए खर्च किया है ....
AGS

किसके लिए, जिसने पूरी कक्षा खो दी: आप इसे विधि द्वारा विधि को पुनर्स्थापित कर सकते हैं: और dir(MyClass)फिर MyClass.__init__??इसी तरह।
Valerij

61

हालांकि मैं आम तौर पर सहमत हूँ कि inspectयह एक अच्छा जवाब है, मैं असहमत हूँ कि आप दुभाषिया में परिभाषित वस्तुओं का स्रोत कोड प्राप्त नहीं कर सकते। यदि आप से उपयोग करते dill.source.getsourceहैं dill, तो आप फ़ंक्शन और लैम्ब्डा के स्रोत प्राप्त कर सकते हैं, भले ही उन्हें अंतःक्रियात्मक रूप से परिभाषित किया गया हो। यह कोड को बाध्य या अनबाउंड क्लास विधियों और करी में परिभाषित कार्यों से भी प्राप्त कर सकता है ... हालांकि, आप उस कोड को संलग्न वस्तु के कोड के बिना संकलित करने में सक्षम नहीं हो सकते हैं।

>>> from dill.source import getsource
>>> 
>>> def add(x,y):
...   return x+y
... 
>>> squared = lambda x:x**2
>>> 
>>> print getsource(add)
def add(x,y):
  return x+y

>>> print getsource(squared)
squared = lambda x:x**2

>>> 
>>> class Foo(object):
...   def bar(self, x):
...     return x*x+x
... 
>>> f = Foo()
>>> 
>>> print getsource(f.bar)
def bar(self, x):
    return x*x+x

>>> 

1
@ Ant6n: ठीक है, यह सिर्फ डरपोक है। dill.source.getsourceफ़ंक्शंस, कक्षाओं, लैम्ब्डा, आदि के लिए दुभाषिया के इतिहास का निरीक्षण करता है - यह निष्पादित करने के लिए पारित स्ट्रिंग्स की सामग्री का निरीक्षण नहीं करता है।
माइक मैकरनस

यह बहुत दिलचस्प लगता है। क्या dillइस प्रश्न का उत्तर देना संभव है : stackoverflow.com/questions/13827543/…
ArtOfWarfare

@ArtOfWarfare: आंशिक रूप से, हाँ। dill.sourceकी तरह कार्य करता है getnameऔर importableऔर getsourceस्रोत कोड (या एक देश में लाने योग्य है कि पैदावार वस्तु) किसी भी वस्तु के लिए हो रही है पर फ़ोकस करते। एक तरह साधारण चीजों के लिए intनहीं है कोई (यानी 'एक = 10' के लिए यह रिटर्न '10') तो यह काम अपेक्षा के अनुरूप नहीं है स्रोत,।
Mc में

हालांकि यह >>> a = 10; print( [key for key, val in globals().items() if val is a][0] )
ग्लोबल्स के

@MikeMcKerns: मैंने उस प्रश्न का उत्तर देने के लिए अपना सर्वश्रेष्ठ प्रयास किया है dill, लेकिन मेरा उत्तर वांछित होने के लिए थोड़ा छोड़ देता है (IE, यदि आपके पास एक ही मूल्य के लिए कई नाम हैं, तो यह पता नहीं लगा सकता है कि इसका उपयोग किया गया था। यदि आप एक अभिव्यक्ति में पास, यह नहीं कह सकता कि वह अभिव्यक्ति क्या थी। हेक, यदि आप एक अभिव्यक्ति में गुजरते हैं जो एक नाम के समान मूल्यांकन करता है, तो वह उस नाम को बदले में देगा।) dillमेरे उत्तर की उन कमियों को हल कर सकता है। यहाँ: stackoverflow.com/a/28634996/901641
ArtOfWarfare

21

रनेह के उत्तर पर विस्तार करने के लिए:

>>> def foo(a):
...    x = 2
...    return x + a

>>> import inspect

>>> inspect.getsource(foo)
u'def foo(a):\n    x = 2\n    return x + a\n'

print inspect.getsource(foo)
def foo(a):
   x = 2
   return x + a

संपादित करें: जैसा कि @ 0sh द्वारा बताया गया है कि यह उदाहरण काम करता है ipythonलेकिन सादा नहीं python। स्रोत फ़ाइलों से कोड आयात करते समय, दोनों में यह ठीक होना चाहिए।


2
यह काम नहीं करेगा, क्योंकि दुभाषिया फूको को बाइटकोड के लिए संकलित करेगा और यदि आप चलाने की कोशिश करते हैं, तो OSError को बढ़ाते हुए स्रोत कोड को फेंक देंगे getsource(foo)
Milo Wielondek

@ 0sh अच्छा बिंदु जहां तक ​​वेनिला पायथन दुभाषिया का संबंध है। हालाँकि IPython का उपयोग करते समय उपरोक्त कोड उदाहरण काम करता है।
टॉमडॉटॉम

11

उसके inspectलिए पूर्ण स्रोत कोड प्राप्त करने के लिए आप मॉड्यूल का उपयोग कर सकते हैं । आपको मॉड्यूल getsource()से इसके लिए विधि का उपयोग करना होगा inspect। उदाहरण के लिए:

import inspect

def get_my_code():
    x = "abcd"
    return x

print(inspect.getsource(get_my_code))

आप नीचे दिए गए लिंक पर और अधिक विकल्प देख सकते हैं। अपने अजगर कोड को पुनः प्राप्त करें


7

चूँकि इस पोस्ट को इस अन्य पोस्ट के डुप्लिकेट के रूप में चिह्नित किया गया है , मैं यहाँ "लंबदा" मामले के लिए जवाब देता हूँ, हालाँकि ओपी लंबोदा के बारे में नहीं है।

तो, लैंबडा कार्यों के लिए जो अपनी स्वयं की पंक्तियों में परिभाषित नहीं हैं: marko.ristin के उत्तर के अलावा, आप मिनी-लैम्ब्डा का उपयोग करना चाहते हैं या इस उत्तर में सुझाए अनुसार सिम्पी का उपयोग कर सकते हैं ।

  • mini-lambda हल्का है और किसी भी तरह के ऑपरेशन का समर्थन करता है, लेकिन केवल एक ही चर के लिए काम करता है
  • SymPyगणितीय / कैलकुलस परिचालनों के साथ भारी लेकिन बहुत अधिक सुसज्जित है। विशेष रूप से यह आपके भावों को सरल बना सकता है। यह एक ही अभिव्यक्ति में कई चर का भी समर्थन करता है।

यहां बताया गया है कि आप इसका उपयोग कैसे कर सकते हैं mini-lambda:

from mini_lambda import x, is_mini_lambda_expr
import inspect

def get_source_code_str(f):
    if is_mini_lambda_expr(f):
        return f.to_string()
    else:
        return inspect.getsource(f)

# test it

def foo(arg1, arg2):
    # do something with args
    a = arg1 + arg2
    return a

print(get_source_code_str(foo))
print(get_source_code_str(x ** 2))

इसकी सही पैदावार होती है

def foo(arg1, arg2):
    # do something with args
    a = arg1 + arg2
    return a

x ** 2

देखें mini-lambda प्रलेखन जानकारी के लिए। मैं लेखक हूँ वैसे;)


5

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

उदाहरण के लिए, एक फ़ाइल पर विचार करें test.py:

import inspect

def main():
    x, f = 3, lambda a: a + 1
    print(inspect.getsource(f))

if __name__ == "__main__":
    main()

इसे निष्पादित करने से आपको (मन की ओर संकेत मिलता है!):

    x, f = 3, lambda a: a + 1

लैम्ब्डा के स्रोत कोड को पुनः प्राप्त करने के लिए, मेरी राय में, आपकी सबसे अच्छी शर्त, पूरे सोर्स फाइल को फिर से पार्स करना (उपयोग करके f.__code__.co_filename) और लाइन नंबर और उसके संदर्भ द्वारा लैम्ब्डा एएसटी नोड से मेल खाना है।

हमें ठीक यही करना था कि हमारे डिजाइन-बाय-कॉन्ट्रैक्ट लाइब्रेरी में जब से हम लैम्ब्डा फंक्शन्स को पार्स करते हैं, हम डेकोरेटर्स के तर्क के रूप में देखते हैं। यहां पेस्ट करने के लिए बहुत अधिक कोड है, इसलिए इस फ़ंक्शन के कार्यान्वयन पर एक नज़र डालें ।


4

यदि आप अपने आप को फ़ंक्शन को कड़ाई से परिभाषित कर रहे हैं और यह एक अपेक्षाकृत छोटी परिभाषा है, तो निर्भरता के बिना एक समाधान एक स्ट्रिंग में फ़ंक्शन को परिभाषित करने और आपके फ़ंक्शन के लिए अभिव्यक्ति का eval () असाइन करेगा।

उदाहरण के लिए

funcstring = 'lambda x: x> 5'
func = eval(funcstring)

फिर वैकल्पिक रूप से फ़ंक्शन में मूल कोड संलग्न करें:

func.source = funcstring

2
जब तक आप किसी तरह का इंटरएक्टिव पायथन दुभाषिया नहीं लिख रहे हैं, तब तक निष्कासन () का उपयोग मुझे वास्तव में बुरा लगता है। बेवजह सुरक्षा संबंधी समस्याएं खुल जाती हैं। यदि आप केवल eval'ing स्ट्रिंग शाब्दिक की नीति अपनाते हैं, तो आप अभी भी विभिन्न प्रकार के सहायक व्यवहार से चूक जाते हैं, जो सिंटैक्स हाइलाइटिंग से लेकर कक्षाओं के समुचित प्रतिबिंब तक होते हैं जिनमें eval'ed सदस्य होते हैं।
मार्क ई। हसे

2
Upvoting। @mehaase: सुरक्षा स्पष्ट रूप से यहाँ एक मुद्दा नहीं है। हालांकि आपकी अन्य टिप्पणियां काफी प्रासंगिक हैं, हालांकि मैं कहूंगा कि वाक्यविन्यास हाइलाइटिंग की कमी आईडीई की गलती का एक संयोजन है और यह तथ्य कि पायथन एक होमोसेक्सुअल भाषा नहीं है।
नौजागेको

7
@ninjagecko सुरक्षा हमेशा एक मुद्दा है जब आप आम जनता को सलाह दे रहे हैं। अधिकांश पाठक यहां आ रहे हैं क्योंकि वे गुगली प्रश्न कर रहे हैं। मुझे नहीं लगता कि बहुत से लोग इस उत्तर को शब्दशः कॉपी करने जा रहे हैं; इसके बजाय, वे सीखी गई अवधारणा को लेने जा रहे हैं और इसे अपनी समस्या पर लागू करते हैं।
मार्क ई। हासे

4

संक्षेप में :

import inspect
print( "".join(inspect.getsourcelines(foo)[0]))

0

मेरा मानना ​​है कि चर नाम pyc / pyd / pyo फ़ाइलों में संग्रहीत नहीं हैं, इसलिए यदि आपके पास स्रोत फ़ाइलें नहीं हैं, तो आप सटीक कोड लाइनों को पुनः प्राप्त नहीं कर सकते हैं।

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