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 list
node.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.
Zastanawiasz się, czy twoje wyjście powinno zawierać również "coś"? – Lafexlos
o tak, przepraszam, że zmienię moje pytanie .. Dzięki, koleś – farhawa
. 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