Hm... with only a little bit of cooperation of the container class (e.g. xylophone), you could implement this yourself:

class xylophone:
    def __contains__(self, item):
        if hasattr(item, '__lcontains__'):
            return item.__lcontains__(self)
        return False

On Tue, Nov 12, 2019 at 5:04 PM Samuel Muldoon <muldoonsamuel@gmail.com> wrote:
Currently, the `in` operator (also known as `__contains__`) always uses the rightmost argument's implementation.

For example,

   status = obj in "xylophone"

Is similar to:

    status = "xylophone".__contains__( obj )

The current implementation of  `__contains__` is similar to the way that `+` used to only look to the leftmost argument for implementation.

    total = 4 + obj
    total = int.__add__(4, obj)

However, these days, `__radd__` gives us the following:

     try:
         total = type(4).__add__(4, obj)
     except NotImplementedError:
         total = type(obj).__radd__(obj, 4)

We propose something similar for `__contains__`: That a new dunder/magic method `__lcontains__` be created and that the `in` operator be implemented similarly to the following:

    # IMPLEMENTATION OF
    #     status = obj in "xylophone"`
    try:
        status =  "xylophone".__contains__(obj)
    except NotImplementedError:
        status = False
    if not status:
        try:
            status = obj.__lcontains__(“xylophone”)
    except AttributeError:
        # type(obj) does not have an `__lcontains__` method
        with io.StringIO() as string_stream:
            print(
                "unsupported operand type(s) for `in`:",
                repr(type(4).__name__),
                "and",
                repr(type(obj).__name__),
                file=string_stream
            )
            msg = string_stream.getvalue()
        raise TypeError(msg) from None


The proposed enhancement would be backwards compatible except in the event that a user already wrote a class having an `__lcontains__` method.

With our running example of the string “xylophone”, writers of user-defined classes would be able to decide whether their objects are elements of  “xylophone” or not. Programmer would do this by writing an `__lcontains__` method.

As an example application, one might develope a tree in which each node represents a string (the strings being unique within the tree). A property of the tree might be that node `n` is a descendant of node `m` if and only if `n` is a sub-string of `m`. For example the string "yell" is a descendant of "yellow." We might want the root node of the tree to be a special object, `root` such that every string is in `root` and that `root` is in no string. That is, the code `root in "yellow"` should return `False`. If ` __lcontains__ ` were implemented, then we could implement the node as follows:

class RootNode(Node):

    def __contains__(container, element):

        return True

    def __lcontains__(element, container):

        return False

_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-leave@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/X2VCWCBJZABPWJH5LNMYPODZKNM7UZML/
Code of Conduct: http://python.org/psf/codeofconduct/


--
--Guido van Rossum (python.org/~guido)
Pronouns: he/him (why is my pronoun here?)