Про набір качок :
Введення качок допомагає звичайним чином не перевіряти тип аргументів у органах методів та функцій, спираючись на документацію, чіткий код та тестування для забезпечення правильного використання.
Про перевірку аргументів (EAFP: простіше просити пробачення, ніж дозволу). Адаптований приклад звідси :
... вважається більш пітонічним зробити:
def my_method(self, key):
try:
value = self.a_dict[member]
except TypeError:
# do something else
Це означає, що будь-хто інший, що використовує ваш код, не повинен використовувати реальний словник або підклас - вони можуть використовувати будь-який об’єкт, що реалізує інтерфейс відображення.
На жаль, на практиці це не так просто. Що робити, якщо член у наведеному вище прикладі може бути цілим числом? Цілі особи незмінні - тому цілком розумно використовувати їх як словникові ключі. Однак вони також використовуються для індексації об'єктів типу послідовності. Якщо член має ціле число, то приклад два може пропустити списки та рядки, а також словники.
Про асертивне програмування:
Твердження - це систематичний спосіб перевірити, чи внутрішній стан програми такий, як очікував програміст, з метою виявлення помилок. Зокрема, вони гарні для лову помилкових припущень, які були зроблені під час написання коду, або зловживання інтерфейсом іншим програмістом. Крім того, вони можуть в деякій мірі виконувати функції внутрішньої документації, роблячи очевидні припущення програміста. ("Явне краще, ніж неявне.")
Згадані поняття іноді суперечать, тому я розраховую на такі фактори, коли вибираю, якщо я взагалі не здійснюю перевірку даних, роблю сильну перевірку чи використовую твердження:
Сильна перевірка. Під сильною валідацією я маю на увазі підняття спеціального винятку (
ApiError
наприклад). Якщо моя функція / метод є частиною загальнодоступного API, краще перевірити аргумент, щоб показати гарне повідомлення про помилку про несподіваний тип. Перевіряючи тип, я не маю на увазі лише використанняisinstance
, але також, якщо переданий об'єкт підтримує необхідний інтерфейс (набирання качки). Хоча я документую API та вказую очікуваний тип, і користувач може захотіти використовувати мою функцію несподівано, я відчуваю себе безпечнішим, коли перевіряю припущення. Я зазвичай використовую,isinstance
і якщо пізніше я хочу підтримувати інші типи або качки, я змінюю логіку перевірки.Асертивне програмування. Якщо мій код новий, я використовую твердження багато. Які ваші поради щодо цього? Пізніше ви видаляєте твердження з коду?
Якщо моя функція / метод не є частиною API, але передає деякі свої аргументи до іншого коду, не написаного, вивченого чи перевіреного мною, я роблю багато тверджень відповідно до названого інтерфейсу. Моя логіка за цим - краще провал у моєму коді, то десь на 10 рівнів глибше в стек-трасі з незрозумілою помилкою, яка змушує багато налагоджувати, а пізніше додавати твердження до мого коду все одно.
Коментарі та поради щодо того, коли використовувати чи не використовувати перевірку типу / значення, стверджує? Вибачте за не найкращу постановку питання.
Наприклад, розглянемо наступну функцію, де Customer
є декларативна модель SQLAlchemy:
def add_customer(self, customer):
"""Save new customer into the database.
@param customer: Customer instance, whose id is None
@return: merged into global session customer
"""
# no validation here at all
# let's hope SQLAlchemy session will break if `customer` is not a model instance
customer = self.session.add(customer)
self.session.commit()
return customer
Отже, існує декілька способів обробки валідації:
def add_customer(self, customer):
# this is an API method, so let's validate the input
if not isinstance(customer, Customer):
raise ApiError('Invalid type')
if customer.id is not None:
raise ApiError('id should be None')
customer = self.session.add(customer)
self.session.commit()
return customer
або
def add_customer(self, customer):
# this is an internal method, but i want to be sure
# that it's a customer model instance
assert isinstance(customer, Customer), 'Achtung!'
assert customer.id is None
customer = self.session.add(customer)
self.session.commit()
return customer
Коли і навіщо ви використовуєте кожне з них у контексті типи качок, перевірки типу, перевірки даних?