Description
Feature description and motivation
At the moment, field values on component instances behave much like instance attributes of generic Python class instances. One value exists per instance, and if it is mutable then an access after modification will return the same, modified value, e.g.:
@component
class A:
foo: List[int] = Field(lambda: [1, 2, 3])
class B:
def __init__(self):
self.foo = [1, 2, 3]
a = A()
b = B()
assert a.foo == b.foo == [1, 2, 3]
a.foo.append(4)
b.foo.append(4)
assert a.foo == b.foo == [1, 2, 3, 4]
We could change this behaviour so that field values instead behave much more like @property
values, i.e. the value is not 'cached' on the instance and instead re-generated on every access. See discussion here for a motivation of this different behaviour: larq/zoo#148 (comment).
Current implementation
For a full explanation of how components access field values, see the docstring of the _wrap_getattribute
method in component.py
:
zookeeper/zookeeper/core/component.py
Lines 116 to 144 in 2b8812a
New implementation
It would be straightforward to implement @property
-esqe behaviour for default values which are passed into fields, as mutable default values are already generated from lambdas, and there's no issue with immutable default values being cached .
However, it would be much more difficult to implement for values passed in through the CLI. Consider the configuration CLI argument foo=[1, 2, 3]
. We receive this as a string, and parse it into a Python value (in this case a list) to be used as the value for the field foo
. If we wanted to return a new instance of this list on each access of foo
, we would either need to be able to deep-clone generic mutable objects, or we would have to hold on to the configuration value as a string, and re-parse it into a Python value each time.
It's an open question whether we are happy for the behaviour of default values vs cli-overriden values to be different.
Activity