Запишите, какой бы ни более ясно состояния Ваше намерение.
После Ваших работ программы, выясните то, что является медленным, и сделайте это быстрее.
не делают этого наоборот.
Во-первых, все, что вы делаете, не возвращает результат и сообщение об ошибке. Это действительно плохой способ справляться с ошибками, который вызовет бесконечную головную боль. Если вам нужно указать ошибку, всегда вызывайте исключение .
Я обычно стараюсь избегать появления ошибок, если в этом нет необходимости. В вашем примере выдача ошибки на самом деле не требуется. Пересечение пустого списка с непустым не является ошибкой. Результатом является пустой список, и это правильно. Но предположим, что вы хотите заняться другими делами. Например, если метод получил тип, отличный от списка. В этом случае лучше вызвать исключение. Нечего бояться исключений.
Мой совет - посмотрите библиотеку Python на предмет похожих функций и посмотрите, как Python обрабатывает эти особые случаи. Например, взгляните на метод пересечения в наборе, он имеет тенденцию прощать. Здесь я пытаюсь пересечь пустой набор с пустым списком:
>>> b = []
>>> a = set()
>>> a.intersection(b)
set([])
>>> b = [1, 2]
>>> a = set([1, 3])
>>> a.intersection(b)
set([1])
Ошибки выдаются только при необходимости:
>>> b = 1
>>> a.intersection(b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
Конечно, есть случаи, когда возврат True или False в случае успеха или неудачи может быть хорошим. Но очень важно быть последовательным. Функция всегда должна возвращать один и тот же тип или структуру. Очень запутанно иметь функцию, которая может возвращать список или логическое значение. Или верните тот же тип, но значение этого значения может быть другим в случае ошибки.
EDIT:
OP говорит:
Я хочу вернуть что-то, чтобы указать Есть случаи, когда возврат True или False в случае успеха или неудачи может быть хорошим. Но очень важно быть последовательным. Функция всегда должна возвращать один и тот же тип или структуру. Очень запутанно иметь функцию, которая может возвращать список или логическое значение. Или верните тот же тип, но значение этого значения может быть другим в случае ошибки.
EDIT:
OP говорит:
Я хочу вернуть что-то, чтобы указать Есть случаи, когда возврат True или False в случае успеха или неудачи может быть хорошим. Но очень важно быть последовательным. Функция всегда должна возвращать один и тот же тип или структуру. Очень запутанно иметь функцию, которая может возвращать список или логическое значение. Или верните тот же тип, но значение этого значения может быть другим в случае ошибки.
EDIT:
OP говорит:
Я хочу вернуть что-то, чтобы указать параметры были неправильными.
Ничто не говорит об ошибке лучше, чем исключение. Если вы хотите указать, что параметры неверны, используйте исключения и поместите полезное сообщение об ошибке. Возврат результата в этом случае просто сбивает с толку. Могут быть и другие случаи, когда вы хотите указать, что ничего не произошло, но это не ошибка. Например, если у вас есть метод, который удаляет записи из таблицы, а запись, запрошенная для удаления, не существует. В этом случае может быть нормально просто вернуть True или False в случае успеха или неудачи. Это зависит от приложения и предполагаемого поведения
Исключения определенно лучше (и более питоничны), чем возвращаемый статус. Подробнее об этом: Исключения и возврат состояния
Было бы лучше вызвать исключение , чем возвращать специальное значение. Это именно то, для чего были разработаны исключения, чтобы заменить коды ошибок более надежным и структурированным механизмом обработки ошибок.
class IntersectException(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg
def intersect_two_lists(self, list1, list2):
if not list1: raise IntersectException("list1 must not be empty.")
if not list2: raise IntersectException("list2 must not be empty.")
#http://bytes.com/topic/python/answers/19083-standard
return filter(lambda x:x in list1,list2)
В этом конкретном случае я бы, вероятно, просто отказался от тестов. На самом деле нет ничего плохого в пересечении пустых списков. Кроме того, лямбда
в наши дни отчасти не одобряется, а не списком. См. Найти пересечение двух списков? , где есть несколько способов написать это без использования лямбда
.
Мне нравится возвращать кортеж:
(True, some_result)
(False, some_useful_response)
Объект some_useful_response может использоваться для обработки условия возврата или может служить для отображать отладочную информацию.
ПРИМЕЧАНИЕ : этот метод применяется к возвращаемым значениям любого типа. Его не следует путать с исключениями .
На принимающей стороне вам просто нужно распаковать:
Код, Response = some_function (...)
Этот метод применяется для «нормальный» поток управления: необходимо использовать функцию исключения, когда происходят некоторые неожиданные вводы / обработки.
Также стоит отметить: этот метод помогает нормализовать возвращаемые функции. И программист, и пользователь функций знают, чего ожидать .
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я пришел из опыта Erlang:
В общем случае создаются исключения для исключительных обстоятельств. Хотелось бы, чтобы я мог вспомнить точную цитату (или того, кто ее сказал), но вы должны стремиться к функциям, которые принимают столько значений и типов, сколько разумно, и поддерживают очень узко определенное поведение. Это вариант того, о чем Надя говорила . Рассмотрим следующие варианты использования вашей функции:
correct_two_lists (None, None)
Intercct_two_lists ([], ())
Intercct_two_lists ('12 ',' 23 ')
correct_two_lists ([1, 2 ], {1: 'one', 2: 'two'})
correct_two_lists (False, [1])
correct_two_lists (None, [1])
Я ожидал, что (5) бросит исключение, поскольку передача False
является ошибкой типа. Остальные, однако, имеет некоторый смысл, но это действительно зависит от контракта, который устанавливает функция. Если correct_two_lists
был определен как возвращающий пересечение двух итераций , тогда все, кроме (5), должно работать, пока вы сделаете None
допустимым представлением пустой набор . Реализация будет примерно такой:
def intersect_two_lists(seq1, seq2):
if seq1 is None: seq1 = []
if seq2 is None: seq2 = []
if not isinstance(seq1, collections.Iterable):
raise TypeError("seq1 is not Iterable")
if not isinstance(seq2, collections.Iterable):
raise TypeError("seq1 is not Iterable")
return filter(...)
Я обычно пишу вспомогательные функции, которые обеспечивают выполнение контракта, а затем вызываю их для проверки всех предварительных условий. Примерно так:
def require_iterable(name, arg):
"""Returns an iterable representation of arg or raises an exception."""
if arg is not None:
if not isinstance(arg, collections.Iterable):
raise TypeError(name + " is not Iterable")
return arg
return []
def intersect_two_lists(seq1, seq2):
list1 = require_iterable("seq1", seq1)
list2 = require_iterable("seq2", seq2)
return filter(...)
Вы также можете расширить эту концепцию и передать «policy» в качестве необязательного аргумента. Я бы не советовал делать это, если вы не хотите использовать Дизайн на основе политик . Я действительно хотел упомянуть об этом на случай, если вы раньше не рассматривали этот вариант.
Если контракт для correct_two_lists
предполагает, что он принимает только два непустых параметра list
, тогда укажите это явно и выбросите исключения, если контракт нарушается:
def require_non_empty_list(name, var):
if not isinstance(var, list):
raise TypeError(name + " is not a list")
if var == []:
raise ValueError(name + " is empty")
def intersect_two_lists(list1, list2):
require_non_empty_list('list1', list1)
require_non_empty_list('list2', list2)
return filter(...)
Я думаю, что Мораль истории такова: что бы вы ни делали, делайте это последовательно и четко . Лично я обычно предпочитаю создавать исключения всякий раз, когда контракт нарушается или мне дают значение, которое я действительно не могу использовать. Если ценности, которые мне дают, разумны, то я стараюсь сделать что-нибудь разумное взамен. Вы также можете прочитать C ++ FAQ Lite об исключениях. Эта конкретная запись дает вам еще пищу для размышлений об исключениях.
затем будьте явными и бросайте исключения, если контракт нарушается:def require_non_empty_list(name, var):
if not isinstance(var, list):
raise TypeError(name + " is not a list")
if var == []:
raise ValueError(name + " is empty")
def intersect_two_lists(list1, list2):
require_non_empty_list('list1', list1)
require_non_empty_list('list2', list2)
return filter(...)
Я думаю, что мораль этой истории такова , что бы вы ни делали, делайте это последовательно и четко . Лично я обычно предпочитаю создавать исключения всякий раз, когда контракт нарушается или мне дают значение, которое я действительно не могу использовать. Если ценности, которые мне дают, разумны, то я стараюсь сделать что-нибудь разумное взамен. Вы также можете прочитать C ++ FAQ Lite об исключениях. Эта конкретная запись дает вам еще пищу для размышлений об исключениях.
затем будьте явными и бросайте исключения, если контракт нарушается:def require_non_empty_list(name, var):
if not isinstance(var, list):
raise TypeError(name + " is not a list")
if var == []:
raise ValueError(name + " is empty")
def intersect_two_lists(list1, list2):
require_non_empty_list('list1', list1)
require_non_empty_list('list2', list2)
return filter(...)
Я думаю, что мораль этой истории такова , что бы вы ни делали, делайте это последовательно и четко . Лично я обычно предпочитаю создавать исключения всякий раз, когда контракт нарушается или мне дают значение, которое я действительно не могу использовать. Если ценности, которые мне дают, разумны, то я стараюсь сделать что-нибудь разумное взамен. Вы также можете прочитать C ++ FAQ Lite об исключениях. Эта конкретная запись дает вам еще пищу для размышлений об исключениях.
Я обычно предпочитаю создавать исключения, когда контракт нарушается или мне дают значение, которое я действительно не могу использовать. Если ценности, которые мне дают, разумны, я стараюсь сделать что-нибудь разумное взамен. Вы также можете прочитать C ++ FAQ Lite об исключениях. Эта конкретная запись дает вам еще пищу для размышлений об исключениях. Я обычно предпочитаю создавать исключения, когда контракт нарушается или мне дают значение, которое я действительно не могу использовать. Если ценности, которые мне дают, разумны, я стараюсь сделать что-нибудь разумное взамен. Вы также можете прочитать C ++ FAQ Lite об исключениях. Эта конкретная запись дает вам еще пищу для размышлений об исключениях.