21

In javascript, there are strict comparison operators op1 === op2 and op1 !== op2 that will compare both type and value. Is there a pythonic way of achieving the same thing?

So far I've only been able to come up with the following messy conditionals:

isinstance(op1, type(op2)) and isinstance(op2, type(op1)) and op1 == op2

and

not isinstance(op1, type(op2)) or not isinstance(op2, type(op1)) or op1 != op2
Gillespie
  • 5,780
  • 3
  • 32
  • 54
  • 4
    No, there isn't, you can only test either identity `is` (reference to same object) or equality `==` (which relies on the implementation of the `__eq__` magic method). – jonrsharpe Jan 19 '15 at 21:36
  • 3
    @jonrsharpe and if your using `!=` Dont forget about the magic `__ne__` method. – Nick Humrich Jan 19 '15 at 22:10

5 Answers5

23

Your approach would indeed check both value and type. There isn't a different operator in Python.

This having been said, in many cases that's not what you want - in Python's philosophy any object that behaves as a duck should be treated as a duck. You often don't want only dictionaries, you want "mapping-like" objects and so on - as long as the object can be used for the particular task then the code should accept it.

Simeon Visser
  • 118,920
  • 18
  • 185
  • 180
17

Python's equal comparator is strict except for when comparing 1 to True, and 0 to False, and it doesn't matter if the value for 1 or 0 is of type float, decimal.Decimal, or long. Zero of any numeric type, for example, 0, 0L, 0.0, 0j is always False. (Note that anything else cast to a bool is True. See Truth Value Testing in Python.) 1 of any type except complex (1L, 1.0, 1) is always True.

In Python:

0 == '0'  # False
0 == '0' and type(0) == type('0')  # False, compare short circuits 
0 == ''  # False
0 == '' and type(0) == type('')  # False, compare short circuits 

1 == True and type(1) == type(True)  # False, makes a difference here
1 == True  # True, also true if 1 was 1.00, etc..
0 == False  # True
False == None  # False
0 == bool(None)  # True

When the first comparison returns False, the second one is not evaluated, hence it short circuits because 0 and anything else is 0. This is unnecessary though, it would only apply to when comparing 1 to True in line 6.

In JavaScript:

0 == '0'  //true
0 === '0'  //false
0 == ''  //true
0 === '0' //false

1 === true //false
1 == true //true
0 == false //true
false == null //false
0 == !!(null) //true

So the closest thing to the JavaScript === in Python is:

a == b and type(a) == type(b)

But only would need to be used in the case of a boolean comparison to 1 or 0, which is unlikely. If you expect a value to be either a numeric or a boolean, you might want to fix your code. A rookie mistake is to have something like this occur:

a = 0.0  # a valid value, lets assume it comes from a source that can also return None and we have no control over that.

# Should be:
# if a not None:
if a: # a is cast to bool, bool(0.0) is False
    print "do something here..."

Just to clear up some confusion, its good to be aware of Python's is operator. Python has a is operator which returns True if both sides of the is are bound to the same object, otherwise it returns False. When using string literals, the lifetime of the objects is only for the instance of the statement. So performing is on string literals is safe since if they are the same, they are assigned to the same object. This also applies to other immutable types like bool, and all number types:

0 is '0'  # False
0 is False  # False
0 is 0  # True

This is not guaranteed to work when comparing two variables or a variable and a literal.

When you create two empty lists you get two different objects, so is returns False:

x = []
y = []
x is y  # False

But in this case, these variables reference the same list, and will continue to do so until they are re-assigned, or a deep copy is made of one from the other:

x = y = []
x is y  # True
x.append(1)
x is y  # True
x = [1, ]
x is y  # False, even though the value is same

The is operator is comparing the identities of the objects, it is performing the following:

id('0') == id(0)

So if both objects reference the same memory, they reference the same object and therefore must be the same.

Its a good idea to avoid is to make strict comparisons unless you want to check if both objects are referencing the same memory.

As Simon's answer states, Python's philosophy on equality differs from JavaScript's and there really is no need for a strict equality comparator. Python's equality comparator is not loose like JavaScripts == but at the same time its not exactly the same as ===.

You should be okay with Python's equality comparator as long as its clear to you that zero of any numeric type (0, 0L, 0.0, 0j) is always equal to False and 1 of any numeric type except complex numbers (1, 1L, 1.0) is True.

radtek
  • 34,210
  • 11
  • 144
  • 111
  • `==` is only strict on in-built objects - on custom classes it can be defined as non-strict as the designer wishes - since you may not need strict comparison - it depends on the semantics you wish your classes to have. Also - if you are comparing object instances - isn't it better to use `is` rather than comparing `id`s. – Tony Suffolk 66 Apr 13 '16 at 07:12
5

Python's equal comparator is for the most part always strict.

For example:

Python

0 == '0'  # False
0 == ''  # False

Javascript

0 == '0'  //True
0 === '0'  //False
0 == ''  //True
0 === '0' //False
Nick Humrich
  • 14,905
  • 8
  • 62
  • 85
  • 1
    The cases I needed to worry about often involved boolean types: `1 == True #True` whereas in javascript `1 === true //false` – Gillespie Jan 19 '15 at 22:02
  • 3
    @RPGillespie You can always use the `is` operator for True and False. `1 is True # False` but `(1 == 1) is True #True` or `(1 == 'a') is False #True`, `(1 == 'a') is (3 == 1) #True`. – Nick Humrich Jan 19 '15 at 22:07
  • 2
    @RPGillespie in what context are you comparing a number to True/False? Maybe you have an underlying logic error that it would be better to correct instead. – Mark Ransom Jan 19 '15 at 22:20
  • 1
    @MarkRansom I'm comparing the fields of two imported JSON objects and I want to print out the fields that differ in either type or value. – Gillespie Jan 19 '15 at 22:28
  • 1
    @RPGillespie then I guess you're stuck, Python considers booleans to be a subclass of integers; `isinstance(False,int)` returns `True`. – Mark Ransom Jan 19 '15 at 22:40
2

You can also use the operator module if you want to be super strict. https://docs.python.org/2/library/operator.html

>>> import operator
>>> operator.eq(True, 1)
True
>>> operator.is_(True, 1)
False

Some of the answers in here are wrong. Python for instance, will not differentiate between some types, for the purpose of some comparisons.

For example:

>>> 1 == 1.0
True
>>> operator.eq(1, 1.0)
True
>>> operator.is_(1, 1.0)
False

Is works better than eq (or ==), but it is dependent on a variable being pointers on the same value, which means there's lots of cases you wouldn't like.

If you want to go deep, implementing this in a shorthand manner, something like this: http://code.activestate.com/recipes/384122/ will let you "kind of" build your own operators.

TinBane
  • 866
  • 11
  • 19
  • your example is the same thing as `==` and `is`. Would just be easier to use `is`. `1 is 1.0 # False`. The operator module is just functions for the same things. – Nick Humrich Mar 26 '20 at 21:53
1

In python there is only one strict comparison operator that is == Suppose we have 2 cases:

>>> 2 == '2'
False

# Comparison of Int with string, it returns False
>>> 2 == 2.0
True

# Comparison of Int with Float, it returns True

However in other programming languages like Julia, There is a distinction between comparison operator and strict comparison operator.

>>> 2 == 2.0
true

>>> 2 === 2.0
false

# strict comparison operator, namely === which is true only if two values agree fully as to type as well as value.