Почему функция format() выдает ValueError: неизвестный код формата «f» для объекта типа «str», когда я не ввожу строку?

Я использую Python 2.7. (Переход на Python 3 для этого конкретного кода невозможен, не предлагайте этого.) Я пишу модульные тесты для некоторого кода.

Вот соответствующий фрагмент кода:

class SingleLineGrooveTable:
  VEFMT = '.3f'

  @classmethod
  def formatve(cls, value, error=None):
    er = 0
    if error is not None:
      er = error
      v = value
    elif len(value) > 1:
      v, er = value
    else:
      v = value
    return format(v, cls.VEFMT), format(er, cls.VEFMT)

и мой тест:

import unittest

class TestSingleLineGrooveTable(unittest.TestCase):
  
  def test_formatve_no_error(self):
    e_v = '3.142'
    e_er = '0.000'
    r_v, r_er = SingleLineGrooveTable.formatve([3.1423])
    self.assertEqual(e_v, r_v)
    self.assertEqual(e_er, r_er)

(Да, я знаю, это забавно, что я получаю ошибку в тесте с «no_error» в названии...)

Когда я запускаю тест, он выдает ValueError: Unknown format code 'f' for object of type 'str' в операторе возврата функции. Но я не могу понять, откуда он берет строку. Возможно, это актуально, этот код и код, который у меня есть, который его использует, были в значительной степени скопированы из чужого кода (с которым я больше не могу связаться), так что, возможно, я называю его неправильно, но тем не менее, это список, не веревка!

Что здесь происходит? Как это исправить?

В любом случае я собираюсь предложить перейти на Python 3, даже если вы не хотите этого слышать. Все еще использовать 2.7 в 2024 году — это странно. Тем не менее: вам захочется превратить это в минимальный воспроизводимый пример, потому что прямо сейчас вы показываете def formatve, который принимает два аргумента (и третий необязательный), но затем ваш код, кажется, вызывает его с помощью единственный аргумент, так что это должно быть бросание TypeError: formatve() missing 1 required positional argument: 'value'. Кроме того, в вашем коде нет f-строк, так вы уверены насчет тега f-строки в своем сообщении?

Mike 'Pomax' Kamermans 13.06.2024 22:13
v = value должно быть v = value[0]. Ошибка возникает при попытке отформатировать список как float.
chepner 13.06.2024 22:40

Вопрос о том, почему вы получаете конкретное сообщение об ошибке при явно непреднамеренном вызове [3.1423].__format__('.3f'), менее важен, чем намеренный вызов 3.1423.__format__('.3f').

chepner 13.06.2024 23:06

@Mike'Pomax'Kamermans К сожалению, я пишу сценарии, которые взаимодействуют с приложением, имеющим только пакет Python для Python 2.7, поэтому переключение действительно не вариант. Я бы с радостью, учитывая акцент моего имени, мне буквально пришлось редактировать кодировку в исходном коде версии 2.7, чтобы она могла работать, но это не вариант :( Даже если бы приложение имело версию Python 3, мы иметь слишком много кода для переключения, чтобы быть практичным.

Réka 14.06.2024 20:06

@chepner Сначала я подумал, что это не должен быть список, но отсутствие списка приводит к тому, что elif len(value) выдает ошибку... Хотя, глядя на код предыдущего кодера, который использует это, я на самом деле не уверен, что он когда-либо вызывал это без значения ошибки, и он не тестировал его. Так что, возможно, это была ошибка, которую так и не обнаружили. Я предположил, что это моя проблема, потому что этот код использовался уже много лет.

Réka 14.06.2024 20:08

@Mike'Pomax'Kamermans Подожди, что ты имеешь в виду, что нужно два аргумента? Первый аргумент — cls. Это не нужно заполнять

Réka 14.06.2024 20:20

ах, извини, хорошая мысль. Чтобы запустить его как минимальный воспроизводимый пример , я убрал из него синтаксис класса. Хотя при этом сказано: пожалуйста, не забудьте указать проблему как MRE. и для того, чтобы люди могли увидеть, что что-то идет не так, и для того, чтобы заставить себя взглянуть на код совершенно другим критическим способом отладки. Обычно при подготовке MRE вы действительно обнаруживаете проблему и необходимость публикации становится спорной =)

Mike 'Pomax' Kamermans 15.06.2024 01:37
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
5
7
100
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

В Python 2 object.__format__ эффективно делегирует format(str(self), format_spec). Посмотреть реализацию можно здесь.

Поскольку list наследует object.__format__, ваш первый вызов format фактически является вызовом format(str([3.1423]), '.3f'). Вот почему вы получаете сообщение об ошибке.

В Python 3 это все равно приведет к ошибке. Просто это будет другая ошибка.

Ну, это странно. Как я уже сказал, я скопировал это у другого программиста, который работал на моей работе, и когда я попытался использовать 3.1423 в качестве аргумента, а не в качестве списка, он пожаловался, что не может использовать для него len(). Хотя, глядя на его код, я не уверен, использовал ли он это когда-либо без ввода значения ошибки, и у него не было для этого модульных тестов...

Réka 14.06.2024 20:04

Но спасибо, это имеет смысл и позволило мне понять, как исправить мой код!

Réka 14.06.2024 20:19

По сути, если вы указали явную ошибку, вы можете передать голый float. В противном случае первым аргументом должен быть список, первый элемент которого — float, а необязательный второй элемент — ошибка.

chepner 14.06.2024 21:55

Проблема в том, что format() не распознает "f" как спецификатор str: "[3.1423]"; Попробуйте онлайн.

Поскольку вы форматируете float, рассмотрите возможность использования операции форматирования строки [python.org] для float.

result = "%.3f" % 3.1423

Итак, какие изменения нам следует внести в ваш код?

VEFMT = "%.3f"
#•••Rest of code•••
else:
    v = value[0]
return cls.VEFMT % v, cls.VEFMT % er

Попробуйте онлайн!

format работает не так. Если бы это было так, то format(1.2, ".3f") не сработало бы, но работает.

user2357112 13.06.2024 23:44

@ user2357112 Я пропустил.

Chukwujiobi Canon 13.06.2024 23:46

format все еще работает не так. Если бы это было так, то format('1.2', '.3f') вел бы себя так же, как format(1.2, '.3f'), но первый вызывает исключение, а второй работает нормально.

user2357112 13.06.2024 23:53

Попробуйте этот код

class SingleLineGrooveTable:
    VEFMT = '.3f'

    @classmethod
    def formatve(cls, value, error=None):
        er = 0
        if error is not None:
            er = error
            v = value
        elif len(value) > 1:
            v, er = value
        else:
            v = value[0]  # Extract the float from the list
        return format(v, cls.VEFMT), format(er, cls.VEFMT)

import unittest

class TestSingleLineGrooveTable(unittest.TestCase):
  
    def test_formatve_no_error(self):
        e_v = '3.142'
        e_er = '0.000'
        r_v, r_er = SingleLineGrooveTable.formatve([3.1423])
        self.assertEqual(e_v, r_v)
        self.assertEqual(e_er, r_er)

if __name__ == '__main__':
    unittest.main()

Ввод должен быть либо списком, либо числом с плавающей запятой — по сути, это то, что я сделал, чтобы исправить это, за исключением того, что я добавил «elif type(value) == float or type(value) == int: v = value ", сделал else, у вас есть "elif len(value) == 1", и переместил "v, er = value" в else.

Réka 24.06.2024 18:57

Другие вопросы по теме