Я хочу узнать общие расходы клиента и общие расходы, понесенные на дату, из двух словарей.
def analysis(file: str, customer: str, date: str) -> (float, float):
try:
with open(file, 'r') as filehand:
for row in filehand:
print(row)r]
else:
return "Name not found"
if date in dates:
date_expense = dates[date]
else:
return "Date not found"
except:
return "File not found"
@flakes, спасибо! я исправил эту часть, хотя в целом все еще не получаю правильных результатов.
Обратите внимание, что «csv» не является «внешней библиотекой», а является частью стандартной библиотеки.






Вам нужно разделить каждую строку?
rows = [row.split(',') for row in filehand]
customer_name = {row[0]:int(row[2]) for row in rows}
dates = {row[3]:int(row[2]) for row in rows}
Не разделяя каждую входную строку, оператор [] извлекает отдельные элементы из строк.
это действительно помогло огромное спасибо! Я все еще получаю одну неправильную ошибку в автогрейдере. я обновил свой код в OG, есть ли у вас какие-либо предложения?
У меня плохие новости. Здесь вы допустили почти все возможные ошибки :)
Во-первых, считается плохой практикой использовать только оператор except:, вам следует проверять конкретные типы исключений, чтобы не пропустить ошибки в своем коде. О типах исключений в Python вы можете прочитать там.
Плохой:
except: # catches all possible errors
return "File not found"
Хороший:
except OSError: # catches only OS errors such as "file not found", "disk full", etc.
return "File not found"
В частности, поскольку вы использовали except:, вы не заметили эту ошибку:
return customer_name.get(name, "Name not found")
Вы используете аргумент customer для имени клиента, а не name, и это вызывает исключение, которое не было перехвачено.
Затем возникает проблема с чтением файла:
customer_name = {rows[0]:rows[2] for rows in filehand}
dates = {rows[3]:rows[2] for rows in filehand}
rows[N] дает вам N-й символ из строки файла, чего вы не хотите. Итак, результаты:
>>> customer_name
{'A': 'i', 'S': 's', 'N': 'c', 'M': 'c'}
>>> dates
{}
dates — это просто {}, потому что вы уже прочитали весь файл, чтобы построить customer_name дикт.
Чтобы создать строки данных, вам следует сначала разделить строку, а затем создать словари. Вот так (@SmellyCat также упомянул об этом в своем ответе):
rows = [row.strip().split(',') for row in filehand]
customer_name = {row[0]: row[2] for row in rows}
dates = {row[3]: row[2] for row in rows}
В любом случае, использование dict-понимания - плохая идея, потому что оно не дает того, что вы ожидали:
>>> customer_name
{'Alice White': '600', 'Susan Green': '500', 'Nick Hanes': '500', 'Michael Jones': '155'}
Как видите, для каждого клиента сохраняется только последняя запись данных. Но мы хотим получить суммы. Поэтому нам нужен другой подход. Например, мы могли бы использовать модуль defaultdict from collections для агрегирования значений для каждого клиента/даты. Подробнее о defaultdict там.
customer_name = defaultdict(float) # set the 0.0 value when the key is missed
dates = defaultdict(float)
for row in rows:
name = row[0]
amount = float(row[2]) # need to convert amount to float type
sale_date = row[3]
customer_name[name] += amount
dates[sale_date] += amount
(Отредактировано) Вы также можете реализовать это с помощью простого dict. Если да, то вам следует добавить блок try/except, чтобы выявить возможные ключевые ошибки:
customer_name = {}
dates = {}
for row in rows:
name = row[0]
amount = float(row[2])
sale_date = row[3]
try:
customer_name[name] += amount
except KeyError: # If name is not present in the dictionary
customer_name[name] = amount
try:
dates[sale_date] += amount
except KeyError: # If date is not present in the dictionary
dates[sale_date] = amount
Хорошо, у нас есть словари. Давайте проверим, есть ли в них customer или date. Строки ниже не работают, потому что some_dict.items() дает вам список кортежей (key, value), поэтому вы, очевидно, не найдете в нем ни одного str, потому что str не является tuple. Это всегда подарит вам False. В этом случае вы можете просто найти ключ в самом словаре, как он ищет ключи по умолчанию.
Не работай
if customer in customer_name.items():
if date in dates.items():
Работает хорошо:
if customer in customer_name:
if date in dates:
Итак, мы находим наши customer/date в наших словарях. Но мы сталкиваемся с другой проблемой. Эти строки дают нам сумму всех расходов, а не конкретного customer/date.
customer_expense = sum(list(customer_name.values()))
date_expense = sum(list(dates.values()))
Чтобы получить расход для конкретного customer, мы можем просто использовать customer_name[customer] и аналогично для date. А в блоке else мы просто возвращаем нужную строку.
Вместо этого:
if customer in customer_name.items():
customer_expense = sum(list(customer_name.values()))
else:
return customer_name.get(name, "Name not found")
Сделай это:
if customer in customer_name:
customer_expense = customer_name[customer]
else:
return "Name not found"
Полный код выглядит следующим образом (реализация с использованием обычного dict):
def customer_analysis(filename: str, customer: str, date: str) -> (float, float):
try:
with open(filename, 'r') as filehand:
rows = [row.strip().split(',') for row in filehand]
customer_name = {}
dates = {}
for row in rows:
name = row[0]
amount = float(row[2])
sale_date = row[3]
customer_name.setdefault(name, 0.0)
customer_name[name] += amount
dates.setdefault(sale_date, 0.0)
dates[sale_date] += amount
if customer in customer_name:
customer_expense = customer_name[customer]
else:
return "Name not found"
if date in dates:
date_expense = dates[date]
else:
return "Date not found"
except OSError:
return "File not found"
return customer_expense, date_expense
И для ваших входных данных возвращается, как и ожидалось:
>>> customer_analysis(filename=filename, customer='Alice White', date='2023-09-05')
(615.0, 170.0)
Если имя не найдено в файле:
>>> customer_analysis(filename=filename, customer='Somebody', date='2023-09-05')
Name not found
Если дата не найдена:
>>> customer_analysis(filename=filename, customer='Alice White', date='1492-10-13')
Date not found
привет! Спасибо! есть ли способ сделать это без импорта defaultdict?
Конечно! Вы можете использовать блок try/except для имитации поведения defaultdict. Я обновил ответ, добавив эту реализацию
Можете ли вы уточнить, какой код вы тестировали? Тот, о котором сейчас идет речь, или что-то другое? «Файл не найден» будет отображаться в моем варианте кода только в том случае, если функция получает неправильное имя файла, поэтому очень странно видеть этот результат так часто.
Код, который сейчас находится в вашем вопросе, даст неверный результат, если для одного человека или даты имеется несколько записей.
Нет необходимости использовать метод .get(). Вы можете просто изменить код в соответствии с моим примером кода в конце моего ответа. Я не вижу никаких проблем с этим кодом
Ах, это странно. У меня нет проблем запустить это на моем компьютере. Я снова обновляю пример кода в своем ответе, исключая некоторые утверждения try/except. Может быть, это поможет
Правильно ли я понимаю, что вам нужно возвращать только «Имя не найдено», когда в файле нет имени, а не («Имя не найдено», 170) tuple?
я должен вернуть «Имя не найдено», если заданное имя отсутствует в файле данных!
ваш обновленный код работал! Спасибо!
Вау, здорово! Я удивлен, что такое изменение имеет значение :) Все вопросы по автогрейдеру верны?
да! было 3 теста и он прошел все 3
Прохладный! Не могли бы вы тогда отметить мой ответ как принятый? Итак, этот вопрос будет закрыт.
Формат
return print("message")Недействителен. Вы наверное хотелиraise Exception("message")