Python вставляет двоеточие в десятичное число из Access через pyodbc

у меня естьта же проблема, что и у этого парня и, возможно,этот пареньЯ собираюсь поделиться кодом и ответить на вопросы!

У меня есть некоторый код в пакетном задании, которое читает поля из базы данных Microsoft Access через pyodbc и подготавливает вывод для отображения.

Вот фрагмент. Обратите внимание на утверждение.

def format_currency(amount):
    if amount is None:
        return ""
    else:
        result = "$%.2f" % amount
        assert ":" not in result, (
            "That's weird. The value %r of class %s is represented as %s" %
             (amount, amount.__class__, result))
        return result

Когда я запускаю его, он успешно обрабатывает 100 000 строк, а затем завершается ошибкой:

AssertionError: That's weird. The value Decimal('54871.0000') of class  is represented as $54870.:0

Обратите внимание на аберрантную кишку. Это происходит редко - примерно один раз в 300 000 записей.

Когда я пытаюсь изолировать это, конечно, это работает.

from decimal import Decimal
print "$%.2f" % Decimal('54871.0000')

$ 54871,00

Тип поля в Access:

Тип данных: валютаДесятичные знаки: 2Маска ввода:Значение по умолчанию:Правило проверки:Выравнивание текста: общее

Мое смутное подозрительное подозрение основано на недостаточных доказательствах: pyodbc ковыряется во внутренностях Decimal, возможно, в замешательстве из-за повреждения Access. Как @ecatmurуказывает на то:':'

 это 9 +1 в ASCII

Кто-нибудь видел это и решил?

Версии:

Python 2.7.4pyodbc 3.0.6 (последняя версия)Access 2010Windows 7

Копаем дальше:

decimal Модуль реализован на Python. Из моего чтения значения описываются четырьмя атрибутами:,,,_exp_int_sign_is_special

Заподозрив коррупцию, я распечатал значения этих полей.

Удивительно, но дляи то и другое Неисправную и рабочую версию я получаю:

_exp: -4
_int: 548710000
_sign: 0
_is_special: False

Тот'странно

вdecimal модуль,__float__ Функция определяется довольно просто:

def __float__(self):
    """Float representation."""
    return float(str(self))

Но когда я делаю это с плохими данными:

print "Str", str(amount)
print "Float", float(amount)

Я получил:

Ул 54871,0000

Поплавок 54870 .:

Чем больше я учусь, тем менее страннымне получить.

 Oddthinking18 мая 2013 г., 03:51
@GordThompson: валюта, с 2 цифрами. (Отредактированный вопрос для добавления.)
 Gord Thompson18 мая 2013 г., 00:34
Какой тип поля вы читаете из таблицы базы данных Access? ...Валюта? ... номер (двухместный)? ... число (десятичное число)?

Ответы на вопрос(1)

Решение Вопроса

ta] ...

ID - AutoNumber

Сумма - Валюта (2 десятичных знака)

... и заполнил его миллионами строк случайных значений от 50000 до 60000. Когда я запустил свой тестовый скрипт, он потерпел неудачу здесь

30815 : $50638.91
30816 : $52423.28
30817 :

Traceback (most recent call last):
  File "C:\__tmp\pyOdbcTest.py", line 20, in <module>
    print row.ID, ":", format_currency(row.Amount)
  File "C:\__tmp\pyOdbcTest.py", line 10, in format_currency
    (amount, amount.__class__, result))
AssertionError: That's weird. The value Decimal('58510.0000') of class <class 'decimal.decimal'=""> is represented as $5850:.00
</class></module>

Я также проверил это значение (58510,00) и значение, которое для вас не удалось (54871,00), как отдельные строки в отдельной таблице с одинаковой структурой, и оба они потерпели неудачу. Итак, мы знаем, что этоне является функцией какого-то остатка "барахло» из более раннего вызова ODBC.

Думая, что это может быть связано с числом, имеющим «1» с нулями в конце числа, я попытался 55871,00, но это работало нормально. 53871.00 тоже работало нормально. Смена номера обратно на 54871.00 вернула ошибку.

Я попробовал тот же тест, используяpypyodbc и получил ту же ошибку. Я был несколько оптимистичен, потому что pypyodbc включает в себя ряд специфичных для Access функций, поэтому я подумал, что один из его пользователей, возможно, сталкивался с этой проблемой раньше, но, видимо, нет.

Наконец, я увеличил тестовую таблицу до SQL Server 2008 R2 Express и попробовал тот же тест, используя драйвер {SQL Server Native Client 10.0}. Номера, которые не удалось прочитать при доступе из ("Валюта" тип столбца) сделалне ошибка при чтении из таблицы SQL Server ("Деньги" тип столбца).

Итак, лучшее, что я могу предложить дляответ" на данный момент есть:

Похоже, этоs либо:

ошибка в pyodbc (и pypyodbc, которая, по-видимому, очень тесно связана с pyodbc), или

ошибка в драйвере ODBC для Microsoft Access, или

"неудачное взаимодействие " между двумя (если спецификация ODBC достаточно свободна, что ни один из компонентов технически не является "неправильно").

В любом случае это выглядит как тыНадо будет обойти это, по крайней мере сейчас.

редактировать

Поскольку у меня была эта большая партия чисел, я решил позволить сценарию продолжить работу и посмотреть, какие другие числа могут быть отформатированы с двоеточием в них. Получившийся список представлял собой целые числа (без копеек), поэтому я провел еще один тест с целыми числами от 1 до 100 000. Я нашел 260 чисел, которые завершились двоеточием в отформатированной строке:

1451.0000 -> $1450.:0
1701.0000 -> $1700.:0
1821.0000 -> $1820.:0
1951.0000 -> $1950.:0
2091.0000 -> $2090.:0
...
98621.0000 -> $98620.:0
98710.0000 -> $9870:.00
99871.0000 -> $99870.:0

Я вставил весь списокВот, Возможно, это может быть полезно.

Редактировать - проблема решена (?)

Мои предыдущие тесты были запущены под Python версии 2.7.3. Я только что обновил Python до версии 2.7.5 (Win 32-bit) с pyodbc до версии 3.0.6, и проблема, похоже, ушла.

 Gord Thompson25 мая 2013 г., 16:34
@ Странно, я только что обновил свой ответ. После обновления Python (не pyodbc) проблема, похоже, ушла.
 Gord Thompson18 мая 2013 г., 21:15
@ Странно звучит хорошо. Пожалуйста, отправьте сюда сюда с любым прогрессом. Кстати, я обновил свой ответ, добавив немного больше информации, которая может помочь отследить это.
 Oddthinking18 мая 2013 г., 20:41
Фантастика. Это'облегчение, что это не такт самопричиненный. Я обращаюсь к разработчикам pyodbc, чтобы узнать, есть ли у них что-то, что они могли бы внести.

Ваш ответ на вопрос