talwai
talwai

Reputation: 59

Python: Freeze arguments into a class __init__ function

Suppose I have a class that looks like this:

  class MyClass(object):
        def __init__(self, some_arg, param=None):
            self.some_arg = some_arg
            self.param = param

In most instances I initialize my class like this:

obj = MyClass(1, param='some_string')

But I'll occasionally have a code path which sets the param keyword argument based on some logic, while holding the some_arg positional argument at a constant value. This code would look something like:

if some_condition:
   obj = MyClass(1, param='some_string')
elif some_other_condition:
   obj = MyClass(1, param='some_other_string')
else:
   obj = MyClass(1, param='some_third_string')

My question is: Can I avoid having to repeat myself for the MyClass(1 portion of my object instantiation? I would like to, for the duration of the code path, freeze the value of the positional some_arg as 1, and simply pass the keyword argument param at instantiation time.

Ideally the code would look something like this:

MyClass = magic_function_to_freeze_some_arg(MyClass, some_arg=1)

if some_condition:
   obj = MyClass(param='some_string')
elif some_other_condition:
   obj = MyClass(param='some_other_string')
else:
   obj = MyClass(param='some_third_string')

print(obj.some_arg) # Always 1 regardless of which if condition is hit

Any ideas for what a clean implementation of magic_function_to_freeze_some_arg would look like? Is there a means to do this via Python standard library?

Upvotes: 2

Views: 1434

Answers (2)

Martijn Pieters
Martijn Pieters

Reputation: 1123700

Instead of repeating MyClass, store the argument in a variable and apply that:

if some_condition:
   param = 'some_string'
elif some_other_condition:
   param = 'some_other_string'
else:
   param = 'some_third_string'

obj = MyClass(1, param=param)

You could create a functools.partial() object or a lambda function but for this case that's overkill.

Upvotes: 3

Adam Smith
Adam Smith

Reputation: 54223

You're looking for functools.partial!

from functools import partial

MyClass_new = partial(MyClass, some_arg=1)

alternatively (as mgilson mentions in the comments) you can build your own anonymous constructor method

MyClass_new = lambda *args,**kwargs: MyClass(*args, some_arg=1, **kwargs)

Upvotes: 5

Related Questions