4

Not a complicate question but I couldn't find an explicit answer around.

For example, if I want to find out the number of prime numbers in a list of numbers:

def count_prime(lst):
    """lst is a list of integers"""

    def isPrime(n):
        return all(n % div != 0 for div in range(2, int(n**0.5) + 1)) if n > 1 else False

    result = 0
    for num in lst:
        if isPrime(num):
            result += 1

    return result

This looks very simple, but I put isPrime(n) inside of the main function.

How does it compare to:

def isPrime(n):
    return all(n % div != 0 for div in range(2, int(n**0.5) + 1)) if n > 1 else False

def count_prime(lst):
    """lst is a list of integers"""

    result = 0
    for num in lst:
        if isPrime(num):
            result += 1

    return result

My question is: Does it make any difference? Which one is preferred?

jxie0755
  • 1,682
  • 1
  • 16
  • 35
  • @match I think that one is mainly asking about high-order functions which the function return a new function? Not very similar to my question? – jxie0755 Mar 19 '18 at 15:45
  • I would define it in the global scope if you use it in multiple places, not just in one function. – internet_user Mar 19 '18 at 15:46
  • 1
    The linked question demonstrates the biggest difference between nested and top-level functions, which is the biggest reason to use them—closures. The local function can use local variables from the outer function. Which means you can make different “adder” functions that add different numbers, with the same code. But your question is more general—are there reasons to use nested functions besides closures? So maybe it _should_ be reopened. – abarnert Mar 19 '18 at 16:02
  • Or maybe you should ask a more specific question, like: is there any stylistic or readability to use a nested function even when I don’t have a closure as in (link)? Or: is there any performance difference between nested and top-level functions when both have the same overall effect? Or: how does the implementation (in CPython if it matters) differ in creating and calling the nested and top-level versions of this function? If you know which one of those you’re interested in, they all seem less likely to be closed—but of course do your own search for dups first. – abarnert Mar 19 '18 at 16:05
  • @internet_user But I wouldn't know that until I realize I write something in the future, right? – jxie0755 Mar 19 '18 at 16:05
  • I don’t understand your last comment. What wouldn’t you know? Are you talking about accidentally writing a nested function with a closure? Or writing a SO question that’s about closures but you didn’t know it? Or...? – abarnert Mar 19 '18 at 16:06
  • @abarnert It's asking as to which style is preferred. I would suggest a good rule of thumb is to limit the scope of *everything* as much as possible. Later you can always expand it – Caleth Mar 19 '18 at 16:08
  • @abarnert my last comment is to answer the comment that "if `isPrime` will be used in other functions, then I should put it in the global frame". But I wouldn't know if other functions will use it or not, until I start writing one in the future. – jxie0755 Mar 19 '18 at 16:09
  • @Caleth Just so that I understand it: nested function will increase scoeps? so to put it in the global frame is limiting the scope right? – jxie0755 Mar 19 '18 at 16:12
  • @Code_Control_jxie0755 no, the other way around. *Many more* things can see the name `isPrime` if it is in global scope than if it is in the scope of `find_prime` – Caleth Mar 19 '18 at 16:13
  • Aside: `find_prime` doesn't find one prime, it counts multiple primes. Also have a look at the `quantify` [itertools recipe](https://docs.python.org/3/library/itertools.html#itertools-recipes) – Caleth Mar 19 '18 at 16:25
  • Although the linked question's accepted answer clearly states when to use nested funcs, I am in favor of not nesting (opinion based). Unfortunately, the question was marked as a duplicate before I was able to post my answer / arguments. – CristiFati Mar 19 '18 at 16:29
  • @Caleth Yes, thank for the catch, I mean to count it, I did not name it properly in this example. I will fix that. – jxie0755 Mar 19 '18 at 17:09
  • @Caleth I see!! Thanks! So actually it is preferred to be nested, unless I plan to use it in some other functions. – jxie0755 Mar 19 '18 at 17:11
  • I think the best rule of thumb here is slightly more complicated. (Assuming you don't need a closure, and the performance cost of a global lookup is irrelevant to your problem) the key difference is that nested functions are not reusable, but they also don't pollute the global namespace. So, if you might want to reuse the function, make it global; if you definitely don't want anyone reusing it, make it nested; if you're not sure, at least you know the metric you're trying to decide on. – abarnert Mar 19 '18 at 17:27
  • For a bit more on that: One good reason to not want the function to be reused is if you think you may need to change not just the implementation, but even the interface, of your "helper" function for a future version of your "public" function. In that case, you definitely don't want any callers relying on `isPrime`. Another reason you might not want to expose it is that it's correct/reliable/efficient for for the particular use your public function needs, but not for other uses someone might try to put it to (e.g., it returns the wrong thing for 1, but you don't care here). And so on. – abarnert Mar 19 '18 at 17:30
  • @Caleth While Python is a pretty opinionated language as far as idioms go (and that's actually one of the reasons I like it), if the question really is just "which equivalent style is preferred for opinionated reasons", I think that might just get re-closed as "question calls for an opinion". That's why I think it would be better to refine the question into something that clearly could have an objective answer. – abarnert Mar 19 '18 at 17:31

1 Answers1

0

I think both approaches are valid. isPrime is very small, so it can be embedded easily. If you want to reuse the function, it makes sense to define it globally.

mbuechmann
  • 5,413
  • 5
  • 27
  • 40
  • The "if you want to reuse" is very important here, but I think the size of the function is a red herring that's rarely the key question, and you've put it first. – abarnert Mar 19 '18 at 17:32
  • I think the length of the embedded function is a concern, too. If the embedded function is very long and the embedding function itself is very short, that could make the code less readable. – mbuechmann Mar 20 '18 at 09:35