我想扩展更多的类集以接受其他关键字参数。所有的类集合共享一个我不能更改的公共接口。
我已经这样尝试过了:
class Base:
def __init__(self, a=0, b=1, c=2):
self.a = a
self.b = b
self.c = c
def extended_base ( Kls ):
additional_fields = [ 'a', 'b' ]
def my_init( self, *args, **kwargs ):
for field in additional_fields:
try:
setattr(self, '{}2'.format(field), kwargs.pop(field))
except KeyError:
setattr(self, '{}2'.format(field), None)
# Does not work as I expect
# super().__init__(*args, **kwargs)
# Does not work as expected
super(Kls, self).__init__(*args, **kwargs)
# I would like to define a function that returns a function that does
# what the following functions do, automatically but for every value
# in `additional_fields`
def get_a2( self ):
return self.a2 or self.a
def get_b2( self ):
return self.b2 or self.b
return type( 'My{}'.format(Kls.__name__), (Kls, ), {
'__init__' : my_init,
'get_a2' : get_a2,
'get_b2' : get_b2,
})
test = extended_base(Base)(a=3, a2=9)
test.a
test.a2
test.get_a2()
test.get_b2()
如您所见,我只想扩展基类的某些属性,并且我希望能够通过简单地指定应在函数additional_fields
中扩展的属性来做到这一点。
我有两个问题:我不知道如何调用双亲__init__
方法,上面显示的两种方法都给出错误第二个是,我不知道如何定义一个匿名函数(?)例如,如果我将c
添加到c
列表中,将对属性additional_fields
进行同样的操作。
答案 0 :(得分:0)
一种方法是为其使用元类:
class LibraryBase:
# imagine it is placed it third-party library
def __init__(self, a=0, b=1, c=2):
self.a = a
self.b = b
self.c = c
class Meta(type):
def __new__(cls, name, bases, attrs):
for name in attrs['additional_fields']:
name2 = '{}2'.format(name)
get_name2 = 'get_{}'.format(name2)
def getter_name2(name2, name):
def _get_name2(self):
return getattr(self, name2, None) or getattr(self, name)
return _get_name2
attrs[get_name2] = getter_name2(name2, name)
return type.__new__(cls, name, bases, attrs)
class Base(LibraryBase, metaclass=Meta):
# we still can inherit from library class with our metaclass
additional_fields = []
def __init__(self, a=0, b=1, c=2, **kwargs):
self.a = a
self.b = b
self.c = c
for key, value in kwargs.items():
setattr(self, key, value)
for name in self.additional_fields:
name2 = '{}2'.format(name)
setattr(self, name2, kwargs.get(name2))
class ExtendBase(Base):
additional_fields = ['a', 'b']
class ExtendBase2(Base):
additional_fields = ['a', 'b', 'c']
test = ExtendBase(a=3, a2=9)
print(test.a) # 3
print(test.a2) # 9
print(test.get_a2()) # 9
print(test.b) # 1
print(test.b2) # None
print(test.get_b2()) # 1
print(test.c) # 2
print(test.c2) # AttributeError
print(test.get_c2()) # AttributeError