Подтвердить что ты не робот

Является ли короткое замыкание поведения Python явным?

Подтверждено обсуждением здесь

Документы предлагают некоторый эквивалентный код для поведения all и any

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

Вот соответствующий отрывок из cpython/Lib/test/test_builtin.py

def test_all(self):
    self.assertEqual(all([2, 4, 6]), True)
    self.assertEqual(all([2, None, 6]), False)
    self.assertRaises(RuntimeError, all, [2, TestFailingBool(), 6])
    self.assertRaises(RuntimeError, all, TestFailingIter())
    self.assertRaises(TypeError, all, 10)               # Non-iterable
    self.assertRaises(TypeError, all)                   # No args
    self.assertRaises(TypeError, all, [2, 4, 6], [])    # Too many args
    self.assertEqual(all([]), True)                     # Empty iterator
    S = [50, 60]
    self.assertEqual(all(x > 42 for x in S), True)
    S = [50, 40, 60]
    self.assertEqual(all(x > 42 for x in S), False)

def test_any(self):
    self.assertEqual(any([None, None, None]), False)
    self.assertEqual(any([None, 4, None]), True)
    self.assertRaises(RuntimeError, any, [None, TestFailingBool(), 6])
    self.assertRaises(RuntimeError, all, TestFailingIter())
    self.assertRaises(TypeError, any, 10)               # Non-iterable
    self.assertRaises(TypeError, any)                   # No args
    self.assertRaises(TypeError, any, [2, 4, 6], [])    # Too many args
    self.assertEqual(any([]), False)                    # Empty iterator
    S = [40, 60, 30]
    self.assertEqual(any(x > 42 for x in S), True)
    S = [10, 20, 30]
    self.assertEqual(any(x > 42 for x in S), False)

Он ничего не делает для обеспечения поведения коротких замыканий

4b9b3361

Ответ 1

Поведение гарантировано. Я внес пакет, который был принят и объединен в последнее время, поэтому, если вы возьмете последние источники, вы увидите, что поведение короткого замыкания теперь явно введено в действие.

git clone https://github.com/python/cpython.git
grep Short-circuit cpython/Lib/test/test_builtin.py

Ответ 2

Документы говорят

"Вернуть True, если какой-либо элемент итерабельного является истинным. Если итерабельность пуста, верните False. ЭКВИВАЛЕНТ НА:" (внимание мое)...

def any(iterable):
    for element in iterable:
        if element:
            return True
    return False

Если any не было короткого замыкания, это не было бы ЭКВИВАЛЕНТ к опубликованному коду, так как четко обозначенный код был коротким. Вы могли бы потреблять больше генератора, чем хотите, например. В свете этого я говорю, что гарантируется короткое замыкание.

Точно такой же аргумент можно было бы сделать для all.

Ответ 3

У него есть короткое замыкание, так как ему может быть присвоен unbound iterable. Если это не короткое замыкание, это никогда не прекратится:

any(x == 10 for x in itertools.count())

Ответ 4

Эта страница является единственной страницей, которая появляется для меня при поиске "любого питона всех коротких замыканий"

Итак: в случае, если вы приземлились здесь в поисках простого "всегда ли все/всегда всегда замыкаете накоротко?"

Они делают, но есть хитрость: использование понимания списка может создать впечатление, что вы переопределяете короткое замыкание:

def hi():
    print('hi')
    return True

>>> any(hi() for num in [1, 2, 3, 4])
hi

>>> any([hi() for num in [1, 2, 3, 4]])
hi
hi
hi
hi

Понимание списка выполняется раньше, чем any().

или как @russianfool предлагает:

>>> any((hi(), hi(), hi(), hi()))
hi
hi
hi
hi

Полный набор вычисляется перед any пинает.

(Это также верно для списков выше: [1, 2, 3, 4] полностью оценивается оба раза выше.)

Также стоит отметить:

any(hi(), hi(), hi(), hi())

throws TypeError: any() takes exactly one argument (4 given)