Как я могу перебрать аргументы функции?

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']

В реальном приложении gradeslist не появляется из воздуха как набор литералов или переменных - он должен быть в состоянии как своего рода структура данных. Если вы придерживаетесь дизайна функций как есть, у вас либо есть дополнительный цикл, либо вы застряли в упаковке и распаковке структур данных, либо и то, и другое.

Также существует проблема с семантикой / удобочитаемостью: 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(), чтобы рассчитывать только на один балл...
Другие вопросы по тегам