
On Fri, Jul 10, 2020 at 01:59:06PM +0100, Jonathan Fine wrote:
I wrote: Let's proceed. We continue to use d = Dummy(). Given that >>> key = d[1, 2, 3, a=4, b=5] is allowed, what should we be able to say about the key. Clearly it should be an instance of a class and there should be a way of creating such an instance without going via d. Let's call the class K (for key).
I'll now expand on this, as it's not clear to everyone that the key should be an instance of a class.
Of course it is clear that if `key` *exists at all*, then it will be an instance of a class, and furthermore that there will be ways to instantiate that class independently of subscript syntax. This is fundamental to Python's design. *If* it exists though. And I'm not convinced that there's any need for this K class, which seems to be analogous to slice(). Or at least, it needs to be justified, and not just assumed. The alternative model is to treat subscripting analogously to function calls, and bind the arguments to parameters in the method. In that case, your "key" object won't even exist. That's how slicing used to work, and there's no reason why we couldn't do the same thing in the future for any enhancement. Before getting bogged down in the question of how to implement this, we ought to firstly establish what this is, and whether we need it. Having read your posts repeatedly, I think it is safe to say that you are thinking along the lines of a something analogous to the slice() builtin. It might have made your explanation easier to understand if you had made that analogy explicit: # Current Python myobj[a:b:c] --> myobj.__getitem__(slice(a, b, c)) # Proposed enhancement: myobj[a, b, c, spam=d, eggs=e] --> myobj.__getitem__(lump(a, b, c, spam=d, eggs=e)) # and similar for assignment and deletion where "lump" (for lack of a better name) is a helper object analogous to "slice", but accepting arbitrary positional and keyword arguments. (Note: to be precise, dunder methods aren't looked up on the instance themselves, but on the class. But as shorthand, I'll continue to pretend otherwise.) As Paul says, this is pretty obvious stuff so far. Also obvious is that we can define our own "lump" class and experiment with it: # Much like your Dummy class. class lump: def __init__(self, *args, **kwargs): self.args = args self.kwargs = kwargs In your `myobj.__getitem__` method, we can handle the "lump": # myobj's class def __getitem__(self, item): print(item.args) print(item.kwargs) which is enough for experimentation. You can even alias `K=lump` if you prefer :-) Some additional issues: For getters, why not just make the object callable and write `myobj(spam=1)`? We need to justify the use of square brackets. For setters, if we're going to change the syntax to allow keywords in subscripts, perhaps it is better/easier to just allow function calls on the left hand side of assignments? We need to consider why we are doing this, what we hope to do, and whether square or round brackets are preferable. For both: there are serious backwards compatibility concerns regarding the use of multiple parameters, since they are currently legal and bound up in a tuple argument: # Current Python myobj[1, 2] # calls __getitem__ with a single tuple argument (1, 2) # How to distinguish the above from this? myobj[1, 2] # call __getitem__ with two int arguments? However, there is no such concern regarding keyword arguments.
So far I know, every Python object that is accessible to the Python user is an instance of a class (or type).
Correct. Even type itself is an instance of itself. -- Steven