3

I have a current implementation like this:

class Infix(object):
  def __init__(self, func):
    self.func = func
  def __or__(self, other):
    return self.func(other)
  def __ror__(self, other):
    return Infix(partial(self.func, other))
  def __call__(self, v1, v2):
    return self.func(v1, v2)

@Infix
def Map(data, func):
  return list(map(func,data))

This is great, it works as expected, however I want to also expand this implementation to allow for a left side only solution. If somebody can showcase a solution AND explanation, that would be phenomenal.

Here is an example of what I would like to do...

 valLabels['annotations'] \
    |Map| (lambda x: x['category_id']) \
    |Unique|

Where Unique is defined as below...

@Infix
def Unique(data):
    return set(data)

Thanks!

3
  • 2
    Isn't that an unavoidable syntax error? You can't end a python expression with |. Commented Aug 15, 2016 at 20:54
  • Have you looked at coconut either for your use case, or at their source code? They have an infix notation, for instance, and I believe their syntax is a superset of Python. Commented Aug 15, 2016 at 20:56
  • @Two-BitAlchemist nah, I'm trying to stay with as much vanilla python stuff I have due to a variety of c integrations etc, just gets hairy to move outside that. Commented Aug 15, 2016 at 21:24

1 Answer 1

2

If you don't mind dropping the final |, you could do

class InfixR(object):
  def __init__(self, func):
    self.func = func
  def __ror__(self, other):
    return self.func(other)
  def __call__(self, v1):
    return self.func(v1)

@InfixR
def Unique(data):
  return set(data)

Then your expression would look like

valLabels['annotations'] \
    |Map| (lambda x: x['category_id']) \
    |Unique

Your original Infix class is (technically) abusing the bitwise or operator: |Map| is nothing special, it's just value | Map | my_lambda, a "bitwise or" of a list, an object, and a lambda, with a couple of spaces removed, and some newlines inserted (using \ to prevent the interpretter from trying to treat each line separately).

In custom classes, you can implement many of the usual operators using __double_underscore__ methods, in the case of bitwise or, they are __or__ and __ror__.

When the python interpreter encounters the | operator, it first looks at the object to the right, to see if it has a __or__ method. It then calls left.__or__(right). If that is not defined or returns NotImplemented, it looks at the object on the right, for __ror__ (reversed or), and calls right.__ror__(left).

The other part of this is the decorator notation.

When you say

@Infix
def Unique(data):
    return set(data)

The interpretter expands that into

def Unique(data):
    return set(data)

Unique = Infix(Unique)

So you get an Infix instance, which has __or__ and __ror__ methods, and a __call__ method. As you might guess, my_obj.__call__() is called when you invoke my_oby().

Sign up to request clarification or add additional context in comments.

1 Comment

You mind adding a little explanation about whats up with this section of code? I've mashed this together from a variety of sources and not really sure whats going on with it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.