2015-11-05 15 views
8

Có thể lạ nhưng tôi đang tìm cách tự động nhận tất cả biến và phương thức trong tập lệnh python.Cách lấy tất cả tên biến và phương thức được sử dụng trong tập lệnh

Ví dụ,

a = 1 
b = 2 
c = 3 
myList = range(10) 

def someMethod(x): 
    something = do_something() 
    return something 

f = someMethod(b) 

print f 

Tôi muốn nhận

a, b, c, someMethod, something, f 

Đây là một Ví dụ minh hoạ, tôi muốn làm việc này cho một kịch bản lớn hơn nhiều.

+1

Chỉ cần tự hỏi, liệu đầu ra của bạn có bao gồm 'something'? – Lafexlos

+0

oh vâng, tôi xin lỗi tôi sẽ sửa câu hỏi của tôi .. Cảm ơn dude – farhawa

+4

Tại sao bạn cần tất cả các tên này? Điều này trông giống như một vấn đề XY tiềm năng ... http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem – turbulencetoo

Trả lời

12

ast module có thể làm điều này khá dễ dàng. Nếu chúng ta giả định nguồn được lưu trữ trong một biến có tên source (có thể được đọc từ một tập tin):

import ast 

root = ast.parse(source) 
names = sorted({node.id for node in ast.walk(root) if isinstance(node, ast.Name)}) 

mà mất đặt hàng để đạt được uniquification và thứ tự hiển thị thân thiện, nhưng bạn chỉ có thể sử dụng một sự hiểu biết danh sách hoặc biểu hiện máy phát điện thay vì một thiết lập hiểu nếu bạn không cần độc đáo nhưng muốn đặt hàng. Kết quả là list là:

['a', 'b', 'c', 'do_something', 'f', 'myList', 'range', 'someMethod', 'something', 'x'] 

Không giống như các giải pháp khác được đăng cho đến nay, điều này sẽ recurse vào lớp học và chức năng để có được những tên được sử dụng bên trong chúng, và không yêu cầu bạn phải nhập khẩu các mô-đun hoặc lớp để kiểm tra, cũng không yêu cầu bạn phải tự thực hiện xử lý đệ quy; mọi mã Python hợp lệ sẽ hoạt động.

Nhưng kỳ lạ, trên Python 3 (thay thế một giá trị print chức năng cuộc gọi), bạn nhận được:

['a', 'b', 'c', 'do_something', 'f', 'myList', 'print', 'range', 'someMethod', 'something'] 

mà thêm print (như mong đợi, đó là một tên bây giờ, không phải là một tuyên bố từ khóa), nhưng bỏ qua x. Bạn đã không yêu cầu x (đối số nhận được bởi someMethod), và điều này không tạo ra nó trên Python 3. Tên trong các nguyên mẫu hàm xuất hiện để không tạo ra một nút ast.Name ở đó, đi con số. Bạn có thể lấy thông tin đó ra khỏi nút ast.FunctionDef từ thuộc tính arg của mỗi mục nhập trong listnode.args.args nhưng có thể vẫn chưa hoàn chỉnh; Tôi nghi ngờ các tên liên quan đến định nghĩa khác có thể bị bỏ qua, ví dụ: trong khai báo lớp với thừa kế. Bạn sẽ cần phải poke xung quanh với một số ví dụ để đảm bảo rằng bạn đang kiểm tra tất cả mọi thứ (giả sử bạn muốn các công cụ như x và muốn làm việc trên Python 3).

Điều đó nói rằng, x sẽ hiển thị tốt nếu bạn tham chiếu; nếu bạn chuyển nó đến do_something hoặc sử dụng nó theo bất kỳ cách nào ngoài việc nhận và loại bỏ nó, nó sẽ hiển thị.

Bạn cũng có thể làm cho một nỗ lực để chỉ xử lý tên giao cho, không được sử dụng (để loại trừ do_something, range) bằng cách mở rộng các thử nghiệm để:

names = sorted({node.id for node in ast.walk(root) if isinstance(node, ast.Name) and not isinstance(node.ctx, ast.Load)}) 

Nhưng điều đó cũng sẽ thả someMethod (trong cả hai Py2 và Py3) bởi vì bản thân định nghĩa không tạo ra một ast.Name, chỉ việc sử dụng nó. Vì vậy, một lần nữa, bạn phải nghiên cứu sâu hơn một chút về nội bộ ast.Node cho ast.FunctionDef, ast.ClassDef, v.v. để lấy các tên không trực tiếp là walk.

1

Bạn có thể sử dụng dir() được tích hợp sẵn cho việc này. Giả sử bạn lưu tệp của mình dưới dạng test.py. Bạn có thể làm như sau:

>>> import test 

>>> dir(test) 
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'a', 'b', 'c', 'f', 'myList', 'someMethod'] 
>>> 
2

Bạn có thể sử dụng globals() chức năng để có được tất cả các tên toàn cầu trong module của bạn, và vì trăn có một số tên toàn cầu bằng cách mặc định như __builtins__ bạn có thể thoát khỏi chúng:

Kể từ globals() trở lại một cuốn từ điển chứa các tên và các giá trị và tên BUILTIN có một định dạng như __builtins__ bạn có thể lọc chúng:

>>> print([var for var in globals().keys() if '__' not in var]) 
['someMethod', 'c', 'b', 'a', 'myList'] 

Nhưng lưu ý rằng nó sẽ không cung cấp cho bạn những cái tên địa phương bên trong chức năng như something. Để đạt được mục tiêu đó, bạn có thể thấy mô hình inspecthttps://docs.python.org/3/library/inspect.html#inspect.getmembers

+0

Và 'local' cũng như OP muốn 'something' được in. –

+0

@BhargavRao: 'locals' không hoạt động trừ khi nó được thực hiện trong khi hàm đang được gọi. Nó không thể giúp bạn có được người dân địa phương cho một chức năng mà bạn không chạy. – ShadowRanger

+0

@ShadowRanger Yep. Chính xác. Nhưng tôi vừa thêm bình luận đó để phù hợp với đầu ra OPs. (OP đang gọi bên trong hàm. Nó cũng sẽ in 'x', đối số). Trân trọng. –

2

Có rất nhiều biến được nhập bởi python để bạn có danh sách dài nhưng vars() sẽ hoạt động.

a = 1 
b = 2 
c = 3 
myList = range(10) 

def someMethod(x): 
    something = 4 
    return something 

f = someMethod(b) 

print vars() 

trong terminal:

$ python temp.py 
{'a': 1, 'c': 3, 'b': 2, 'myList': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 'f': 4, '__builtins__': <module '__builtin__' (built-in)>, '__file__': 'temp.py', '__package__': None, 'someMethod': <function someMethod at 0x10759b488>, '__name__': '__main__', '__doc__': None} 

EDIT
Bạn có thể làm sạch nó lên một chút bằng cách kiểm tra cho loại biến

import types 
all_vars = dict(vars()) 
for var_name, var in all_vars.iteritems(): 
    if type(var) not in [types.ModuleType, types.FunctionType] and not var_name.startswith("_"): 
     print var_name 

trong terminal:

$ python temp.py 
a 
c 
b 
myList 
f 
Các vấn đề liên quan