Является ли короткое замыкание поведения 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)
Он ничего не делает для обеспечения поведения коротких замыканий
Ответы
Ответ 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)