True there is some work in keeping the two synchronized, but there are benefits.
First, unexpected arguments are immediately caught since they throw a TypeError.
Without this, you either have to manually check for unexpected keys (probably doing a set difference with `allowed_keys` or something) or you just silently pass through unrecognized attributes, probably causing strange behavior later on.
Second, you are forced to say explicitly which attributes are modifiable. To draw from the 'person' example, `name` and `age` might be modifiable, but `admin` might be protected. That would be made abundantly clear by `update(person, name=NotSet, age=NotSet)`, but less so, by `update(person, attrs)` or `update(person, kwargs)`.
A clear docstring would help, but I'd prefer to have the code just fail-fast on this unexpected input.