Как я могу перебрать аргументы функции?
def grade(*score):
for i in range(0, score):
if score >= 90:
return "A"
elif score >=80:
return "B"
elif score >=70:
return "C"
elif score >=60:
return "D"
else:
return "F"
print(grade(87, 92, 100, 54, 72, 84, 81, 74))
Я хочу иметь возможность перебирать аргументы и возвращать правильную оценку в каждом цикле.
4 ответа
Вы можете использовать цикл for, добавлять каждую оценку в список и возвращать список.
def grade(*score):
grades = []
for i in score:
if i >= 90:
grades.append("A")
elif i >=80:
grades.append("B")
elif i >=70:
grades.append("C")
elif i >=60:
grades.append("D")
else:
grades.append("F")
return grades
print(grade(87, 92, 100, 54, 72, 84, 81, 74))
Как упоминалось в комментариях, здесь доступен лучший дизайн, чем цикл по аргументам. Примените функцию к одному элементу, который является минимальной единицей детализации, необходимой для оценки оценки. Включение цикла в каждую функцию, которую вы, возможно, захотите применить к более чем одному элементу, в лучшем случае является пустой тратой ввода, а в худшем случае действительно наносит ущерб удобочитаемости и обслуживанию вызывающей стороны.
Как правило, когда функция работает с одним устройством, переместите цикл к вызывающему (например,
int
). Цикл внутри функции только тогда, когда требуется работать с итерацией (например,
sort
,
min
,
sum
).
Кроме того, избегайте длинных
if
-else
цепь. Что, если бы у вас было 30 ведер вместо 5? Письмо 30
if
-else
операторы не масштабируются. Назовите это преждевременным, но я чувствую себя неловко, когда
if
-else
цепь становится длиннее 3 или около того.
Вот мое предложение, в котором используется тот факт, что большинство ведер делятся на 10, и нам нужно только учитывать тот факт, что <60 - это гигантское ведро, а 100 требует дополнительного ведра. Теперь полностью устраняем ветки.
>>> def grade(x): return "FFFFFFDCBAA"[x//10]
...
>>> grade(99)
'A'
>>> grade(100)
'A'
>>> grade(80)
'B'
>>> grade(89)
'B'
>>> grade(60)
'D'
>>> grade(59)
'F'
Если вы хотите быть устойчивым, добавьте еще одну строку и проверьте границы, подняв
IndexError
если аргумент вне допустимого диапазона и, возможно,
ValueError
если аргумент неправильного типа.
Вооружившись нашим новым
grade
функцию, мы можем применить ее к одной или итерации оценок по выбору вызывающего:
>>> grades = [87, 92, 100, 54, 72, 84, 81, 74]
>>> [grade(x) for x in grades]
['B', 'A', 'A', 'F', 'C', 'B', 'B', 'C']
>>> list(map(grade, grades)) # alternately
['B', 'A', 'A', 'F', 'C', 'B', 'B', 'C']
В реальном приложении
grades
list не появляется из воздуха как набор литералов или переменных - он должен быть в состоянии как своего рода структура данных. Если вы придерживаетесь дизайна функций как есть, у вас либо есть дополнительный цикл, либо вы застряли в упаковке и распаковке структур данных, либо и то, и другое.
Также существует проблема с семантикой / удобочитаемостью:
grade(100, 20, 64)
Непонятно, какая операция должна произойти. Является
grade
собираетесь вернуть среднее значение всех оценок и выставить итоговую оценку? Редукция - типичный образец для таких функций с переменным аргументом (например,
sum
,
min
, и т.д). Когда вызывающий абонент использует
[grade(x) for x in grades]
, гораздо яснее, что мы используем операцию сопоставления, применяя функцию
grade
индивидуально для каждого элемента, а не для коллекции как целого. Следуя этой логике, лучшее имя функции может быть
score_to_letter_grade
или аналогичный, который четко описывает выполняемую операцию 1:1.
Кроме того, если вы просто хотите оценить что-то одно, вы застряли со списком в качестве результата, независимо от того, что в значительной степени мгновенно нарушает правила для поддержания чистоты вызывающего абонента. Если встроенный
int
работал так, это было бы действительно большой болью в тылу:
x = int(x)[0]
просто разобрать
x
от целого числа к строке.
Это не такая уж ужасная ситуация, потому что существует такой небольшой объем кода, но большие проблемы дизайна можно объяснить на микромасштабе, как это, и это неправильное распределение ответственности может накапливать задолженность за дизайн при применении к более крупным базам кода.
Вы можете попробовать этот интересный компактный способ сделать это (и я не уверен, что вы ошиблись, но да, это работает кортеж):
def grade(score):
scores = {range(90,101):"a", range(80,90):"b", range(70,80):"c", range(60,70):"d", range(1,60):"f"}
return tuple([scores[gradeRange] for i in score for gradeRange in scores.keys() if i in gradeRange])
print(grade((100,30,70)))
("a","f","c")
for student in grade_tuple:
print(grade(student))
- Предполагая, что вы переписываете grade(), чтобы рассчитывать только на один балл...