2015-11-05 10 views
8

Może to być dziwne, ale szukam sposobu automatycznego uzyskania wszystkich zmiennych i metod w skrypcie pythona.Jak uzyskać wszystkie nazwy zmiennych i metod używane w skrypcie

Na przykład

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

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

f = someMethod(b) 

print f 

Chcę dostać

a, b, c, someMethod, something, f 

To poglądowe przykład, chcę to zrobić dla znacznie większego skryptu.

+1

Zastanawiasz się, czy twoje wyjście powinno zawierać również "coś"? – Lafexlos

+0

o tak, przepraszam, że zmienię moje pytanie .. Dzięki, koleś – farhawa

+4

. Po co ci te wszystkie nazwy? To wygląda na potencjalny problem XY ... http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem – turbulencetoo

Odpowiedz

12

Może to zrobić całkiem łatwo. ast module Jeśli zakładamy, że źródło jest przechowywany w zmiennej o nazwie source (można odczytać z pliku):

import ast 

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

który traci zamawiania zyskać uniquification i przyjazną kolejność wyświetlania, ale może po prostu użyć rozumienie listy lub wyrażenie generator zamiast zestawu zrozumiałości, jeśli nie potrzebujesz niepowtarzalności, ale chcesz zamówić. Powstały list jest:

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

W przeciwieństwie do innych rozwiązań opublikowanych do tej pory, to spowoduje przeszukanie do klas i funkcji, aby uzyskać nazwy stosowane wewnątrz nich, i nie wymaga, aby zaimportować moduł lub klasy w celu sprawdzenia, nie wymaga też samodzielnego wdrażania przetwarzania rekurencyjnego; każdy poprawny składniowo kod Pythona będzie działał.

dziwne, na Pythonie 3 (zastępując ważnego print funkcja połączenia), można uzyskać:

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

który dodaje print (zgodnie z oczekiwaniami, jest to nazwa teraz, a nie stwierdzenie kluczowe), ale pomija x. Nie prosiłeś o x (argument otrzymany przez someMethod), a to nie powoduje jego powstania w Pythonie 3. Nazwy w prototypach funkcji nie tworzą tam węzła ast.Name, idź. Możesz wyciągnąć te informacje z węzła ast.FunctionDef z atrybutu arg każdego wpisu w pliku listnode.args.args, ale prawdopodobnie nadal nie jest on wyczerpujący; Podejrzewam, że można pominąć inne nazwy powiązane z definicją, np. w deklaracjach klasowych z dziedziczeniem. Będziesz musiał przejrzeć kilka przykładów, aby upewnić się, że wszystko sprawdzasz (zakładając, że chcesz rzeczy takie jak x i chcesz pracować na Pythonie 3).

To powiedziawszy, x pojawi się dobrze, jeśli się do niego odwołasz; jeśli przekazałeś go do do_something lub użyłeś go w jakikolwiek inny sposób oprócz otrzymywania i odrzucania go, byłby wyświetlany.

Można także dołożyć starań, aby obsłużyć tylko nazwy przypisane, nie używany (wykluczyć do_something, range) poprzez rozszerzenie test:

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

Ale to będzie również spaść someMethod (zarówno Py2 i Py3), ponieważ sama definicja nie generuje wartości ast.Name, a jedynie jej użycie. Więc znowu, musielibyście zagłębić się nieco głębiej w obiekty wewnętrzne ast.Node dla ast.FunctionDef, ast.ClassDef itp., Aby uzyskać nazwy, które nie są bezpośrednio podane.

1

Możesz użyć do tego dir() wbudowanego. Załóżmy, że zapisujesz swój plik jako test.py. Można to zrobić w następujący sposób:

>>> import test 

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

Można użyć globals() funkcji, aby uzyskać wszystkie globalne nazwy w module, a ponieważ Python ma kilka globalnych nazw domyślnie jak __builtins__ można uciec im:

Od globals() powrót słownika zawiera nazwy i wartości oraz nazwy wbudowane mają format jak __builtins__ można filtrować je:

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

Należy jednak pamiętać, że nie daje lokalnych nazw wewnątrz funkcja taka jak something. Do tego celu można zobaczyć inspect moduł https://docs.python.org/3/library/inspect.html#inspect.getmembers

+0

A 'locals' również jako OP chce" coś "do wydrukowania. –

+0

@BhargavRao: 'locals' nie działa, dopóki nie zostanie wykonane podczas wywoływania funkcji. Nie może dostarczyć ci lokalnych dla funkcji, której nie używasz. – ShadowRanger

+0

@ShadowRanger Yep. Poprawny. Ale właśnie dodałem ten komentarz, aby dopasować wyjście OP. (OP wywołuje to wewnątrz funkcji, a także wypisze 'x', argument). Pozdrowienia. –

2

Istnieje wiele zmiennych importowanych przez pytona więc masz zamiar uzyskać długą listę, ale vars() zadziała.

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

def someMethod(x): 
    something = 4 
    return something 

f = someMethod(b) 

print vars() 

w terminalu:

$ 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
Można je posprzątać trochę sprawdzając na typ zmiennych

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 

w terminalu:

$ python temp.py 
a 
c 
b 
myList 
f 
Powiązane problemy