
Chris Angelico wrote:
Allow me to rephrase what I think you're arguing here, and you can tell me if I'm close to the mark.
You close to the mark. :) Chris Angelico wrote:
Given an object of a custom class C, you can make it usable as "x, y, z = C()" or "f(*C())" or anything else by defining __iter__, and in all ways that object will be iterable, unpackable, etc.
Yes, the only small problem: ``` class MyClass: def __iter__(self): return self.items_for_iteration def __unpack__(self): return self.items_for_unpack ``` This is not hurt. Chris Angelico wrote:
Given the same object, how can you ensure that it can be used as "f(**C())"? What about in "{}.update(C())"? Or "dict(C())"? Is there a single well-defined protocol that allows you to make your object usable in all mapping-like contexts?
Look at the example: ``` seq = zip('abc', 'xyz') d = {} d.update(seq) print(d) # {'a': 'x', 'b': 'y', 'c': 'z'} def f(**kwargs): print(kwargs) seq = zip('abc', 'xyz') f(**seq) # TypeError: f() argument after ** must be a mapping, not zip ``` `dict.update` does the job. I think a single protocol is: `x, y, z = C()`, `[i for i in C()]`, ... call `C.__iter__()` `f(C())`: get C instance. `f(*C())`: call `C.__unpack_args__(self) -> Iterator[Any]:` `f(**C())`: call `C.__unpack_kwargs__(self) -> Iterator[Tuple[str, Any]]:`