gin-config
gin-config copied to clipboard
inheriting configs with default parameters
Let's consider a simple two-class hierarchy:
@gin.configurable
class A:
def __init__(self, a=1):
self.a = a
@gin.configurable
class B(A):
def __init__(self, a=1, b=2):
super().__init__(a)
self.b = b
Ideally I would like to replicate this structure in my .gin
config files:
A.a = 3
B.b = 4
So that when I call obj = B()
it would contain obj.a == 3 and obj.b == 4
.
However, right now this does not happen - I get obj.a == 1 and obj.b == 4
.
This is because gin detects that A
constructor is manually called with a
set as B
's default.
The current workaround is to define full configuration for each class separately, however that becomes quite cumbersome when configuring many classes that inherit from one base class with majority of the parameters shared.
One possible fix would be to reuse existing macro syntax and explicitly replicate the hierarchy in .gin
config, e.g.:
A.a = 3
B = #A
b.b = 4
This a bit hard, since it will violate the Python behavior. But maybe Dan would have some insights in a few weeks.
As a reference I've made a hacky work-around that implicitly does this by checking locals()
and only passing arguments forward if they differ from defaults. Here's how it looks in the inheriting class. Then in the config file I can define the global configs for the parent class, only overriding relevant parts for children.
Of course when doing this from the outside you most likely can't just call locals()
, but maybe the general idea could help.
I don't know if this is a solution to your problem, but it works if you don't explicitly have the arguments of the superclass in the constructor of your subclass but rather use *args
and **kwargs
:
import gin
@gin.configurable
class A:
def __init__(self, a=1):
self.a = a
@gin.configurable
class B(A):
def __init__(self, b=2, *args, **kwargs):
super(B, self).__init__(*args, **kwargs)
self.b = b
if __name__ == '__main__':
gin.parse_config(["A.a = 3", "B.b = 4"])
obj = B()
print(obj.a)
print(obj.b)