简体   繁体   中英

Best Practice for Equality in Python

is there a best practice to determine the equality of two arbitrary python objects? Let's say I write a container for some sort of object and I need to figure out whether new objects are equal to the old ones stored into the container.

The problem is I cannot use "is" since this will only check if the variables are bound to the very same object (but we might have a deep copy of an object, which is in my sense equal to its original). I cannot use "==" either, since some of these objects return an element-wise equal, like numpy arrays.

Is there a best practice to determine the equality of any kind of objects? For instance would

repr(objectA)==repr(objectB)

suffice?

Or is it common to use:

numpy.all(objectA==objectB)

Which probably fails if objectA == objectB evaluates to "[]"

Cheers, Robert

EDIT:

Ok, regarding the 3rd comment, I elaborate more on "What's your definition of "equal objects"?"

In the strong sense I don't have any definition of equality, I rather let the objects decide whether they are equal or not. The problem is, as far as I understand, there is no well agreed standard for eq or ==,respectively. The statement can return arrays or all kinds of things.

What I have in mind is to have some operator lets call it SEQ (strong equality) in between eq and "is". SEQ is superior to eq in the sense that it will always evaluate to a single boolean value (for numpy arrays that could mean all elements are equal, for example) and determine if the objects consider themselves equal or not. But SEQ would be inferior to "is" in the sense that objects that are distinct in memory can be equal as well.

I suggest you write a custom recursive equality-checker, something like this:

from collections import Sequence, Mapping, Set
import numpy as np

def nested_equal(a, b):
    """
    Compare two objects recursively by element, handling numpy objects.

    Assumes hashable items are not mutable in a way that affects equality.
    """
    # Use __class__ instead of type() to be compatible with instances of 
    # old-style classes.
    if a.__class__ != b.__class__:
        return False

    # for types that implement their own custom strict equality checking
    seq = getattr(a, "seq", None)
    if seq and callable(seq):
        return seq(b)

    # Check equality according to type type [sic].
    if isinstance(a, basestring):
        return a == b
    if isinstance(a, np.ndarray):
        return np.all(a == b)
    if isinstance(a, Sequence):
        return all(nested_equal(x, y) for x, y in zip(a, b))
    if isinstance(a, Mapping):
        if set(a.keys()) != set(b.keys()):
            return False
        return all(nested_equal(a[k], b[k]) for k in a.keys())
    if isinstance(a, Set):
        return a == b
    return a == b

The assumption that hashable objects are not mutable in a way that affects equality is rather safe, since it would break dicts and sets if such objects were used as keys.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM