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 шт):

Автор решения: Vitalizzare ушел в монастырь

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)
    ...
→ Ссылка
Автор решения: Stanislav Volodarskiy

Имя 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

Проще всего переименовать функцию, скажем fff. Код заработает. Только он неправильно работает. Вы не используете последний столбец таблицы, вместо него подставили единицы зачем-то.

Переменные цикла 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 ошибочна.

→ Ссылка