6

I have the following class:

class Foo(object):
    def setUp(self):
        self.var1 = "some value"
        self.var2 = something
    def bar(self):
        var3 = some value
    def baz(self, var):
        var4 = some value

I want to print the names of all variables defined inside the methods, like:

setUp, bar, baz, var1, var2, var3, var4

I have tried using locals(), vars(), globals() but I am getting only the names of method and not variable names.

I also tried using ast module, but no success.

atg
  • 204
  • 3
  • 18

3 Answers3

9

You can use ast.parse to generate AST node. Then ast.walk can be used to recursively iterate over the node and its` descendants. For each node you can check the type and then extract the correct attribute.

Below is an example that is working with your code but don't expect it to work as such with more complex files:

source = '''
class Foo(object):
    def setUp(self):
        self.var1 = "some value"
        self.var2 = 1
    def bar(self):
        var3 = 2
    def baz(self, var):
        var4 = var
'''

import ast

def hack(source):
    root = ast.parse(source)

    for node in ast.walk(root):
        if isinstance(node, ast.Name) and isinstance(node.ctx, ast.Store):
            yield node.id
        elif isinstance(node, ast.Attribute):
            yield node.attr
        elif isinstance(node, ast.FunctionDef):
            yield node.name

print(list(hack(source)))

Output:

['setUp', 'bar', 'baz', 'var1', 'var2', 'var3', 'var4']
niemmi
  • 17,113
  • 7
  • 35
  • 42
  • It's pretty impressive! It's just a random question, but I wonder where did you learn all of these. Did you learn it by inspecting ast module on your own? or can you recommend me a good material? –  Jan 08 '19 at 13:59
  • [Python documentation](https://docs.python.org/3/library/ast.html) is really good but nothing beats playing around with the shell. – niemmi Jan 08 '19 at 18:42
  • For this source, "def reverse(str): return str[::-1]", I don't get "str". why? – TheChosenOne Jan 02 '22 at 11:00
2
class Foo(object):
    def setUp(self):
        self.var1 = "some value"
        self.var2 = "something"
    def bar(self):
        var3 = "some value"
    def baz(self, var):
        var5 = 34


print Foo.setUp.__code__.co_varnames
print Foo.bar.__code__.co_varnames
print Foo.baz.__code__.co_varnames
Output:
('self',)
('self', 'var3')
('self', 'var', 'var5')




 #There are many more things in __code__ dict:
   # '__class__', '__cmp__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']
Notepad
  • 1,659
  • 1
  • 12
  • 14
  • Are there any more attributes like 'co_varnames' that I can access? it is giving all variable names except variable names in setUp function. – atg Dec 13 '16 at 08:11
  • Thank you very much.. this link is very helpful – atg Dec 13 '16 at 08:34
1

Can't comment yet (not enough reputation), but this looks like a duplicate of Iterate over object attributes in python.

Try this:

print([a for a in dir(obj) if not a.startswith('__') and not callable(getattr(obj,a))])
Community
  • 1
  • 1
Tim Harding
  • 299
  • 1
  • 12