Вернуть другой класс на основе необязательного флага в аргументах без фабрики.Python

Программы на Python
Ответить
Anonymous
 Вернуть другой класс на основе необязательного флага в аргументах без фабрики.

Сообщение Anonymous »

Я реализую ряд классов в Equinox, чтобы можно было использовать производные по параметрам класса. Большую часть времени пользователь будет создавать экземпляр класса A и использовать функцию fn для генерации некоторых данных, детали которых не важны. Однако в тех случаях, когда нас интересуют градиенты, полезно представить param_c в виде сигмовидной функции, чтобы гарантировать, что он останется зафиксированным в диапазоне (0,1). Однако я не хочу, чтобы пользователь заметил разницу в поведении класса, если он это сделает. Таким образом, я реализую другой класс A_sigmoid, который имеет параметр param_c в качестве свойства, и использую A_abstract, чтобы гарантировать, что оба класса наследуют метод fn, который будет вызывать param_c в его логике. Хотя я мог бы просто попросить пользователя создать экземпляр объекта A_sigmoid с помощью _param_c_sigmoid вместо param_c, я не хочу заставлять пользователя делать это различие. Скорее, я бы хотел, чтобы они передавались в один и тот же словарь kwargs независимо от класса и чтобы преобразование происходило незаметно. Я также хотел сделать так, чтобы при создании нового A можно было просто передать необязательный флаг, чтобы указать программе использовать сигмовидную версию кода. Для этого я реализовал следующий MWE:
class A_abstract(eqx.Module):
param_a: jax.Array
param_b: jax.Array
param_c: eqx.AbstractVar[jax.Array]

def fn(self,*args,**kwargs):
pass

class A_sigmoid(A_abstract):
_param_c_sigmoid: jax.Array

@property
def param_c(self):
return 1 / (1 + jnp.exp(-self._param_c_sigmoid))

class A(A_abstract):
param_c: jax.Array

def __new__(cls, **kwargs):
sigmoid_flag = kwargs.pop('use_sigmoid_c',False)
if sigmoid_flag == True:
param_c = kwargs.pop('param_c')
_param_c_sigmoid = jnp.log(param_c / (1 - param_c))
kwargs['_param_c_sigmoid'] = _param_c_sigmoid
instance = A_sigmoid.__new__(A_sigmoid)
instance.__init__(**kwargs)
print(type(instance))
return instance
else:
return super(A,cls).__new__(cls)

classA = A(param_a = 1.,param_b = 2.,param_c = 0.5,use_sigmoid_c=True)
print(type(classA))

В коде правильно указано, что экземпляр имеет тип A_sigmoid, когда print вызывается в методе __new__. Однако когда я печатаю type(classA), он имеет тип A и не имеет атрибута param_c, хотя у него есть значение для _param_c_sigmoid. Почему это так? Я что-то упустил при использовании __new__, что вызывает эту ошибку? Хотя я знаю, что в принципе лучшим способом сделать это будет фабрика, существуют другие классы типов B, C и т. д., которым не нужна сигмовидная реализация, и которые Я хотел бы вести себя точно так же, как A, чтобы их можно было легко менять местами. Таким образом, я не хочу, чтобы какой-либо собственный метод создавал экземпляр A, который отличался бы от вызова конструктора по умолчанию в других классах.
Я запускаю это в блокноте Jupyter. со следующими версиями пакета:
Python : 3.12.4
IPython : 8.30.0
ipykernel : 6.29.5
jupyter_client : 8.6.3
jupyter_core : 5.7.2


Подробнее здесь: https://stackoverflow.com/questions/793 ... thout-fact
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»