Я использую 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' в операторе возврата функции. Но я не могу понять, откуда он берет строку. Возможно, это актуально, этот код и код, который у меня есть, который его использует, были в значительной степени скопированы из чужого кода (с которым я больше не могу связаться), так что, возможно, я называю его неправильно, но тем не менее, это список, не веревка!
Что здесь происходит? Как это исправить?
v = value должно быть v = value[0]. Ошибка возникает при попытке отформатировать список как float.
Вопрос о том, почему вы получаете конкретное сообщение об ошибке при явно непреднамеренном вызове [3.1423].__format__('.3f'), менее важен, чем намеренный вызов 3.1423.__format__('.3f').
@Mike'Pomax'Kamermans К сожалению, я пишу сценарии, которые взаимодействуют с приложением, имеющим только пакет Python для Python 2.7, поэтому переключение действительно не вариант. Я бы с радостью, учитывая акцент моего имени, мне буквально пришлось редактировать кодировку в исходном коде версии 2.7, чтобы она могла работать, но это не вариант :( Даже если бы приложение имело версию Python 3, мы иметь слишком много кода для переключения, чтобы быть практичным.
@chepner Сначала я подумал, что это не должен быть список, но отсутствие списка приводит к тому, что elif len(value) выдает ошибку... Хотя, глядя на код предыдущего кодера, который использует это, я на самом деле не уверен, что он когда-либо вызывал это без значения ошибки, и он не тестировал его. Так что, возможно, это была ошибка, которую так и не обнаружили. Я предположил, что это моя проблема, потому что этот код использовался уже много лет.
@Mike'Pomax'Kamermans Подожди, что ты имеешь в виду, что нужно два аргумента? Первый аргумент — cls. Это не нужно заполнять
ах, извини, хорошая мысль. Чтобы запустить его как минимальный воспроизводимый пример , я убрал из него синтаксис класса. Хотя при этом сказано: пожалуйста, не забудьте указать проблему как MRE. и для того, чтобы люди могли увидеть, что что-то идет не так, и для того, чтобы заставить себя взглянуть на код совершенно другим критическим способом отладки. Обычно при подготовке MRE вы действительно обнаруживаете проблему и необходимость публикации становится спорной =)






В Python 2 object.__format__ эффективно делегирует format(str(self), format_spec). Посмотреть реализацию можно здесь.
Поскольку list наследует object.__format__, ваш первый вызов format фактически является вызовом format(str([3.1423]), '.3f'). Вот почему вы получаете сообщение об ошибке.
В Python 3 это все равно приведет к ошибке. Просто это будет другая ошибка.
Ну, это странно. Как я уже сказал, я скопировал это у другого программиста, который работал на моей работе, и когда я попытался использовать 3.1423 в качестве аргумента, а не в качестве списка, он пожаловался, что не может использовать для него len(). Хотя, глядя на его код, я не уверен, использовал ли он это когда-либо без ввода значения ошибки, и у него не было для этого модульных тестов...
Но спасибо, это имеет смысл и позволило мне понять, как исправить мой код!
По сути, если вы указали явную ошибку, вы можете передать голый float. В противном случае первым аргументом должен быть список, первый элемент которого — float, а необязательный второй элемент — ошибка.
Проблема в том, что 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 % erformat работает не так. Если бы это было так, то format(1.2, ".3f") не сработало бы, но работает.
@ user2357112 Я пропустил.
format все еще работает не так. Если бы это было так, то format('1.2', '.3f') вел бы себя так же, как format(1.2, '.3f'), но первый вызывает исключение, а второй работает нормально.
Попробуйте этот код
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.
В любом случае я собираюсь предложить перейти на Python 3, даже если вы не хотите этого слышать. Все еще использовать 2.7 в 2024 году — это странно. Тем не менее: вам захочется превратить это в минимальный воспроизводимый пример, потому что прямо сейчас вы показываете
def formatve, который принимает два аргумента (и третий необязательный), но затем ваш код, кажется, вызывает его с помощью единственный аргумент, так что это должно быть бросаниеTypeError: formatve() missing 1 required positional argument: 'value'. Кроме того, в вашем коде нет f-строк, так вы уверены насчет тега f-строки в своем сообщении?