我有以下情况:
我有抽象类A
和B
,而A
使用B
来执行某些任务。在这两个类中,有一些“常量”参数(现在作为类属性实现)由扩展那些抽象类的具体类设置,并且一些参数是共享的(它们在派生的“套件”中应该具有相同的值)课程SubA
和SubB
)。
我在这里面临的问题是如何在Python中组织命名空间。如果Python具有动态范围,那么理想的解决方案是将这些参数声明为模块变量,然后在创建新的扩展类套件时,我可以在新模块中覆盖它们。但是(幸运的是,因为大多数情况下更安全,更方便)Python不能像那样工作。
把它放在一个更具体的环境中(不是我的实际问题,当然不准确也不现实),想象一下像nbody模拟器这样的东西:
ATTRACTION_CONSTANT = NotImplemented # could be G or a Ke for example
class NbodyGroup(object):
def __init__(self):
self.bodies = []
def step(self):
for a in self.bodies:
for b in self.bodies:
f = ATTRACTION_CONSTANT * a.var * b.var / distance(a, b)**2
...
class Body(object):
def calculate_field_at_surface(self):
return ATTRACTION_CONSTANT * self.var / self.r**2
然后其他模块可以实现PlanetarySystem(NBodyGroup)
和Planet(Body)
设置ATTRACTION_CONSTANT
到6.67384E-11
,其他模块可以实现MolecularAggregate(NBodyGroup)
和Particle(Body)
并设置ATTRACTION_CONSTANT
至8.987E9
。
简而言之:在模块级别模拟全局常量的哪些好方法可以在派生模块中实现“覆盖”(实现第一个模块中定义的抽象类的模块)?
答案 0 :(得分:1)
以下是我可以提出的一些建议:
将每个主体链接到其组,以便主体在计算其力时从组中访问常量。例如:
class NbodyGroup(object):
def __init__(self, constant):
self.bodies = []
self.constant = constant
def step(self):
for a in self.bodies:
for b in self.bodies:
f = self.constant * a.var * b.var / distance(a, b)**2
...
class Body(object):
def __init__(self, group):
self.group = group
def calculate_field_at_surface(self):
return self.group.constant * self.var / self.r**2
Pro:这会自动强制执行同一组中的实体应施加相同类型的力量这一事实。骗局:从语义上讲,你可以争辩说一个团体应该独立于任何一个团体而存在。
添加参数以指定力的类型。例如,这可以是枚举的值。
class Force(object):
def __init__(self, constant):
self.constant = constant
GRAVITY = Force(6.67e-11)
ELECTRIC = Force(8.99e9)
class NbodyGroup(object):
def __init__(self, force):
self.bodies = []
self.force = force
def step(self):
for a in self.bodies:
for b in self.bodies:
f = self.force.constant * a.charge(self.force) \
* b.charge(self.force) / distance(a, b)**2
...
class Body(object):
def __init__(self, charges, r):
# charges = {GRAVITY: mass_value, ELECTRIC: electric_charge_value}
self.charges = charges
...
def charge(self, force):
return self.charges.get(force, 0)
def calculate_field_at_surface(self, force):
return force.constant * self.charge(force) / self.r**2
从概念上讲,我更喜欢这种方法,因为它封装了您通常与该对象中的给定对象(以及那些对象)关联的属性。但是,如果执行速度是一个重要目标,那么这可能不是最好的设计。
希望您可以将这些翻译成您的实际应用。
答案 1 :(得分:1)
使用mixin怎么样?您可以定义(基于您的示例)包含PlanetarySystemConstants
的{{1}}和MolecularAggregateConstants
的类,然后使用ATTRACTION_CONSTANT
和class PlanetarySystem(NBodyGroup, PlanetarySystemConstants)
来定义这些类。< / p>
答案 2 :(得分:1)
删除旧版本
您可以尝试子类化__new__
来创建元类。然后在类创建中,您可以通过使用python std的inspect
模块查看以前的帧来获取子类模块,如果找到一个,则在此处获取新常量,并修补派生类的class属性。 / p>
我暂时不会发布一个实现,因为它对我来说是微不足道的,而且有点危险。
修改:添加了实施
A.py
中的:
import inspect
MY_GLOBAL = 'base module'
class BASE(object):
def __new__(cls, *args, **kwargs):
clsObj = super(BASE, cls).__new__(cls, *args, **kwargs)
clsObj.CLS_GLOBAL = inspect.stack()[-1][0].f_globals['MY_GLOBAL']
return clsObj
B.py
中的:
import A
MY_GLOBAL = 'derived'
print A.BASE().CLS_GLOBAL
现在你可以享受自己的范围规则......
答案 3 :(得分:0)
在这种情况下你应该使用property,
例如
class NbodyGroup(object):
@property
def ATTRACTION_CONSTANT(self):
return None
...
def step(self):
for a in self.bodies:
for b in self.bodies:
f = self.ATTRACTION_CONSTANT * a.var * b.var / distance(a, b)**2
class PlanetarySystem(NBodyGroup):
@property
def ATTRACTION_CONSTANT(self):
return 6.67384E-11