আমি পাইথন ফাংশনের উত্স কোডটি কীভাবে পেতে পারি?


406

ধরুন নীচের সংজ্ঞা অনুসারে আমার পাইথন ফাংশন রয়েছে:

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

আমি ব্যবহার করে ফাংশনটির নাম পেতে পারি foo.func_name। আমি উপরে টাইপ করার সাথে সাথে আমি প্রোগ্রামের মাধ্যমে কীভাবে এর উত্স কোডটি পেতে পারি?



1
নোট, পাইথন 3 আপনি ব্যবহার ফাংশনের নাম পেতে পারেনfoo.__name__
MikeyE

আপনি অন্যান্য প্রচুর জিনিসও পেতে পারেন ।
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 ফেরত ; tuple [0] হ'ল সোর্স কোডের লাইনগুলি উপস্থাপন করে এমন স্ট্রিংয়ের তালিকা এবং টিপল [1] এটি সঞ্চালনের প্রসঙ্গে লাইন নম্বর যেখানে এটি চালিত হয়েছিল। আইপিথনে; এটি সামগ্রিক নোটবুক নয় কক্ষের মধ্যে লাইন নম্বর
দ্য রেড মটর

12
এই উত্তরটি সুস্পষ্টভাবে এটি উল্লেখ করে না, তবে ইন্সপেক্ট.গেটসোর্স (foo) টিপলের পরিবর্তে একক স্ট্রিংয়ে উত্সটি দেয় যেখানে টিপল [0] লাইনগুলির একটি তালিকা। গেটসোর্স আরও কার্যকর হবে যদি আপনার প্রতিবেদনে উঁকি দেওয়া দরকার
তিমি 23'15

এটি যেমন ফাংশন সঙ্গে কাজ করে না lenlenফাংশনের সোর্স কোডটি কোথায় পাব?
ওকল্যান্ডের 114

1
বাinspect.getsourcelines(foo)
সাওওমির লেনার্ট

1
@ ওকল্যান্ডার 113 ইন্সপেক্ট.গেটসোর্স স্ট্যান্ডার্ড লাইব্রেরির বেশিরভাগ ফাংশনের মতো বিল্ট-ইনগুলির সাথে কাজ করে না। আপনি cpython জন্য সোর্স কোড পরীক্ষা করতে পারবেন তাদের ওয়েবসাইট বা তাদের গিটহাব
নিকোলাস এপ্রিল

183

পরিদর্শন মডিউল পাইথন বস্তু থেকে সোর্স কোড পুনরুদ্ধারের জন্য মেথড। দৃশ্যত এটি কেবল তখনই কাজ করে যদি উত্সটি কোনও ফাইলে অবস্থিত তবে। যদি আপনার মনে হয় যে আমি অনুমান করেছি যে আপনাকে অবজেক্ট থেকে উত্সটি পাওয়ার দরকার নেই।


3
হ্যাঁ, এটি কেবল কোনও ফাইলে সংজ্ঞায়িত সামগ্রীর জন্য কাজ করে বলে মনে হচ্ছে। দোভাষীর সংজ্ঞায়িতদের জন্য নয়।
সস্তানিন

3
আমার অবাক করার বিষয়, এটি আইপথন / জুপিটার নোটবুকগুলিতেও কাজ করে
ডঃ গৌলু

1
আমি python 3.5.3দোভাষীর মধ্যে পরিদর্শন ব্যবহার করার চেষ্টা করেছি । import inspect+ ভাল inspect.getsource(foo)কাজ করে।
আন্দ্রে সি। অ্যান্ডারসন

@ অ্যান্ড্রি ক্রিসটফারঅ্যান্ডারসেন হ্যাঁ তবে এটি দোভাষীর সংজ্ঞায়িত ফাংশনগুলির জন্য কাজ করা উচিত নয়
কেউ

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
@ নুমেনন যেহেতু পাইথনে সাধারণত তাদের সোর্স কোড থাকে না, সেগুলি সি তে লিখিত হয়
স্ক্ল্যামার-

83

