4

I do not want to import my module. I have to count the number of functions given the .py file path. What is the best way to do so?

One thing I thought about was to count the number of "def" in my code, but it does not seem like the best way to go about this. Is there any better way to count the number of functions?

Lana
  • 1,124
  • 1
  • 8
  • 17
  • 3
    I'd say counting the number of occurrences of `def` is actually the best way to do it. – RobertR May 29 '16 at 20:29
  • 1
    do you need to include dynamically created functions? what if you did `from math import sin` would that count towards the number of functions in the file? – Tadhg McDonald-Jensen May 29 '16 at 20:32
  • If you're going to count the number of `def`s, you should make sure those are tokens (i.e counting `def ` and not just `def`) because you can have a variable with the word `def` inside. You should also consider whether or not counting inner functions (i.e a function defined inside of another function) or methods (functions defined for a class) count. What's wrong with importing the module, though? It'd arguably be much simpler and you can use `inspect` to get the information you want. – Rushy Panchal May 29 '16 at 20:32
  • 1
    No. Just functions in the form def my_function: ... – Lana May 29 '16 at 20:32
  • 1
    @RobertR No. I can think of 2 cases where counting `def` would fail: 1) if there is a string containing def 2) if there is a block commented def! – Gurupad Hegde May 29 '16 at 20:33
  • 1
    You're sorted limited to your options if you don't want to import it. Otherwise you'd be able to do `len(dir(module))` and nifty things. But since you're limited to reading a string of content, you sorta have to check for `def(` . – Torxed May 29 '16 at 20:33
  • I think importing will not work, because I need to run that script on a directory, and it can look at all of its files and their functions :/ – Lana May 29 '16 at 20:36
  • if that is all that restricts you from importing the files then take a look at [this question](http://stackoverflow.com/questions/10043485/python-import-every-module-from-a-folder) – Tadhg McDonald-Jensen May 29 '16 at 20:41

6 Answers6

4

To count the top level definition, use ast module like this:

import ast

with open(filename) as f:
    tree = ast.parse(f.read())
    sum(isinstance(exp, ast.FunctionDef) for exp in tree.body)
malbarbo
  • 10,717
  • 1
  • 42
  • 57
3

You can use ast.NodeVisitor:

import inspect
import importlib
import ast

class CountFunc(ast.NodeVisitor):
    func_count = 0
    def visit_FunctionDef(self, node):
        self.func_count += 1


mod = "/path/to/some.py"

p = ast.parse(open(mod).read())

f = CountFunc()
f.visit(p)

print(f.func_count)

If you wanted to include lambdas you would need to add a visit_Lambda:

 def visit_Lambda(self, node):
    self.func_count += 1

That will find all defs including methods of any classes, we could add more restrictions to disallow that:

class CountFunc(ast.NodeVisitor):
    func_count = 0

    def visit_ClassDef(self, node):
        return 

    def visit_FunctionDef(self, node):
        self.func_count += 1


    def visit_Lambda(self, node):
        self.func_count += 1

You can tailor the code however you like, all the nodes and their attributes are described in the greentreesnakes docs

Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
1

Padraic beats me to it, but here is my code, which works with Python 2 and Python 3.

from __future__ import print_function
import ast

class FunctionCounter(ast.NodeVisitor):
    def __init__(self, filename):
        self.function_count = 0
        with open(filename) as f:
            module = ast.parse(f.read())
            self.visit(module)

    def visit_FunctionDef(self, node):
        print('function: {}'.format(node.name))
        self.function_count += 1

    # Uncomment this to disable counting methods, properties within a
    # class
    # def visit_ClassDef(self, node):
    #     pass

if __name__ == '__main__':
    counter = FunctionCounter('simple.py')
    print('Number of functions: {}'.format(counter.function_count))

Discussion

  • This code not only count the function at the module level, it also count functions (method and properties) nested within class definitions.
  • To disable counting functions in the class definitions, uncomment the 2 lines for visit_ClassDef
Hai Vu
  • 37,849
  • 11
  • 66
  • 93
1

You can use

len(dir(module))

Hope it helps

Naveen Kumar
  • 277
  • 4
  • 5
  • 1
    this won't work without importing `module` first, will it? even if the original question clearly smells of x-y, it does very explicitly say: "i do not want to import my module" -- therefore, i don't think we can consider this answer correct, especially since comments from 2016 already specifically said this would have been an option if it weren't for the "no importing" constraint: https://stackoverflow.com/questions/37514636/good-way-to-count-number-of-functions-of-a-python-file-given-path/63896309#comment62522817_37514636 – rsandwick3 Sep 15 '20 at 08:33
  • 1
    Yes, We need to import the module before finding the number of functions for this code !! – Naveen Kumar Sep 17 '20 at 06:38
0

you can use the pyclbr module to get results of the module, the only catch is that you need to use the name of the module as you would import it instead of the file path, this benefits from also recognizing from X import Y for python source based modules (not builtin ones like math)

from pyclbr import readmodule_ex, Function
#readmodule_ex is function 1

def test(): #2
    pass
def other_func(): #3
    pass

class Thing:
    def method(self):
        pass


result = readmodule_ex("test") #this would be it's own file if it is test.py

funcs = sum(isinstance(v,Function) for v in result.values())

print(funcs)
Tadhg McDonald-Jensen
  • 20,699
  • 5
  • 35
  • 59
0

My answer is an edit to the answer of @ Naveen Kumar because I can not edit his answer at the moment. You can use

import module

len(dir(module))

i.e:

import math
print(len(dir(math)))

output:

 63
Dharman
  • 30,962
  • 25
  • 85
  • 135