У меня есть класс с очень общим инициализатором, принимающим любую комбинацию args
и kwargs
. Я хотел бы реализовать другой способ создания экземпляров, который будет использовать 3 списка: один для args
и два для kwargs
(Key
и values
, оба одинаковой длины). Очевидно, что я не могу сделать это с помощью моего обычного __init()__
метода, поскольку прохождение 3 списков является вполне допустимым случаем.
class MyVeryGenericClass:
__init__(self, *args, **kwargs):
pass #Do something really nice with args and kwargs, any case is valid.
По этой причине, я полагаю, мне придется использовать другую функцию, которая обернет мою __init__
функцию следующим образом:
def mvgc_wrapper(lll, keys, vals):
if len(keys) != len(vals):
raise ValueError("keys and vals must have the same length.")
return MyVeryGenericClass(*lll, **dict(zip(keys, vals)))
Вопрос в том, должна ли моя функция-обертка быть методом моего класса или нет, и по какой причине и если это так, то как?
- С одной стороны, за исключением специальных методов, таких как
__new__
и __init__
, экземпляр класса уже должен существовать, что не соответствует действительности.
- С другой стороны, было бы более логично, чтобы моя обертка была частью моего класса, чтобы сделать ее монолитной.
- Или же, если бы я мог определить его так же, как
__new__
, с параметром cls вместо self. Я попытался написать так, но это не сработало.
Код:
#!/usr/bin/python3
# coding: UTF-8
import traceback
class MyVeryGenericClass:
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
def __repr__(self):
return repr(self.args)+repr(self.kwargs)
def wrapper(cls, lll, keys, vals):
if len(keys) != len(vals):
raise ValueError("keys and vals must have the same length.")
return MyVeryGenericClass(*lll, **dict(zip(keys, vals)))
def wrapper2(cls, lll, keys, vals):
if len(keys) != len(vals):
raise ValueError("keys and vals must have the same length.")
return cls(*lll, **dict(zip(keys, vals)))
def wrapper3(cls, lll, keys, vals):
if len(keys) != len(vals):
raise ValueError("keys and vals must have the same length.")
return cls.MyVeryGenericClass(*lll, **dict(zip(keys, vals)))
genlist = [1, 2, 3]
genkeys = ["spam", "eggs"]
genvals = ["foo", "bar"]
try:
cmd="instance1 = MyVeryGenericClass(genlist, genkeys, genvals)"
print(">", cmd)
exec(cmd)
print("instance1 = {}".format(repr(instance1)))
except TypeError: traceback.print_exc()
print()
try:
cmd="instance2 = instance1.wrapper(genlist, genkeys, genvals)"
print(">", cmd)
exec(cmd)
print("instance2 = {}".format(repr(instance2)))
except TypeError: traceback.print_exc()
print()
try:
cmd="failed_instance = MyVeryGenericClass.wrapper(genlist, genkeys, genvals)"
print(">", cmd)
exec(cmd)
print("failed_instance = {}".format(repr(failed_instance)))
except TypeError: traceback.print_exc()
print()
try:
cmd="failed_instance = MyVeryGenericClass.wrapper2(genlist, genkeys, genvals)"
print(">", cmd)
exec(cmd)
print("failed_instance = {}".format(repr(failed_instance)))
except TypeError: traceback.print_exc()
print()
try:
cmd="failed_instance = MyVeryGenericClass.wrapper3(genlist, genkeys, genvals)"
print(">", cmd)
exec(cmd)
print("failed_instance = {}".format(repr(failed_instance)))
except TypeError: traceback.print_exc()
Производит:
RESTART: /media/raid/ArcFolder/Mes documents/Mes Textes/Mes programmes/python/init_wrapper.py
> instance1 = MyVeryGenericClass(genlist, genkeys, genvals)
instance1 = ([1, 2, 3], ['spam', 'eggs'], ['foo', 'bar']){}
> instance2 = instance1.wrapper(genlist, genkeys, genvals)
instance2 = (1, 2, 3){'eggs': 'bar', 'spam': 'foo'}
> failed_instance = MyVeryGenericClass.wrapper(genlist, genkeys, genvals)
Traceback (most recent call last):
File "/media/raid/ArcFolder/Mes documents/Mes Textes/Mes programmes/python/init_wrapper.py", line 51, in <module>
exec(cmd)
File "<string>", line 1, in <module>
TypeError: wrapper() missing 1 required positional argument: 'vals'
> failed_instance = MyVeryGenericClass.wrapper2(genlist, genkeys, genvals)
Traceback (most recent call last):
File "/media/raid/ArcFolder/Mes documents/Mes Textes/Mes programmes/python/init_wrapper.py", line 58, in <module>
exec(cmd)
File "<string>", line 1, in <module>
TypeError: wrapper2() missing 1 required positional argument: 'vals'
> failed_instance = MyVeryGenericClass.wrapper3(genlist, genkeys, genvals)
Traceback (most recent call last):
File "/media/raid/ArcFolder/Mes documents/Mes Textes/Mes programmes/python/init_wrapper.py", line 65, in <module>
exec(cmd)
File "<string>", line 1, in <module>
TypeError: wrapper3() missing 1 required positional argument: 'vals'
Редактировать:
Благодаря @kindall, есть решение, добавив #classmethod
над альтернативным конструктором. Но теперь проблема в следующем: как мне отличить альтернативный конструктор от альтернативного инициализатора?