考虑以下示例:
class Company():
def hireEmployee():
def fireEmployee():
def promoteEmployee():
etc...
class EngineeringFirm(Company):
pass
class PaintingFirm(Company):
pass
假设 Company 类有很多方法。如果我想从父类(super class)中重命名这些方法怎么办,以便获得以下内容:
class EngineeringFirm(Company):
def hireEngineer():
...
class PaintingFirm(Company):
def hirePainter():
...
……等等。虽然在这种情况下使用“Employee”确实不会有什么坏处,但这实际上只是为了说明这个想法。我该怎么办?
我的想法是使用一个 classFactory 函数,它将员工的类型作为参数并生成一个 Company 类,而元类将通过遍历属性字典并将“Employee”替换为所述类型来处理重命名。
class EngineeringFirm(companyFactory('Engineer'))
...
唯一的问题是:如果 Company 内部的方法通过默认的“Employee”名称相互调用怎么办?这就是我难过的地方。我的想法是重命名方法所涉及的元类也可以获取每个函数的源代码(通过检查模块)并搜索是否在其中找到已知的方法属性,如果是,则替换该部分并通过创建一个新函数exec 并将其分配回正确的属性键。
...但这看起来确实有点老套。我对替代方案持开放态度,尽管我意识到这个问题可能存在与设计相关的问题(我也对这方面的建议持开放态度)我很想知道这个问题是否有更优雅的解决方案。
谢谢!
编辑:另一个解决方案
为了论证,我暂时假设上面的代码确实是我正在使用的代码;我想我可以用我想到的另一种解决方案来解决评论中的一些问题,我已经考虑过并搁置了这个解决方案,原因我将解释。
如果 Firm
类继承自 Company 并且我希望维护相同的接口(interface)(在这种情况下通常会允许动态调用 hire()
或 promote()
等)我可以实现一个 __getattribute__
来接受 HirePainter()
(通过访问原始的 Employee 方法),同时仍然允许任何必要时使用 HireEmployee()
的其他接口(interface)。
我想知道,假设可以扩展我的问题,这是否会被认为是不好的做法,比如说,我计划这样做是因为我认为 PaintingFirm
中的代码会受益在可读性?再一次,我意识到这个例子很糟糕,因为这里的可读性似乎并没有以任何方式受益,但假设它有好处呢?
(我一开始没有提出这个想法的唯一原因是我的 __getattribute__
已经处理了很多,并且向它添加额外的噪音并没有那么吸引人。不过,我可以解决这个问题,但这是我不得不问的一个问题,以防万一那里有更多神奇(但不是 hacky)的解决方案..)
最佳答案
为了后代,我发布了一个我自己的解决方案,我认为它是一个不错的选择。我不建议将此作为答案,因为事实是我没有在我的问题中提到我更喜欢不添加额外的名称,或者保留将这些属性称为 self.hireEngineer
而不是ClassDict['HireEngineer']
。鉴于此,我真的不能说这些答案中的任何一个都没有回答问题。
解决方案:
事后看来,问题比我想象的要简单得多。我想我只是为了它而迷上了元分类。如果它还不是很明显,我真的只是在学习元类,有那么一刻这似乎是一个尝试它们的好机会。唉。
我相信以下解决方案尊重 Liskov 原则的精神(谢谢 Ignacio),同时赋予派生类以自己的方式引用派生方法的能力。类命名空间保持不变,其他对象可以在必要时使用它们的真实名称调用这些方法。
# superclass...
def __getattribute__(self, attr):
# Early exit (AttributeError) if attribute not found.
obj = object.__getattribute__(self, attr)
# All the extra code...
def __getattr__(self, attr):
# Ex. self.type == 'Engineer'
# Replacing titled-cased and lower-cased
# versions just to be safe (ex. self.employeeNames)
attr = (attr
.replace(self.type, 'Employee')
.replace(self.type.lower(), 'employee')
)
if attr in self.attributes:
return self.__getattribute__(attr)
else:
raise AttributeError
下次在概述要求时,我会尽量做得更好。谢谢,伙计们。
关于Python:重命名父类(super class)的方法及其函数范围引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27729681/