9

If I have two variables, a and b and they could be integers, float, or strings.

I want to return True if they are equal (in case of string, ignore case).

As Pythonic as possible.

Simeon Visser
  • 118,920
  • 18
  • 185
  • 180
user1008636
  • 2,989
  • 11
  • 31
  • 45

3 Answers3

21

This is the most pythonic I can think of. Better to ask for foregiveness than for permission:

>>> def iequal(a, b):
...    try:
...       return a.upper() == b.upper()
...    except AttributeError:
...       return a == b
... 
>>> 
>>> iequal(2, 2)
True
>>> iequal(4, 2)
False
>>> iequal("joe", "Joe")
True
>>> iequal("joe", "Joel")
False
jterrace
  • 64,866
  • 22
  • 157
  • 202
  • +1. Probably better to use basestring instead of str, but otherwise this seems like exactly what he wants. (Edited to say "jinx, buy me a Coke" to mgilson.) – abarnert Aug 16 '12 at 18:30
  • sorry, meant to use basestring – jterrace Aug 16 '12 at 18:31
  • Actually, your try/except variant is probably better than the typecheck anyway. – abarnert Aug 16 '12 at 18:31
  • Yeah, I hit (+1) as soon as I saw `try/except` :-) – mgilson Aug 16 '12 at 18:31
  • Agreed - I removed the type check version. – jterrace Aug 16 '12 at 18:32
  • I'm not sure I like the `except` condition... if the point of this method is to check if a string is equal to something else regardless of case, it should require that the objects at least are valid to be interpreted as strings. Rather than `return a == b`, maybe `return str(a).upper() == str(b).upper()`, so the caller gets an exception if the test values are not at least string-y. – Silas Ray Aug 16 '12 at 18:39
  • @sr2222 but anything can be turned into a string - ``str(3).upper()`` – jterrace Aug 16 '12 at 18:43
  • @sr2222 -- you can convert any object to a string. Your proposition will never raise an exception. Plus, then `iequal(1.0,1)` would return `False`, which seems a little funky ... – mgilson Aug 16 '12 at 18:44
  • First, objects without `__str__`, or a `__str__` that has been intentionally overridden to return an exception, can't be converted to a string. Second, @mgilson, yes, a method meant to compare 2 strings without case shouldn't evaluate `True` for 2 things that don't have the same string representation with the exception of case. It's a basic question of functional symmetry. Third, since calling `upper()` doesn't coerce an object to a string, you could have 2 objects who's string representations are equivalent for which this function would return `False`. – Silas Ray Aug 16 '12 at 18:54
  • @sr2222 objects have a default ``__str__`` though: ``class Foo(): pass; x = Foo(); print str(x)`` == ``<__main__.Foo object at 0x108dcec90>`` – jterrace Aug 16 '12 at 18:57
  • @sr2222 -- classes without `__str__` are pretty hard (impossible?) to find. I'm not even sure how you could manage that ... second, OP says the input could be "integers, floats, or strings". While OP is a little vague on the details of how cross-type comparisons should be made, I thought it was worth pointing out where a cross-type comparison would be logical and your proposed solution would yield an unexpected result. – mgilson Aug 16 '12 at 19:00
7

How about this, without isinstance (frowned upon):

def equal(a, b):
    try:
        return a.lower() == b.lower()
    except AttributeError:
        return a == b
DrGodCarl
  • 1,666
  • 1
  • 12
  • 17
2
>>> def equals_ignore_case(a,b):
...   return a.upper() == b.upper()
...
>>> equals_ignore_case("hello","Hello")
True
tokhi
  • 21,044
  • 23
  • 95
  • 105