0

I have two files in a library I am creating:

file1.py

def func1(a, b):
    c = a + b
    return c

file2.py

def func2(a, b):
    c = a - b
    return c

Now I want each file to have a function that takes the function from that file as an argument, but otherwise does the same thing. So a function like:

def new_func(f, x, y, z):
    return f(x, y) * z

Since I don't want to repeat myself, I would prefer to define this function in a separate file, then use some sort of function inheritance that creates a partial function with the first argument set to the func at the beginning of that file. So users can access new_func using file1.new_func(x, y, z) and file2.new_func(x, y, z).

For context, I have many new_funcs I want to add to about a handful of files. Each would take in the func at the beginning of the file as a fixed argument, so essentially a partial function. But beyond that, they would all do the same thing with that func.

Is this possible using the functional programming paradigm?

I have Googled like crazy about function inheritance, partial functions and decorators (as I thought that might help), but have so far found nothing like what I am attempting to do.

EDIT: To be clear, the point of this question is (1) multiple files each with a single function and (2) a set of partial functions that would take in the single function as the fixed parameter, but without copying and pasting the partial functions to each file. That is why I mention inheritance, as I essentially want to do some sort of function inheritance rather than copying and pasting functions across files.

3
  • 1
    funny you used the actual term... docs.python.org/3/library/functools.html#functools.partial If you want a more specific answer you'd have to ask a more specific question Commented Jun 19 at 20:58
  • For that don't I still have to copy the same function across the files? The point of my question is that I don't want to do that as I don't want to repeat myself. That is why I mention decorators, I was hoping something like that would allow me to declare only one function and use it across multiple files. Commented Jun 19 at 22:15
  • This question is similar to: How does functools partial do what it does?. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. Commented Jun 19 at 22:30

3 Answers 3

1

Your question asks to mix two things (inheritance and partial function binding) together that are both possible to do separately, but not really something that can happen automatically together.

In Python inheritance is strictly a thing for classes. You're not using classes, but if you did, you could get a base class new_function to call different function1 methods on its subclasses:

class BaseClass:
    def base_function(self, a, b, c):
        return self.child_function(a, b) * c

class File1Class(BaseClass):
    def child_function(self, a, b):
        return a+b

class File2Class(BaseClass):
    def child_function(self, a, b):
        return a-b

f1c = File1Class()
f2c = File2Class()
print(f1c.base_function(1, 2, 3)) # prints 9
print(f2c.base_function(1, 2, 3)) # prints -3

If you don't want to use classes, you can partially bind functions to do what you want, but it won't happen automatically, since you don't have any inheritance hierarchy. You'll need to do the partial binding yourself:

def function1(a, b):
    return a+b

def function2(a, b):
    return a-b

def new_function(f, a, b, c):
    return f(a, b)*c

from functools import partial

new_function1 = partial(new_function, function1)
new_function2 = partial(new_function, function2)

print(new_function1(1, 2, 3)) # prints 9
print(new_function2(1, 2, 3)) # prints -3
Sign up to request clarification or add additional context in comments.

Comments

0

If you want to use inheritance then you can declare the functions as classes and implement the __call__ method:

# file1.py
class Func1:
    def __call__(self, a, b):
        return a + b
# file2.py
class Func2:
    def __call__(self, a, b):
        return a - b
# file3.py
from file1 import Func1
from file2 import Func2

class NewFunc1(Func1):
    def __call__(self, x, y, z):
        return super().__call__(x, y) * z

class NewFunc2(Func2):
    def __call__(self, x, y, z):
        return super().__call__(x, y) * z

# Create instances of the classes:
func1 = Func1()
func2 = Func2()
new_func1 = NewFunc1()
new_func2 = NewFunc2()

print(func1(1, 2))  # Outputs 3
print(func2(1, 2))  # Outputs -1
print(new_func1(1, 2, 3))  # Outputs 9
print(new_func2(1, 2, 3))  # Outputs -3

fiddle


However, it would be more generic to not use class inheritance and pass the callable object as an argument when you instantiate the class:

(Using your file1.py and file2.py.)

# file3.py
class NewFunc:
    def __init__(self, f):
        self.f = f

    def __call__(self, x, y, z):
        return self.f(x, y) * z
# file4.py

from file1 import func1
from file2 import func2
from file3 import NewFunc

new_func1 = NewFunc(func1)
new_func2 = NewFunc(func2)

print(func1(1, 2))  # Outputs 3
print(func2(1, 2))  # Outputs -1
print(new_func1(1, 2, 3))  # Outputs 9
print(new_func2(1, 2, 3))  # Outputs -3

fiddle

Comments

0

I think you don't need to use inheritance at all.

So it is not necessary to use classes.

Sure, you can use classes with .__call__() method - it creates functions with state. But that is overkill here.

You use the word "inheritance" in a special way.

The function at the beginning of the file should be "inherit"ed.

But inherit is a term quite occupied by OOP inheritance.

You want to place the functions into separate files, so that you can say: "Use the function in file X, and apply this function e.g. new_func() on that file X" to obtain a partial function.

But why not do it like this:


# `file` functions:

def func1(a, b):
    c = a + b
    return c

def func2(a, b):
    c = a - b
    return c

# and more such functions in "files"

## then you have functions you want to apply on those:

def new_func_1(f, x, y, z):
    return f(x, y) * z

def new_func_2(f, x, y, z):
    return f(x, y) / z

# and more such functions

Ah I see, you say:

So users can access new_func using file1.new_func(x, y, z) and file2.new_func(x, y, z).

So you want the user dynamically "apply" new_func on func1 (file1), func2 (file2) etc.

Why not simply apply in this way:

new_func_1(func1, x, y, z)
new_func_1(func2, x, y, z)
new_func_2(func1, x, y, z)
new_func_2(func2, x, y, z)

Ok, let's say you want to have the order: func1, new_func_1, x, y, z

The easiest way would be to have a function which does that:

from functools import partial

def apply(base_func, modifier_func, x, y, z):
    return partial(modifier_func, base_func)

# and now you can use it like this:

apply(func1, new_func_1)(x, y, z)
apply(func2, new_func_1)(x, y, z)
apply(func1, new_func_2)(x, y, z)
apply(func2, new_func_2)(x, y, z)

No need for "inheritance" in any way.

The apply() is a partial() where you just switch the first two argument's order.

You could - if the order can be switched also write:

partial(new_func_1, func1)(x, y, z)
partial(new_func_1, func2)(x, y, z)
partial(new_func_2, func1)(x, y, z)
partial(new_func_2, func2)(x, y, z)

But then, you could have also written:

new_func_1(func1, x, y, z)
new_func_1(func2, x, y, z)
new_func_2(func1, x, y, z)
new_func_2(func2, x, y, z)

as well.

But apply() brings the arguments more into the order and shape you want.

Comments

Your Answer

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.