Где мне следует поставить проверки на входные данные класса. Сейчас я ставлю __init__
следующим образом, но не уверен, что это правильно. См. пример ниже.
import numpy as np
class MedianTwoSortedArrays:
def __init__(self, sorted_array1, sorted_array2):
# check inputs --------------------------------------------------------
# check if input arrays are np.ndarray's
if isinstance(sorted_array1, np.ndarray) == False or \
isinstance(sorted_array2, np.ndarray) == False:
raise Exception("Input arrays need to be sorted np.ndarray's")
# check if input arrays are 1D
if len(sorted_array1.shape) > 1 or len(sorted_array2.shape) > 1:
raise Exception("Input arrays need to be 1D np.ndarray's")
# check if input arrays are sorted - note that this is O(n + m)
for ind in range(0, len(sorted_array1)-1, 1):
if sorted_array1[ind] > sorted_array1[ind + 1]:
raise Exception("Input arrays need to be sorted")
# end of input checks--------------------------------------------------
self.sorted_array1 = sorted_array1
self.sorted_array2 = sorted_array2
Обычно у вас есть две возможности проверить аргументы, переданные в выражение конструктора:
Обычно вам следует использовать __init__
для инициализации и проверки. Используйте __new__
только в тех случаях, когда требуются его уникальные характеристики. Итак, ваши чеки находятся на «правильном» месте.
Если вы также хотите проверить любые назначения переменным экземпляра, которые происходят после инициализации, вам может оказаться полезным этот вопрос и ответы на него.
__new__
Одной из отличительных характеристик __new__
является то, что он вызывается до создания экземпляра соответствующего класса. Фактически, вся цель __new__
— создать экземпляр. (Затем этот экземпляр передается __init__
для инициализации.)
Как указано в документации, «__new__() предназначен главным образом для того, чтобы позволить подклассам неизменяемых типов (таких как int, str или tuple) настраивать создание экземпляров». Следовательно, при создании подкласса неизменяемого типа вы, скорее всего, включите логику проверки в __new__
, а не в __init__
.
Рассмотрим простой пример, в котором вы хотите создать подкласс tuple
, называемый Point2D
, который позволяет создавать только экземпляры, содержащие 2 float
(целесообразно ли создавать подкласс tuple
для этой цели - другой вопрос):
class Point2D(tuple):
def __new__(cls, x, y):
if not isinstance(x, (int, float)) or not isinstance(y, (int, float)):
error = "The coordinates of a 2D point have to be numbers"
raise TypeError(error)
return super().__new__(cls, (float(x), float(y)))
В документации на __new__
говорится, что «его также часто переопределяют в пользовательских метаклассах, чтобы настроить создание классов». Этот вариант использования и многие другие варианты использования выходят за рамки этого вопроса. Если вас все еще интересуют различия между __new__
и __init__
, вам могут пригодиться эти источники:
Не имеет отношения к основному вопросу: если аргументы недействительны, тип возникающего исключения должен быть как можно более конкретным. В твоем случае:
Exception
.Exception
.@Amazonian, я добавил дополнительную информацию о выполнении проверки в __new__
.
Можете ли вы привести пример того, где проверка будет включена в
__new__
? Я не знаком с этим методом и нашел документацию немного абстрактной.