py4j / py4j

Py4J enables Python programs to dynamically access arbitrary Java objects

Home Page:https://www.py4j.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

?) "*.equals(" code inside py.

MvGulik opened this issue · comments

Total Java noob here, that's more at home with Python.

I'm wondering about the "*.equals( code part inside the java_gateway.py file.
(I know about pythons __eq__ part.)

Is that correct code ?
Considering ".equals" is a general Java thing and not a python thing.
(did not look for a potential python definition on this though)

Its only seems to be used 2 times in py4j pythons files. (second one is in some test py file ... so its a rare case)

What is the target here ?
As I have run into something similar inside some code that uses py4j. But which triggers a py error.
But I can't figuring out what its intended to do ... so I can potential fix it.

It's for JVM object comparison. Was there any issue by that?

I don't know. I don't understand that last code line. so can't tel what the real problem is (or potentially fix it ... correctly).

Related pyj4 local code.
Which btw it not part of the original py4j source code ... but somewhat similar to what I found in the java_gateway.py file.

class PBotItem(object):
    def __init__(self, item):
        self.__item = item
        self._item = item

    def __eq__(self, other):
        if other is None:
            return False
        return self.__item.equals(other._item)

Which triggers this error when def __eq__(...) is indirectly called by my DEBUG call.

    DEBUG('.. '+'item_at_hand', item_at_hand)
  File "/.../_Python_/_Includes_/DEBUG.py", line 194, in DEBUG
    if data == 'fOObAr': ## no data-part input.
  File "/.../__pbot/PBotItem.py", line 12, in __eq__
    return self.__item.equals(other._item)
AttributeError: 'str' object has no attribute '_item'

I'm totally mystified about the .equals( part (+its part of some larger bulk code using py4j). Which makes debugging this kinda hard (at least for me).

(+Original coder of the bulk code is also no longer available.)

It's for JVM object comparison.

Yea. but is that not just a Java thing. While this is inside some python code.

@MvGulik in the java_gateway.py code you linked:

def __eq__(self, other):
    if other is None:
        return False
    elif (hasattr2(other, "_get_object_id")):
        return self.equals(other)
    else:
        return other.__eq__(self)

We only use self.equals() if other has _get_object_id defined. Since _get_object_id is a method defined on JavaObject, I take this to be a "duck typing" way to determine whether other can also be treated like a JavaObject, in which case we can delegate equality to Java. If other can't be treated like a JavaObject, we default to other's method of determining equality.

As far as the question (my interpretation, apologies if I'm misunderstanding 🙂):

Where does self.equals() get defined, since it's not explicitly defined as a method on the class & we're not inheriting from any other class that defines .equals()?

Check the __getattr__ definition. Since getattr(x, "name")() is equivalent to x.name(), and defining __getattr__ is how we define the behavior of getattr for a class, self.equals() is calling the Java .equals() implementation by way of self.__getattr__(name="equals") -> self._get_field(name="equals").

In your PBotItem constructor, it looks like there are 2 implicit assumptions:

  1. item is of type JavaObject (or otherwise has .equals() defined)
  2. other is of type PBotItem (or otherwise has ._item defined)

Given your error message, it looks like you're trying to check whether equality between a PBotItem and a str, which is not necessarily an issue with py4j.

In [1]: class FakeJavaObject:
   ...:     def equals(self, other):
   ...:         return True
   ...:

In [2]: class PBotItem(object):
   ...:     def __init__(self, item):
   ...:         self.__item = item
   ...:         self._item = item
   ...:
   ...:     def __eq__(self, other):
   ...:         if other is None:
   ...:             return False
   ...:         return self.__item.equals(other._item)
   ...:

In [3]: x = PBotItem(FakeJavaObject())

In [4]: x == "y"
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[4], line 1
----> 1 x == "y"

Cell In[2], line 9, in PBotItem.__eq__(self, other)
      7 if other is None:
      8     return False
----> 9 return self.__item.equals(other._item)

AttributeError: 'str' object has no attribute '_item'

@jdayton3
Thanks for the extensive info/help.

After digesting your message for the first time. Things already start to make more sens.
(extracting whatever else I can from it will take some additional time and studying)

So basically ... If I got it right. The problem in the related PBotItem code is that the __eq__(self. other) part (if other is not None) blindly defaults to calling the Java equals part (ie: letting Java do the comparing. I need to so some additional reading-up on that part) ... without checking if that "other" thing is actually a valid (Java) parameter/type/thing in this case.

I think I now should be able to fix this problem ... one way or an other.
Thank you.

Closing (As resolved/explained, +The error source was not part of py4j's own code.)

... Edit ...
Figure that, if all else fails, just switching my if data == 'fOObAr': ... to if 'fOObAr' == data: ... would be a plausible workaround. (that did not work. ... more reading todo)