আপনি যদি আইপিথন ব্যবহার করে থাকেন তবে আপনাকে "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
আইপিথন এবং জুপিটার নোটবুকের ক্ষেত্রে খুব সহায়ক যদি / আপনি যদি ঘটনাক্রমে একাধিক সেল মুছে ফেলেন যাতে ফাংশন রয়েছে যা আপনি সবেমাত্র তৈরি এবং পরীক্ষায় কাটিয়েছেন ....
এজিএস

যার কাছে, পুরো ক্লাসটি কে হারিয়েছে: আপনি এটিকে পদ্ধতি দ্বারা পুনঃস্থাপন করতে পারেন: dir(MyClass)তারপরে MyClass.__init__??এবং আরও অনেক কিছু।
ভালেরিজ

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
@ অ্যান্ট n এন: ঠিক আছে, এটি কেবল ছদ্মবেশী। dill.source.getsourceক্রিয়াকলাপ, ক্লাস, ল্যাম্বডাস ইত্যাদির জন্য অনুবাদকের ইতিহাস পরিদর্শন করে - এটি কার্যকর করার জন্য পাস করা স্ট্রিংয়ের সামগ্রীটি পরীক্ষা করে না।
মাইক ম্যাকার্নস

এটি খুব আকর্ষণীয় বলে মনে হচ্ছে। এটি ব্যবহার করা সম্ভব dill: এই প্রশ্নের উত্তর দিতে stackoverflow.com/questions/13827543/...
ArtOfWarfare

@ আর্টঅফ ওয়ারফেয়ার: আংশিক, হ্যাঁ dill.sourceমতো কাজগুলির হয়েছে getnameএবং importableএবং getsourceসোর্স কোড (অথবা একটি আমদানিযোগ্য যে উৎপাদনের বস্তুর) কোনো বস্তুর জন্য পেয়ে যে ফোকাস। সাধারণ জিনিসের intজন্য কোনও উত্স নেই, সুতরাং এটি প্রত্যাশিতভাবে কাজ করে না (যেমন 'a = 10' এর জন্য এটি '10' ফেরায়)।
মাইক ম্যাকার্নস

এটি তবে গ্লোবালগুলির জন্য কাজ করে: >>> a = 10; print( [key for key, val in globals().items() if val is a][0] )
মাইক ম্যাকার্নস

@ মাইকম্যাকার্নস: আমি ব্যবহার না করেই এই প্রশ্নের উত্তর দেওয়ার জন্য যথাসাধ্য চেষ্টা করেছি dill, তবে আমার উত্তরটি চাওয়া হতে খানিকটা ছেড়ে গেছে (আই, যদি একই মানের জন্য আপনার একাধিক নাম থাকে তবে এটি কোনটি ব্যবহৃত হয়েছিল তা নির্ধারণ করতে পারে না। একটি অভিব্যক্তিটি পাস করুন, এটি বলতে পারে না যে এই অভিব্যক্তিটি কী ছিল, হেক, যদি আপনি কোনও অভিব্যক্তিটি পাস করেন যা নামের সাথে একই মূল্যায়ণ করে তবে এটি সেই নামটিই দেবে)) 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

সম্পাদনা: @ 0 এস দ্বারা চিহ্নিত হিসাবে এই উদাহরণটি ব্যবহার করে কাজ করে ipythonতবে সরল নয় python। এটি উভয় ক্ষেত্রে সূক্ষ্ম হওয়া উচিত, উত্স ফাইলগুলি থেকে কোড আমদানি করার সময়।


2
এটি কাজ করবে না, যেহেতু দোভাষী অনুবাদকটি বাইকোডে ফু সংকলন করবে এবং উত্স কোডটি ফেলে দেবে, যদি আপনি চালনার চেষ্টা করেন তবে একটি OSError উত্থাপন করে getsource(foo)
মিলো উইলোনডেক

@ 0 টি ভাল পয়েন্টটি যতক্ষণ না ভ্যানিলা পাইথন দোভাষীর সাথে সম্পর্কিত। তবে আইপিথন ব্যবহার করার সময় উপরের কোড উদাহরণটি কাজ করে।
টমডটম

11

আপনি এর inspectজন্য সম্পূর্ণ উত্স কোড পেতে মডিউল ব্যবহার করতে পারেন । মডিউল getsource()থেকে আপনাকে তার জন্য পদ্ধতিটি ব্যবহার করতে হবে inspect। উদাহরণ স্বরূপ:

