PEP-584 alternative operator

TL:DR; How about rshift for the update operator?

When reading about ZipFile.Path in 3.8 I thought I might like to use the following one liner in a project I’m working on.

ZipFile("spam.zip").extractall(zipfile.path(ZipFile("eggs.zip", "w")))

However fails to close the ZipFiles properly. I don’t really enjoy using double with statements either so instead of one I imagine I would need to do at least 3 with probably two intermediate variables.

So I then thought I might like to make a library that implements rshift for this double context manager operation where the ZipFiles are closed.

However this is in essence a namespace update, and so to be idiomatic I might instead implement iadd from PEP-584, which I don’t really like as much as it reverses the order of spam and eggs which isn’t the same as extractall, and I prefer src-to-dest order in a sequence of atomic directed graph operations instead of dest-from-src.

I noticed lshift is mentioned as a rejected idea in the PEP but not rshift. Has rshift already been rejected somewhere? I tried to use the search for this forum but I seem to be bad at it.

As an aside, this operator with my ZipFile idea would also make sense if Path.open worked on directories, with a context manager that could set permissions, notify security contexts etc and then revert on exit so I was hoping to explore all that as a learning exercise but it’s all a little late if += is to be the anointed python idiom for updating values by copying to a namespace from another.

You mean something like

new = d1 >> d2

as short-hand for:

new = d1.copy()
new.update(d2)  # push values of d2 into copy of d1

To me, >> implies that the values from d1 are being pushed into d2,
rather than the other way around. That would mean that using rshift
instead of lshift has all the same disadvantages of lshift:

  • doesn’t match dict addition in other languages
  • doesn’t match set union
  • hardly anybody thinks of it as having any connection
    to dict updates

plus its own unique disadvantage:

  • arrows point the wrong way to indicate data flow.

If there is any advantage to >> besides “its different from the others,
so nobody has objected to it yet” I can’t see it from your explanation.
Whatever connection there is between your failed ZipFile.Path one-liner
and merging dicts, I’m afraid it is too subtle for me to understand.

No my suggestion of the rshift operator wouldn’t allow for the creation of a new dict. The ZipFile case pertains only to the __iadd__. I think +, or a “merged” method instead, might be an orthogonal consideration to the complexity of updating in place.

To be clear I am raising the possibility that the general case of updating a mapping in place might need a context manager. If that’s so then the creation of the context manager could support many different semantics for the operator. Therefore the disadvantage of the += operator is that it’s inflexible as the concept of addition is well understood to be fundamental rather than contextual. In the case of a dict I’m not sure I have a case to argue in terms of specific alternate semantics that should be supported. But in the case of a generic mapping, such as the example of paths in ZipFile mapped to file data, an interface to handle more complex updates of a mapping in place (from a second mapping with its second context) would be likely to also apply to a dict, thereby superseding +=.

Thanks for your reply and thanks again for all your hard work also.

I think you’re going to have to justify this remark a lot harder. The point that your ZipFile example shows is that it’s not the merge operation but the objects that you’re merging that need management.

In the python docs the Data Model examples of mappings, after dict, are dbm.nbdm and dbm.gnu which have context managers with both an up front intent context (flag) and a semantic context (mode). See also: pypi modules with more extensive relational database contexts as dicts.

There’s now another ideas thread asking for how to exclude certain keys. The context manager could support, either on the left hand object (don’t copy this data) or the right hand object (don’t overwrite this data), bearing in mind that they might be quite different objects that both support the protocol.

I suspect that many custom mappings might find a use for the managed context.

The above are examples that pertain more directly to dicts than the ZipFile example. Also I may not have been as persuasive as I could be that a filesystem-like root directory is a compelling analogy for Mapping now that pathlib is implemented. I am actually as curious about general thoughts on that idea about as much as I am about affecting the progress of the PEP. You can’t open a pathlib.Path if it’s a directory but if you could there are some opportunities

To affect the PEP I imagine I’d need to suggest a compelling alternative. The rshift operator is one idea but in a perfect world I’d like to establish it as a more obvious left-to-right DAG idiom that should also apply to dicts and it seems ridiculous to think that could occur, when meanwhile there’s the PEP there and it seems like many people want it.

Sorry, no. This is still a context manager on the database object, not the update operation.

I haven’t gone and checked them, but from memory I think those context managers are about managing database cursors (access objects) rather than any kind of operation. One could probably make a case for a context manager for the update-commit-rollback cycle, but that smells more like exception handling to me.

I still don’t understand what you think a context manager for an operation does. Could you give an example, with an actual explanation, of what you mean?

The context manager is not a database object in the dbm examples. It better represents a connection to the database. An update is moving data between databases (represented by connection strings or filenames in this case), and the live connections are context for the operation. This is illustrated well by the fast flag for dbm.gnu.open - writes aren’t synchronised to the database, ie the ultimate intent of the operation, until the context is resolved.

Context for a dict update operation in principle is well illustrated by any of the rejected semantics in the PEP, such as raise on conflict. For example an option on a context manager would allow the user to be more explicit for mappings where the behaviour might differ from the dict behaviour. This would also work with +=.

Sorry, no. I still find your idea of context on operations confusing, even in the database example. The context there is having a connection (cursor) to the database; what you do with that connection is entirely separate. The fast flag on dbm.gnu.open is no different to caching on ordinary files.

No need to be sorry, your file example is very apt. The idiom for managing the open file is to use a context manager. The contents of the file is represented by a collection, but rather than a sequence the collection representing the file contents in the dbm example is a mapping.