TypeError: 'int' object is not callable (Задание 2 ЕГЭ по информатике)
from itertools import *
def f(x, y, z, w):
return (x and y) or (z == y) and w
for a, b, c, d, e, f, g in product([0, 1], repeat = 7):
table = [(a, b, 1, 1, 0),
(c, 0, 0, d, 0),
(e, 0, f, 0, 1),
(g, 0, 0, 0, 1)]
if len(set(table)) == len(table):
for p in permutations('xyzw'):
if [f(**dict(zip(p, s))) for s in table] == [1, 1, 1, 1]:
print(p)
if [f(**dict(zip(p, s))) for s in table] == [1, 1, 1, 1]:
^^^^^^^^^^^^^^^^^^^^
TypeError: 'int' object is not callable
Ссылка на задачу: https://education.yandex.ru/ege/variants/b78b69a4-40af-4217-8bd6-91195047d4e8/task/2
Вопрос: Что не так с моим кодом?
Ответы (2 шт):
TL;DR
Используйте разные имена для функции и переменной цикла.
Почему имя функции должно отличаться от имени переменной цикла
Переменную в Python удобно рассматривать как ключ в словаре локальных имен объектов; значение, извлекаемое по ключу, - это объект, на который указывает имя переменной. Эта модель не точна, но она лучше отражает логику Python, нежели думать о переменных как о ячейках или указателях. В качестве примера см. globals() и словари по атрибуту __dict__ импортируемых модулей.
Функция в Python - это объект. Определяя функцию через def, мы сохраняем её исходное имя в словаре локальных имён как ключ, по которому она извлекается. Функцию можно связать с новым именем, переназначив исходное другому объекту; сама функция остаётся при этом неизменной.
Имена функций не имеют в Python особого статуса, в отличие, например, от языка R, где учитывается контекст вызова при разрешении имён. То есть, в нем невозможна конструкция, где по контексту вызова различаются локальная переменная и глобальная функция с одинаковым именем:
> f <- function(x) paste('Hello', x)
> g <- function() for (f in 1:3) print(f(f)) # глобальная функция f выполняется
# с локальной переменной f
> g()
[1] "Hello 1"
[1] "Hello 2"
[1] "Hello 3"
Также, в отличие, например, от языка Си, переменная цикла в Python не ограничена телом цикла, а сам цикл представляет собой многократное присваивание новых объектов одной и той же переменной. То есть, если в конструкции for f in sequence: ... итератор по sequence не пуст, имя 'f' будет каждый раз связываться с новым объектом - и мы потеряем ссылку на исходную функцию f.
Итого:
- функция в Python - это объект, который не отличим от других объектов на этапе разрешения имён;
- цикл
forв Python - это "присвоение на повторе", которое связывает заданное имя с объектами итератора, а видимость имени не ограничена телом цикла.
А значит, для корректной работы кода вам нужно переименовать либо функцию, либо переменную цикла, чтобы отличить по локальному имени связанные с ними объекты и сохранить связь с функцией.
P.S. Размышление на тему перебора таблиц.
В данном случае мы могли бы использовать строковый паттерн для создания таблиц, благодаря чему сокращается количество переменных для заполнения изменяемых ячеек. Например:
table_pattern = '''[(%s, %s, 1, 1, 0),
(%s, 0, 0, %s, 0),
(%s, 0, %s, 0, 1),
(%s, 0, 0, 0, 1)]'''
for x in product('01', repeat=7):
table = eval(table_pattern % x)
...
Имя f используется два раза. Первый раз это имя функции, второй раз имя переменной цикла. Внутри цикла f содержит целое число, а для целых чисел запись f(...) не имеет смысла. Проверьте сами:
def f():
return 42
print('f is', f)
for f in range(42):
print('f is', f)
f()
$ python temp.py f is <function f at 0x7f11ec0344a0> f is 0 Traceback (most recent call last): File "/home/sv/desk/stackoverflow/temp.py", line 9, in <module> f() TypeError: 'int' object is not callable
Проще всего переименовать функцию, скажем f → ff. Код заработает. Только он неправильно работает. Вы не используете последний столбец таблицы, вместо него подставили единицы зачем-то.
Переменные цикла a, b, c, d, e, f, g нигде кроме оператора формирования таблицы не участвуют. То есть они замусоривают пространство имён без всякой пользы. Логично упрятать их в генератор таблиц:
def tables():
for a, b, c, d, e, f, g in product([0, 1], repeat=7):
table = [(a, b, 1, 1, 0),
(c, 0, 0, d, 0),
(e, 0, f, 0, 1),
(g, 0, 0, 0, 1)]
if len(set(table)) == len(table):
yield table
А основной цикл тогда примет вид:
for table in tables():
for p in permutations('xyzw'):
if [f(**dict(zip(p, s))) for s in table] == [1, 1, 1, 1]:
print(p)
Ещё раз напоминаю что строка с if ошибочна.