dieggsy
dieggsy

Reputation: 372

Python - Use external function as class method

Say I have some very long function module.my_function that's something like this:

def my_function(param1,param2,param3='foo',param4='bar',param5=None,...)

With a large number of args and keyword args. I want this function to be usable both as a part of module module and as a class method for myClass. The code for the function will remain exactly the same, but in myClass a few keyword args may take different default values.

What's the best way of doing this? Previously I was doing something like:

class myCLass(object):
    def __init__(self,...
    def my_function(self, param1,param2,param3='hello',param4='qaz',param5=['baz'],...):
        module.my_function(param1,param2,param3=param3,param4=param4,param5=param5,...)

It seems a little silly to write all these arguments that many times, especially with a very large number of arguments. I also considered doing something like module.my_function(**locals()) inside the class method, but I'm not sure how to handle the self argument and I don't know if this would lead to other issues.

I could just copy paste the entire code for the function, but that doesn't really seem very efficient, when all that's changing is a few default values and the code for my_function is very long. Any ideas?

Upvotes: 0

Views: 1225

Answers (1)

DurgaDatta
DurgaDatta

Reputation: 4170

You can convert the function to bound method by calling its __get__ method (since all function as descriptors as well, thus have this method)

def t(*args, **kwargs):
    print(args)
    print(kwargs)

class Test():
    pass
Test.t = t.__get__(Test(), Test) # binding to the instance of Test

For example

Test().t(1,2, x=1, y=2)
(<__main__.Test object at 0x7fd7f6d845f8>, 1, 2)
{'y': 2, 'x': 1}

Note that the instance is also passed as an positional argument. That is if you want you function to be instance method, the function should have been written in such a way that first argument behaves as instance of the class. Else, you can bind the function to None instance and the class, which will be like staticmethod.

Test.tt = t.__get__(None, Test)
Test.tt(1,2,x=1, y=2)
(1, 2)
{'y': 2, 'x': 1}

Furthermore, to make it a classmethod (first argument is class):

Test.ttt = t.__get__(Test, None) # bind to class
Test.ttt(1,2, x=1, y=2)
(<class '__main__.Test'>, 1, 2)
{'y': 2, 'x': 1}

Upvotes: 1

Related Questions