简体   繁体   中英

Can one use closures to simplify functions in Python?

Imagine if you want to make a closure function that decides some option for what its inner function does. In this example, we have an inner function that decides whether a number is even, but the generator decides whether the number zero is even, as if there were a debate.

def generate_is_even(reject_zero):
    def is_even(x):
        return (x % 2 == 0 and x != 0) if reject_zero else x % 2 == 0
    return is_even

If is_even(x) is run millions of times, it appears reject_zero will still be checked every single time is_even(x) is run! My actual code has many similar 'options' to create a function that is run millions of times, and it would be inconvenient to write functions for every combination of options. Is there a way to prevent this inefficiency, or does some implementation of Python simplify this?

You seem to be looking for something like macros in C. Unfortunately, Python is not compiled (not the same way as C, for purists), and I don't see direct solutions for your need.

Still, you could set all your parameters at the beginning of runtime, and select the functions at this moment according to the values of the parameters. For instance, your function generator would be something like:

def generate_is_even(reject_zero):
    def is_even_true(x):
        return (x % 2 == 0 and x != 0)
    def is_even_false(x):
        return x % 2 == 0
    return (is_even_true if reject_zero else is_even_false)

def setup(reject_zero, arg2, arg3):
    is_even = generate_is_even(reject_zero)

The backlash of this is having to write a generator for each function that handles such a parameter. In the case you present, this is not a big problem, because there are only two versions of the function, that are not very long.

You need to ask yourself when it is useful to do so. In your situation, there is only one boolean comparison, which is not really resource-consuming, but there might be situations where generating the functions before could become worthwhile.

consider caching all your options in a list, and the generated function only iterates the chosen function

def generate_is_even(**kwargs):
    options = {'reject_zero': lambda x: x != 0}
    enabled = [options[o] for o in options if o in kwargs and kwargs[o]]
    def is_even(x):
        return all([fn(x) for fn in enabled]) and x % 2 == 0
    return is_even

then you could use

is_even_nozero = generate_is_even(reject_zero=True)
is_even_nozero(0) # gives False
is_even = generate_is_even()
is_even(0) # gives True

if you need add options then add it to the options dict , and you could usee new_option=True is the generate_is_even function to enable it

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM