#python #class #keyword-argument #optional-arguments
Вопрос:
Пожалуйста, рассмотрите следующий код:
def build_matrix(x_coordinates, y_coordinates, calc_element, **kwargs):
matrix = np.zeros((len(x_coordinates), len(y_coordinates)))
for i in range(len(x_coordinates)):
for j in range(len(y_coordinates)):
matrix = calc_element(x_coordinates[i], y_coordinates[j], i, j, **kwargs)
return matrix
Функция build_matrix
используется для построения матрицы путем заполнения ее элементов с помощью вызываемой функции calc_element
. Поскольку я точно не знаю, какие все возможные функции могут быть переданы этой build_matrix
функции, я использую необязательные аргументы ключевых слов, чтобы мне не нужно было менять build_matrix
их каждый раз, когда я хочу использовать их с другой функцией (единственное, что объединяет все эти функции, — это то, что им нужны аргументы x_coords_i, y_coords_j, i, j
).
Тем не менее, мне было интересно, будет ли питоническим использовать класс в этом случае вместо функции. Например, если бы я определил конкретную версию calc_element
следующим образом
class calc_element_velocity_mass():
def __init__(self, velocity, mass):
self.velocity = velocity
self.mass = mass
def __call__(self, x_coords_i, y_coords_j, i, j):
return self.velocity * i / x_coords_i - y_coords_j * j * self.mass
затем, после инициализации, выполните следующие действия
calc_element = calc_element_velocity_mass(20, 10)
Я мог бы передать его build_matrix
без использования необязательных аргументов ключевого слова, т. Е., например, без передачи kwargs = dict(mass = 10, velocity = 20)
build_matrix
.
Вопрос: Будет ли это правильным способом занятий? И правильна ли моя первоначальная реализация, или мне следует подойти к этому по-другому? Спасибо!
Комментарии:
1. Любой из вариантов кажется мне разумным. Главное здесь то, что
build_matrix()
определяет, какcalc_element
используется. Если вы хотитеbuild_matrix
заключить контракт, у вас есть большая гибкость в том, каким должен быть ваш контракт. Обратите внимание , что текущая реализация позволяетbuild_matrix()
принимать пустоеkwargs
значение, поэтому классcalc_element_velocity_mass
будет работать с ним как есть.2. Ну, для начала,
def __init__(self, **kwargs):
наверное, так и должно бытьdef __init__(self, velocity, mass)
. В любом случае, работает либо то, либо другое.3. Обратите внимание, что клиент для вашей функции может просто передать
lambda x_cords_i, y_cords_j, i, j: calc_element(x_cords_i, y_cords_j, i, j, velocity=20, mass=10)
, например (т. Е. с использованием частичного приложения). Важной частью является то, что ваш API должным образом задокументирован
Ответ №1:
Ваше классовое решение определенно сработало бы, но закрытие было бы гораздо более простым способом сделать то же самое:
def calc_element_velocity_mass(velocity, mass):
def f(x_coords_i, y_coords_j, i, j):
return velocity * i / x_coords_i - y_coords_j * j * mass
return f
Вы также можете вернуть лямбду вместо f
, но я использовал здесь именованную функцию для ясности.
Комментарии:
1. Ура закрытиям! Это такой отличный способ элегантно инкапсулировать небольшое состояние.