Helpex - Trao đổi & giúp đỡ Đăng nhập
315

Giả sử tôi có một hàm Python như được định nghĩa dưới đây:

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

Tôi có thể lấy tên của hàm bằng cách sử dụng foo.func_name. Làm thế nào tôi có thể lập trình lấy mã nguồn của nó, như tôi đã gõ ở trên?

315 hữu ích 4 bình luận 170k xem chia sẻ
12 trả lời 12
449

Nếu chức năng là từ một tệp nguồn có sẵn trên hệ thống tệp, thì inspect.getsource(foo)có thể hữu ích:

Nếu foođược định nghĩa là:

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

Sau đó:

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

Trả về:

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

Nhưng tôi tin rằng nếu hàm được biên dịch từ một chuỗi, luồng hoặc được nhập từ một tệp được biên dịch, thì bạn không thể truy xuất mã nguồn của nó.

449 hữu ích 5 bình luận chia sẻ
175

Các kiểm tra mô-đun có phương pháp để lấy mã nguồn từ đối tượng python. Dường như nó chỉ hoạt động nếu nguồn được đặt trong một tập tin mặc dù. Nếu bạn có điều đó tôi đoán bạn sẽ không cần lấy nguồn từ đối tượng.

175 hữu ích 4 bình luận chia sẻ
79

dis là bạn của bạn nếu mã nguồn không có sẵn:

>>> 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
79 hữu ích 3 bình luận chia sẻ
62

Nếu bạn đang sử dụng IPython, thì bạn cần gõ "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
62 hữu ích 1 bình luận chia sẻ
54

Mặc dù tôi thường đồng ý rằng đó inspectlà một câu trả lời hay, tôi không đồng ý rằng bạn không thể lấy mã nguồn của các đối tượng được xác định trong trình thông dịch. Nếu bạn sử dụng dill.source.getsourcetừ dill, bạn có thể lấy nguồn hàm và lambdas, ngay cả khi chúng được xác định tương tác. Nó cũng có thể lấy mã từ các phương thức và hàm lớp bị ràng buộc hoặc không ràng buộc được xác định trong các dòng chữ ... tuy nhiên, bạn có thể không thể biên dịch mã đó mà không có mã của đối tượng kèm theo.

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

>>> 
54 hữu ích 5 bình luận chia sẻ
21

Để mở rộng câu trả lời của runeh:

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

EDIT: Như được chỉ ra bởi @ 0sh ví dụ này hoạt động bằng cách sử dụng ipythonnhưng không đơn giản python. Nó sẽ ổn trong cả hai, tuy nhiên, khi nhập mã từ các tệp nguồn.

21 hữu ích 2 bình luận chia sẻ
10

Bạn có thể sử dụng inspectmô-đun để có được mã nguồn đầy đủ cho điều đó. Bạn phải sử dụng getsource()phương pháp cho điều đó từ inspectmô-đun. Ví dụ:

import inspect

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

print(inspect.getsource(get_my_code))

Bạn có thể kiểm tra thêm các tùy chọn trên liên kết dưới đây. lấy mã trăn của bạn

10 hữu ích 0 bình luận chia sẻ
4

tóm tắt:

import inspect
print( "".join(inspect.getsourcelines(foo)[0]))
4 hữu ích 0 bình luận chia sẻ
3

Nếu bạn tự xác định hàm một cách nghiêm ngặt và đó là một định nghĩa tương đối ngắn, một giải pháp không phụ thuộc sẽ là xác định hàm trong một chuỗi và gán eval () của biểu thức cho hàm của bạn.

Ví dụ

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

sau đó tùy chọn đính kèm mã gốc vào hàm:

func.source = funcstring
3 hữu ích 3 bình luận chia sẻ
1

Xin lưu ý rằng các câu trả lời được chấp nhận chỉ hoạt động nếu lambda được đưa ra trên một dòng riêng biệt. Nếu bạn chuyển nó dưới dạng đối số cho hàm và muốn lấy mã của lambda làm đối tượng, thì vấn đề sẽ hơi phức tạp vì inspectsẽ cung cấp cho bạn toàn bộ dòng.

Ví dụ: xem xét một tệp test.py:

import inspect

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

if __name__ == "__main__":
    main()

Thực hiện nó mang lại cho bạn (nhớ sự cố gắng!):

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

Để lấy mã nguồn của lambda, theo tôi, cách tốt nhất của bạn là phân tích lại toàn bộ tệp nguồn (bằng cách sử dụng f.__code__.co_filename) và khớp với nút lambda AST theo số dòng và ngữ cảnh của nó.

Chúng tôi đã phải làm một cách chính xác rằng trong thư viện thiết kế theo hợp đồng của chúng tôi icontract kể từ khi chúng tôi phải phân tích các chức năng lambda chúng tôi vượt qua trong như các đối số để trang trí. Đó là quá nhiều mã để dán ở đây, vì vậy hãy xem việc thực hiện chức năng này .

1 hữu ích 0 bình luận chia sẻ
0

Tôi tin rằng tên biến không được lưu trong tệp pyc / pyd / pyo, vì vậy bạn không thể truy xuất các dòng mã chính xác nếu bạn không có tệp nguồn.

0 hữu ích 0 bình luận chia sẻ
0

Nếu bạn sử dụng IPython, một tùy chọn khác là sử dụng ??sau tên hàm để xem mã nguồn của nó. Đây là một ví dụ:

[nav] In [1]: def foo(arg1,arg2):
         ...:     #do something with args
         ...:     a = arg1 + arg2
         ...:     return a

[nav] In [2]: foo??
Signature: foo(arg1, arg2)
Docstring: <no docstring>
Source:
def foo(arg1,arg2):
    #do something with args
    a = arg1 + arg2
    return a
0 hữu ích 0 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ python function , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading