使用基础 class 来创建所有对象
Using base class for all object creation
一位高级开发人员希望我在 Python 中实现面向对象编程,我们使用 Base class 实例化所有对象创建。它不太适合我,因为 Base class 中有抽象方法 Derived class 必须实现。他仅将 Base class 用作实例化对象的一种方式的推理是,当我们遍历对象列表时,我们可以以相同的方式访问其变量和方法。由于基础 class 的每个派生对象比基础 class 具有更多实例化的属性,他建议 init 函数将 *args 和 **kwargs 作为论据的一部分。
这样做是不是一个好方法?如果没有,你能帮忙推荐一个更好的选择吗?
这是一个简单的实施示例。
import abc
class Base(metaclass = abc.ABCMeta):
def __init__(self, reqarg1, reqarg2, **kwargs):
self.reqarg1 = reqarg1
self.reqarg2 = reqarg2
self.optarg1 = kwargs.get("argFromDerivedA", 0.123)
self.optarg2 = kwargs.get("argFromDerivedB", False)
self.dict = self.create_dict()
@abstractmethod
def create_dict(self):
pass
def get_subset_list(self, id):
return [item for item in self.dict.values() if item.id == id]
def __iter__(self):
for item in self.dict.values():
yield item
raise StopIteration()
class Derived_A(Base):
def __init__(self, regarg1, regarg2, optarg1):
super().__init__(regarg1, regarg2, optarg1)
def create_dict(self):
# some implementation
return dict
class Derived_B(Base):
def __init__(self, regarg1, regarg2, optarg2):
super().__init__(regarg1, regarg2, optarg2)
def create_dict(self):
# some implementation
return dict
编辑:为了说清楚,我不太清楚如何正确处理基础 class 中的抽象方法,因为高级开发人员希望按如下方式使用它:
def main():
b = Base(100, 200)
for i in get_subset_list(30):
print(i)
但是Base class中的dict没有定义,因为它是在派生的classes中定义的,因此会输出如下错误:
NameError: name 'abstractmethod' is not defined
您根本不必使用关键字参数;只需在函数的参数部分定义具有默认值的变量,并仅发送您想要从派生的 classes.
发送的参数
请注意,不必提供具有默认值的参数 - 这样您就可以拥有一个具有一定数量参数的函数(其中参数是唯一的,不能被视为列表)。
这是一个部分示例(取自您的代码):
import abc
class Base(metaclass = abc.ABCMeta):
def __init__(self, reqarg1, reqarg2, optarg1 = 0.123, optarg2 = False):
self.reqarg1, self.reqarg2 = reqarg1, reqarg2
self.optarg1, self.optarg2 = optarg1, optarg2
...
class Derived_A(Base):
def __init__(self, regarg1, regarg2, optarg1):
super().__init__(regarg1, regarg2, optarg1=optarg1)
...
class Derived_B(Base):
def __init__(self, regarg1, regarg2, optarg2):
super().__init__(regarg1, regarg2, optarg2=optarg2)
...
编辑:随着问题的更新,我会给出一个小提示 - 抽象方法用于确保一些派生的 Base
对象的混合列表可以调用相同的方法。 Base
对象本身 不能 调用此方法 - 它是基础 class 的抽象,并且就在那里,因此我们可以确保每个派生实例都必须实现这个方法。
我的建议是在 Base
class 中使用工厂 class 方法。您只需要能够根据提供的输入确定您需要 return 的 Derived
class。我将复制一个实现,假设您提供关键字 optarg1
时需要 Derived_A
,如果提供关键字 optarg2
则需要 Derived_B
。当然,这完全是人为的,您应该根据自己的需要进行更改。
import abc
class Base(metaclass = abc.ABCMeta):
@classmethod
def factory(cls,reqarg1,reqarg2,**kwargs):
if 'optarg1' in kwargs.keys():
return Derived_A(reqarg1=reqarg1,reqarg2=reqarg2,optarg1=kwargs['optarg1'])
elif 'optarg2' in kwargs.keys():
return Derived_B(reqarg1=reqarg1,reqarg2=reqarg2,optarg2=kwargs['optarg2'])
else:
raise ValueError('Could not determine Derived class from input')
def __init__(self, reqarg1, reqarg2, optarg1=0.123, optarg2=False):
self.reqarg1 = reqarg1
self.reqarg2 = reqarg2
self.optarg1 = optarg1
self.optarg2 = optarg2
self.dict = self.create_dict()
@abc.abstractmethod
def create_dict(self):
pass
def get_subset_list(self, id):
return [item for item in self.dict.values() if item.id == id]
def __iter__(self):
for item in self.dict.values():
yield item
class Derived_A(Base):
def __init__(self, reqarg1, reqarg2, optarg1):
super().__init__(reqarg1, reqarg2, optarg1=optarg1)
def create_dict(self):
# some implementation
dict = {'instanceOf':'Derived_A'}
return dict
class Derived_B(Base):
def __init__(self, reqarg1, reqarg2, optarg2):
super().__init__(reqarg1, reqarg2, optarg2=optarg2)
def create_dict(self):
# some implementation
dict = {'instanceOf':'Derived_B'}
return dict
这将允许您始终创建一个 Derived_X
class 实例,当您 __init__
它时,该实例将定义 create_dict
非抽象方法。
In [2]: b = Base.factory(100, 200)
ValueError: Could not determine Derived class from input
In [3]: b = Base.factory(100, 200, optarg1=1213.12)
In [4]: print(b.dict)
{'instanceOf': 'Derived_A'}
In [5]: b = Base.factory(100, 200, optarg2=True)
In [6]: print(b.dict)
{'instanceOf': 'Derived_B'}
此外,您可以拥有多个工厂方法。查看 here 获取简短教程。
一位高级开发人员希望我在 Python 中实现面向对象编程,我们使用 Base class 实例化所有对象创建。它不太适合我,因为 Base class 中有抽象方法 Derived class 必须实现。他仅将 Base class 用作实例化对象的一种方式的推理是,当我们遍历对象列表时,我们可以以相同的方式访问其变量和方法。由于基础 class 的每个派生对象比基础 class 具有更多实例化的属性,他建议 init 函数将 *args 和 **kwargs 作为论据的一部分。
这样做是不是一个好方法?如果没有,你能帮忙推荐一个更好的选择吗?
这是一个简单的实施示例。
import abc
class Base(metaclass = abc.ABCMeta):
def __init__(self, reqarg1, reqarg2, **kwargs):
self.reqarg1 = reqarg1
self.reqarg2 = reqarg2
self.optarg1 = kwargs.get("argFromDerivedA", 0.123)
self.optarg2 = kwargs.get("argFromDerivedB", False)
self.dict = self.create_dict()
@abstractmethod
def create_dict(self):
pass
def get_subset_list(self, id):
return [item for item in self.dict.values() if item.id == id]
def __iter__(self):
for item in self.dict.values():
yield item
raise StopIteration()
class Derived_A(Base):
def __init__(self, regarg1, regarg2, optarg1):
super().__init__(regarg1, regarg2, optarg1)
def create_dict(self):
# some implementation
return dict
class Derived_B(Base):
def __init__(self, regarg1, regarg2, optarg2):
super().__init__(regarg1, regarg2, optarg2)
def create_dict(self):
# some implementation
return dict
编辑:为了说清楚,我不太清楚如何正确处理基础 class 中的抽象方法,因为高级开发人员希望按如下方式使用它:
def main():
b = Base(100, 200)
for i in get_subset_list(30):
print(i)
但是Base class中的dict没有定义,因为它是在派生的classes中定义的,因此会输出如下错误:
NameError: name 'abstractmethod' is not defined
您根本不必使用关键字参数;只需在函数的参数部分定义具有默认值的变量,并仅发送您想要从派生的 classes.
发送的参数请注意,不必提供具有默认值的参数 - 这样您就可以拥有一个具有一定数量参数的函数(其中参数是唯一的,不能被视为列表)。
这是一个部分示例(取自您的代码):
import abc
class Base(metaclass = abc.ABCMeta):
def __init__(self, reqarg1, reqarg2, optarg1 = 0.123, optarg2 = False):
self.reqarg1, self.reqarg2 = reqarg1, reqarg2
self.optarg1, self.optarg2 = optarg1, optarg2
...
class Derived_A(Base):
def __init__(self, regarg1, regarg2, optarg1):
super().__init__(regarg1, regarg2, optarg1=optarg1)
...
class Derived_B(Base):
def __init__(self, regarg1, regarg2, optarg2):
super().__init__(regarg1, regarg2, optarg2=optarg2)
...
编辑:随着问题的更新,我会给出一个小提示 - 抽象方法用于确保一些派生的 Base
对象的混合列表可以调用相同的方法。 Base
对象本身 不能 调用此方法 - 它是基础 class 的抽象,并且就在那里,因此我们可以确保每个派生实例都必须实现这个方法。
我的建议是在 Base
class 中使用工厂 class 方法。您只需要能够根据提供的输入确定您需要 return 的 Derived
class。我将复制一个实现,假设您提供关键字 optarg1
时需要 Derived_A
,如果提供关键字 optarg2
则需要 Derived_B
。当然,这完全是人为的,您应该根据自己的需要进行更改。
import abc
class Base(metaclass = abc.ABCMeta):
@classmethod
def factory(cls,reqarg1,reqarg2,**kwargs):
if 'optarg1' in kwargs.keys():
return Derived_A(reqarg1=reqarg1,reqarg2=reqarg2,optarg1=kwargs['optarg1'])
elif 'optarg2' in kwargs.keys():
return Derived_B(reqarg1=reqarg1,reqarg2=reqarg2,optarg2=kwargs['optarg2'])
else:
raise ValueError('Could not determine Derived class from input')
def __init__(self, reqarg1, reqarg2, optarg1=0.123, optarg2=False):
self.reqarg1 = reqarg1
self.reqarg2 = reqarg2
self.optarg1 = optarg1
self.optarg2 = optarg2
self.dict = self.create_dict()
@abc.abstractmethod
def create_dict(self):
pass
def get_subset_list(self, id):
return [item for item in self.dict.values() if item.id == id]
def __iter__(self):
for item in self.dict.values():
yield item
class Derived_A(Base):
def __init__(self, reqarg1, reqarg2, optarg1):
super().__init__(reqarg1, reqarg2, optarg1=optarg1)
def create_dict(self):
# some implementation
dict = {'instanceOf':'Derived_A'}
return dict
class Derived_B(Base):
def __init__(self, reqarg1, reqarg2, optarg2):
super().__init__(reqarg1, reqarg2, optarg2=optarg2)
def create_dict(self):
# some implementation
dict = {'instanceOf':'Derived_B'}
return dict
这将允许您始终创建一个 Derived_X
class 实例,当您 __init__
它时,该实例将定义 create_dict
非抽象方法。
In [2]: b = Base.factory(100, 200)
ValueError: Could not determine Derived class from input
In [3]: b = Base.factory(100, 200, optarg1=1213.12)
In [4]: print(b.dict)
{'instanceOf': 'Derived_A'}
In [5]: b = Base.factory(100, 200, optarg2=True)
In [6]: print(b.dict)
{'instanceOf': 'Derived_B'}
此外,您可以拥有多个工厂方法。查看 here 获取简短教程。