import inspect

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

print(inspect.getsource(get_my_code))

আপনি নীচের লিঙ্কে আরও বিকল্প পরীক্ষা করে দেখতে পারেন। আপনার অজগর কোডটি পুনরুদ্ধার করুন


7

যেহেতু এই পোস্টটিকে অন্য পোস্টের নকল হিসাবে চিহ্নিত করা হয়েছে, তাই আমি এখানে "ল্যাম্বদা" মামলার জন্য উত্তর দিই, যদিও ওপি ল্যাম্বডাস সম্পর্কে নয়।

সুতরাং, লাম্বদা ফাংশনগুলির জন্য যা তাদের নিজস্ব লাইনে সংজ্ঞায়িত করা হয়নি: মার্কো.রিস্টিনের উত্তর ছাড়াও , আপনি মিনি- ল্যাম্বদা ব্যবহার করতে পারেন বা এই উত্তরটিতে প্রস্তাবিত সিমপি ব্যবহার করতে পারেন ।

  • 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

যদি আপনি নিজেই ফাংশনটি কঠোরভাবে সংজ্ঞায়িত করেন এবং এটি একটি অপেক্ষাকৃত সংক্ষিপ্ত সংজ্ঞা, নির্ভরতা ছাড়াই একটি সমাধান হ'ল ফাংশনটিকে একটি স্ট্রিংয়ে সংজ্ঞায়িত করা এবং আপনার ফাংশনে এক্সপ্রেশনটির ইওল () নির্ধারণ করা।

যেমন

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

তারপরে codeচ্ছিকভাবে ফাংশনের সাথে মূল কোডটি সংযুক্ত করতে:

func.source = funcstring

2
আপনি যদি একরকম ইন্টারেক্টিভ পাইথন ইন্টারপ্রেটার না লিখে থাকেন তবে এভাল () এর ব্যবহার আমাকে সত্যই সত্যই খারাপ বলে মনে করে। Eval কঠোর সুরক্ষা সমস্যাগুলি খুলবে। আপনি যদি কেবল স্ট্রিং লিটারালগুলি বিলোপ করার নীতি অবলম্বন করেন তবে আপনি সিনট্যাক্স হাইলাইটিং থেকে শুরু করে ক্লাসগুলির যথাযথ প্রতিচ্ছবি পর্যন্ত বিস্তৃত সদস্যদের বিভিন্ন সহায়ক আচরণের হাতছাড়া করতে পারেন।
মার্ক ই। হাজেস

2
Upvoting। @ মেহাজে: এখানে অবশ্যই নিরাপত্তা কোনও সমস্যা নয়। যদিও আপনার অন্যান্য মন্তব্যগুলি যথেষ্ট প্রাসঙ্গিক, যদিও আমি বলব সিনট্যাক্স হাইলাইটের অভাব হ'ল আইডিইয়ের ত্রুটি এবং অজগর একটি হোমোকোনিক ভাষা নয় এর সংমিশ্রণ।
নিনজেকেকো

7
আপনি সাধারণ জনগণকে পরামর্শ দিচ্ছেন যখন @ নিনজাজেকো সুরক্ষা সর্বদা একটি সমস্যা is বেশিরভাগ পাঠকই এখানে আসছেন কারণ তারা গুগল প্রশ্ন করছে। আমি মনে করি না যে অনেকে এই উত্তরটি ভারব্যাটিকমের অনুলিপি করতে যাচ্ছেন; পরিবর্তে, তারা যে ধারণাটি শিখেছিল সেগুলি গ্রহণ করবে এবং এটিকে তাদের নিজের সমস্যায় প্রয়োগ করবে।
মার্ক ই। হাজেস


0

আমি বিশ্বাস করি যে ভেরিয়েবলের নামগুলি পাইক / পিএডি / পাইও ফাইলে সংরক্ষণ করা হয় না, সুতরাং আপনার যদি সোর্স ফাইল না থাকে তবে সঠিক কোড লাইনগুলি পুনরুদ্ধার করতে পারবেন না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.