2

For a project, I am trying to read through a python file and keep a list of all the variable being used within a certain function. I am reading through the lines in the python file in string format and then focusing on a line where starting with "def". For the purpose of this example pretend we have the following line identified:

def func(int_var:int,float_var=12.1,string_var=foo()):

I want to use regex or any other method to grab the values within this function declaration.

I want to grab the string "int_var:int,float_var=12.1,string_var=foo()", and later split it based on the commas to get ["int_var:int","float_var=12.1","string_var=foo()"]

I am having a lot of trouble being able to isolate the items between the parenthesis corresponding to 'func'.

Any help creating a regex pattern would be greatly appreciated!

Ajax1234
71.7k9 gold badges68 silver badges110 bronze badges
asked Nov 21, 2021 at 18:41
1
  • I'd also like to grab the function name ('func') as a separate variable! Commented Nov 21, 2021 at 18:42

2 Answers 2

2

Instead of regex, it is much easier and far more robust to use the ast module:

import ast
s = """
def func(int_var:int,float_var=12.1,string_var=foo()):
 pass
"""
def form_sig(sig):
 a = sig.args
 d = [f'{ast.unparse(a.pop())}={ast.unparse(j)}' for j in sig.defaults[::-1]][::-1]
 v_arg = [] if sig.vararg is None else [f'*{sig.vararg.arg}']
 kwarg = [] if sig.vararg is None else [f'*{sig.kwark.arg}']
 return [*map(ast.unparse, a), *d, *v_arg, *kwarg]
f = [{'name':i.name, 'sig':form_sig(i.args)} for i in ast.walk(ast.parse(s)) 
 if isinstance(i, ast.FunctionDef)] 

Output:

[{'name': 'func', 'sig': ['int_var: int', 'float_var=12.1', 'string_var=foo()']}]
answered Nov 21, 2021 at 18:52
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for taking the time to write this up! Super useful.
1
func_pattern = re.compile(r'^\s*def\s(?P<name>[A-z_][A-z0-9_]+)\((?P<args>.*)\):$')
match = func_pattern.match('def my_func(arg1, arg2):')
func_name = match.group('name') # my_func
func_args = match.group('args').split(',') # ['arg1', 'arg2']
answered Nov 21, 2021 at 18:56

4 Comments

I appreciate this!
I noticed that this solution fails when there are spaces before or after the commas. For example: This works --> def foo(x,y,z=foo1()) This fails --> def foo( x ,y , z=foo1()) I was trying to see the pattern for identifying the arguments but couldn't determine how to modify it to allow for spaces.
I'm not sure I understand. The ".*" found in the pattern should match any type of character in between the parentheses, spaces included. A quick check on my end indicates that the pattern matches on both of the examples you gave (after adding a colon to the end, strings not ending with a colon will not be matched by the pattern I gave). Perhaps the issue is that we don't want spaces in the output? If you would like to remove the whitespace that show up around the arguments after you get your match you could do: func_args = [arg.strip() for arg in match.group('args'),split(',')]
The split(',') does not work in cases of argument types like "dict[str, int]"

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.