考虑以下示例:
class Company():
def hireEmployee():
def fireEmployee():
def promoteEmployee():
etc...
class EngineeringFirm(Company):
pass
class PaintingFirm(Company):
pass
假设Company类有更多方法。如果我想从超类重命名这些方法,那么我可以得到以下内容:
class EngineeringFirm(Company):
def hireEngineer():
...
class PaintingFirm(Company):
def hirePainter():
...
......等等。虽然在这种情况下使用“员工”确实不会有点伤害,但这只是为了说明这个想法。我该怎么办呢?
我的想法是使用classFactory函数,该函数将employee类型作为参数并生成Company类,而元类将通过迭代属性字典并用所述类型替换“Employee”来处理重命名。 p>
class EngineeringFirm(companyFactory('Engineer'))
...
唯一的问题是:如果公司内部的方法通过默认的“员工”名称相互调用怎么办?这是我难倒的地方。我认为重命名方法所涉及的元类也可以获取每个函数的源(通过检查模块)并搜索是否在其中找到已知方法属性,如果是,则替换该部分并通过以下方法创建新函数exec并将其分配回正确的属性键。
......但这真的看起来有点像黑客。我对替代方案持开放态度,虽然我意识到问题上可能存在与设计相关的问题(我也对这方面的建议持开放态度),但我很想知道这个问题是否有更优雅的解决方案。
谢谢!
编辑:其他解决方案
为了争论,我暂时假设上面的代码就是我正在使用的代码;我想我可以用我想到的另一个解决方案来解决评论中的一些问题,我已经考虑过这个问题,并且由于我将要解释的原因而放弃。
如果Firm
类继承自公司并且我希望保持相同的界面(通常在这种情况下允许动态调用hire()
或promote()
等等我可以实现一个__getattribute__
接受HirePainter()
(通过访问原始的Employee方法),同时仍然允许任何其他接口在必要时使用HireEmployee()
。
我想知道,假设我可以延长我的问题,如果这样做会被认为是不好的做法,如果我打算这样做,因为我认为PaintingFirm
中的代码会在可读性方面受益吗?再一次,我意识到这个例子很可怕,因为这里的可读性似乎并没有以任何方式受益,但是假设它确实如此?
(我首先没有提出这个想法的唯一原因是我的__getattribute__
已经处理了很多,并且添加了额外的噪音并没有让人觉得有吸引力。但是,我还能工作它在,但这是一个我不得不问的问题,以防有更多神奇的(但不是hacky)解决方案..)
答案 0 :(得分:1)
为了后人的缘故,我发布了自己的解决方案,我相信这是一个不错的选择。我不建议将其作为答案,因为事实是我在我的问题中没有提到我不希望添加额外的名称,或者保留将这些属性称为self.hireEngineer
而不是ClassDict['HireEngineer']
的能力。 。鉴于此,我不能说这些答案中的任何一个都没有回答这个问题。
<强>解决方案:强>
事后看来,问题比我做的要简单得多。我想我只是为了它而迷上了metaclassery。如果它还不是很明显,我真的只是在学习元类,一时间看起来似乎是一个尝试它们的好机会。唉。
我相信以下解决方案尊重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
下次概述要求时,我会尽力做得更好。谢谢,伙计们。
答案 1 :(得分:0)
您可以尝试为每个班级添加字典。
class EngineeringFirm(Company):
ClassDict = {'HireEngineer':self.HireEmployee,
...
};
每当你想要调用该函数时,你都会使用
<EngineeringFirmInstanc>.ClassDict['HireEngineer'](<arguments>)
它并不是特别优雅,但它可能会让你接近你所要求的。
答案 2 :(得分:0)
我倾向于同意对这个问题的评论:我怀疑你提出的问题会给代码增加不必要的复杂性,使得阅读更加难以理解。只是为了实施一个未成年人的化妆品&#34;可疑的好处。
但是,如果您真的想要这样做,也许您可以创建现有方法的同义词的方法,这样您就可以使用其原始名称调用方法或者使用&#34;定制的&#34;在合适的时候命名。
这是一种相当直接的方式。我想有一些方法可以用类装饰器来做,但我不知道如何使用它们。 :)
#! /usr/bin/env python
''' Class synonym demo
From http://stackoverflow.com/q/27729681/4014959
Written by PM 2Ring 2015.01.01
'''
class Foo(object):
def __init__(self, data):
self.foo_set(data)
def foo_set(self, data):
self.data = data
def foo_add(self, n):
self.data += n
return self.data
def foo_mul(self, n):
self.data *= n
return self.data
def foo_mul_add(self, n, m):
self.foo_mul(n)
return self.foo_add(m)
def make_synonyms(cls, old, new):
class newclass(cls):
pass
d = cls.__dict__
for k in d:
if k.startswith(old):
newname = k.replace(old, new)
#print k, d[k], newname
setattr(newclass, newname, d[k])
return newclass
#--------------------------------------
Bar = make_synonyms(Foo, 'foo', 'bar')
a = Foo(5)
print a.data
print a.foo_add(10)
print a.foo_mul(4)
print a.foo_mul_add(2, 1)
print '-' * 20
a = Bar(6)
print a.data
print a.foo_add(10)
print a.foo_mul(4)
print a.foo_mul_add(2, 1)
print '-' * 20
a.bar_set(5)
print a.data
print a.bar_add(10)
print a.bar_mul(4)
print a.bar_mul_add(2, 1)
<强>输出强>
5
15
60
121
--------------------
6
16
64
129
--------------------
5
15
60
121