• Равенство Питона Проверить Разницу

    Предположим, что нам требуется какой-то блок кода, который будет выполнен, когда как 'A' и 'B' равна, скажем, 5. Тогда мы можем записать как :

    if a == 5 and b == 5:     # do something 

    Но несколько дней назад, я просто невольно написал аналогичную проверку состояния как :

    if a == b and b == 5:     # do something  

    что заставило меня задуматься, есть ли разница между ними ? Также, есть и другой способ,

    if a == b == 5:     # do something 

    Есть ли разница, никакой разницы с точки зрения процесса оценки или выполнение, или Время, затраченное ? а также какой из них лучше или какие лучше использовать?

    Это связано с понятием транзитивности ?

  • Ответы

  • Так как они в основном эквиваленте, вы могли бы также рассмотреть, как вы читаете/думаете по поводу кода:

    if a == 5 and b == 5:   # do something 

    можно читать как "если a равно 5 и b равно 5, то и делают ...". Надо подумать/сделать вывод, что то же a будет равна b.

    Это противоположно к следующему примеру:

    if a == b and b == 5:   # do something  

    Это читается как "если a равна b и b равно 5"и вы должны сделать вывод, что то же a будет равна 5

    Вот почему я предпочитаю последний пример:

    if a == b == 5:   # do something 

    Если вы знакомы с Python (благодаря Itzkata) сразу ясно, что все три вещи должны быть равны (в 5). Если, однако, люди с меньшим опытом в Python (но навыки программирования на других языках) увидят это, они могут оценить это

    if (a == b) == 5: 

    что бы сравнивать логический результат первого сравнения со значением 5, которые не то, что делает Python и может привести к разным результатам (рассмотрим, например, с a=0, b=0: a==b==0 правда, пока (a==b) == 0 нет!

    В руководстве написано:

    Есть восемь операций сравнения в Python. Они все имеют одинаковый приоритет (что выше, чем у логических операций). Сравнения могут быть соединены произвольно; например, x < Г <= Z эквивалентно х < Y и Y <= Z и, кроме того, что Y вычисляется только один раз (но в обоих случаях Z не рассматривается вообще, когда x < y является ложной).

    Там может быть разница, например если evaulating b в вашем примере будет иметь побочный эффект.

    Что касается транзитивности, вы правы.

    Если у вас есть больше переменных, чтобы проверить, используя all может быть немного более читаемым:

    if all(i==5 for i in [a,b,c,d]):     # do something 

    Что касается чисел, нет никакой разницы, с точки зрения производительности, между первыми двумя сравнениями.

    Третье сравнение-это разные, хотя, с немного больше возиться со стеком ввязывается. Действительно, код

    import dis  def comparison_1(a, b):     if a == 5 and b == 5:         pass  def comparison_2(a, b):     if a == b and b == 5:         pass  def comparison_3(a, b):     if a == b == 5:         pass  print("*** First comparison ***") dis.dis(comparison_1)  print("\n*** Second comparison ***") dis.dis(comparison_2)  print("\n*** Third comparison ***") dis.dis(comparison_3) 

    возвращает

    *** First comparison ***   4           0 LOAD_FAST                0 (a)               3 LOAD_CONST               1 (5)               6 COMPARE_OP               2 (==)               9 POP_JUMP_IF_FALSE       27              12 LOAD_FAST                1 (b)              15 LOAD_CONST               1 (5)              18 COMPARE_OP               2 (==)              21 POP_JUMP_IF_FALSE       27    5          24 JUMP_FORWARD             0 (to 27)         >>   27 LOAD_CONST               0 (None)              30 RETURN_VALUE          *** Second comparison ***   8           0 LOAD_FAST                0 (a)               3 LOAD_FAST                1 (b)               6 COMPARE_OP               2 (==)               9 POP_JUMP_IF_FALSE       27              12 LOAD_FAST                1 (b)              15 LOAD_CONST               1 (5)              18 COMPARE_OP               2 (==)              21 POP_JUMP_IF_FALSE       27    9          24 JUMP_FORWARD             0 (to 27)         >>   27 LOAD_CONST               0 (None)              30 RETURN_VALUE          *** Third comparison ***  12           0 LOAD_FAST                0 (a)               3 LOAD_FAST                1 (b)               6 DUP_TOP                            7 ROT_THREE                          8 COMPARE_OP               2 (==)              11 JUMP_IF_FALSE_OR_POP    23              14 LOAD_CONST               1 (5)              17 COMPARE_OP               2 (==)              20 JUMP_FORWARD             2 (to 25)         >>   23 ROT_TWO                           24 POP_TOP                      >>   25 POP_JUMP_IF_FALSE       31   13          28 JUMP_FORWARD             0 (to 31)         >>   31 LOAD_CONST               0 (None)              34 RETURN_VALUE         

    Это зависит от того. Вы могли бы написать свой собственный __eq__ которое позволяет сравнить себя с инц и вещи:

     class NonNegativeInt(object):    def __init__(self, value):      if value < 0:        raise Exception("Hey, what the...")      self.value = value     def __eq__(self, that):      if isinstance(that, int):        return self.value == that      elif isinstance(that, NonNegativeInt):        return self.value == that.value      else:        raise ArgumentError("Not an acceptible argument", "__eq__", that) 

    что бы работали разные в зависимости от сравнения "B" до "A" и "B" до "инт". Следовательно, a == b могут быть ложные пока a == 5 and b == 5 может быть правда.