2014-10-28 13 views
6

Trong trăn, bạn có thể làm fname.__code__.co_names để truy xuất danh sách các hàm và những thứ chung mà hàm tham chiếu. Nếu tôi làm fname.__code__.co_varnames, điều này bao gồm các chức năng bên trong, tôi tin.python - liệt kê tất cả các chức năng bên trong của một hàm?

Có cách nào về cơ bản thực hiện inner.__code__.co_names không? bằng cách bắt đầu bằng một chuỗi trông giống như 'inner', như được trả về bởi co_varnames?

+0

Đây có phải là điều một cấp hoặc bạn cũng muốn có chức năng lồng nhau không? –

Trả lời

3

I don' Tôi nghĩ rằng bạn có thể kiểm tra đối tượng mã vì các hàm bên trong là lười và các đối tượng mã của chúng chỉ là c reated chỉ trong thời gian. Những gì bạn có thể muốn xem thay vào đó là mô-đun ast. Dưới đây là một ví dụ nhanh:

import ast, inspect 

# this is the test scenario 
def function1(): 
    f1_var1 = 42 
    def function2(): 
     f2_var1 = 42 
     f2_var2 = 42 
     def function3(): 
      f3_var1 = 42 

# derive source code for top-level function 
src = inspect.getsource(function1) 

# derive abstract syntax tree rooted at top-level function 
node = ast.parse(src) 

# next, ast's walk method takes all the difficulty out of tree-traversal for us 
for x in ast.walk(node): 
    # functions have names whereas variables have ids, 
    # nested-classes may all use different terminology 
    # you'll have to look at the various node-types to 
    # get this part exactly right 
    name_or_id = getattr(x,'name', getattr(x,'id',None)) 
    if name_or_id: 
     print name_or_id 

Kết quả là: Function1, function2, f1_var1, function3, f2_var1, f2_var2, f3_var1. từ chối trách nhiệm bắt buộc: có lẽ không phải là một lý do chính đáng để làm kiểu này mà .. nhưng có niềm vui :)

Oh và nếu bạn chỉ muốn tên của các chức năng bên trong?

print dict([[x.name,x] for x in ast.walk(ast.parse(inspect.getsource(some_function))) if type(x).__name__=='FunctionDef']) 
+0

Suy nghĩ tốt. Điều này sẽ thất bại nếu chạy từ một 'pyc', nhưng tôi đoán đó là điều bất thường. – goncalopp

+0

Cảm ơn bạn, điều này trông giống như những gì tôi sẽ tìm kiếm. Lý do tôi làm điều đó là vì tôi đang cố gắng thực hiện các dấu vết chức năng, và tôi muốn bao gồm các chức năng bên trong trong đó. – user3475234

3

Trong Python 3.4+ bạn có thể lấy tên bằng cách sử dụng dis.get_instructions. Để hỗ trợ các chức năng lồng nhau cũng bạn cần phải đệ quy loop qua từng đối tượng mã bạn gặp phải:

import dis 
import types 

def get_names(f): 
    ins = dis.get_instructions(f) 
    for x in ins: 
     try: 
      if x.opcode == 100 and '<locals>' in next(ins).argval\ 
               and next(ins).opcode == 132: 
       yield next(ins).argrepr 
       yield from get_names(x.argval) 
     except Exception: 
      pass 

Demo:

def func(): 
    x = 1 
    y = 2 
    print ('foo') 
    class A: 
     def method(self): 
      pass 
    def f1(): 
     z = 3 
     print ('bar') 
     def f2(): 
      a = 4 
      def f3(): 
       b = [1, 2, 3] 
    def f4(): 
     pass 

print(list(get_names(func))) 

Đầu ra:

['f1', 'f2', 'f3', 'f4'] 
Các vấn đề liên quan