的Python:重命名一个父类的方法和他们的功能范围引用
请看下面的例子:的Python:重命名一个父类的方法和他们的功能范围引用
class Company():
def hireEmployee():
def fireEmployee():
def promoteEmployee():
etc...
class EngineeringFirm(Company):
pass
class PaintingFirm(Company):
pass
假设公司类有很多方法。如果我想从超类中重命名这些方法,那么我可以得到以下内容:
class EngineeringFirm(Company):
def hireEngineer():
...
class PaintingFirm(Company):
def hirePainter():
...
...等等。在这种情况下使用“员工”确实不会有什么伤害,但这只是为了说明这个想法。我会怎么做呢?
我的想法是使用一个classFactory函数,该函数将雇员的类型作为参数并生成一个Company类,而元类将通过遍历属性字典并用所述类型替换'Employee'来处理重命名。
class EngineeringFirm(companyFactory('Engineer'))
...
唯一的问题是:如果公司内部的方法通过默认的'员工'名称互相打电话怎么办?这是我难倒的地方。我有一个想法,即涉及重命名方法的元类也可以获取每个函数的源代码(通过检查模块),并搜索是否在内部找到已知的方法属性,如果是,则替换该部分并通过通过创建新函数exec并将其分配回正确的属性键。
...但这真的看起来有点哈克。我愿意接受替代品,尽管我意识到这个问题可能存在与设计相关的问题(我也愿意接受有关该方面的建议),但我很想知道这个问题是否具有更优雅的解决方案。
谢谢!
编辑:另一种解决方案
为了讨论的方便,我假设了一下,上面的代码是真的是我的工作;我想我可以用我想到的另一个解决方案来解决评论中的一些问题,其中一个我已经考虑过,并且因为我将解释的原因而放弃。
如果Firm
类从公司继承和我希望保持一个相同的接口(如一个通常会在这样的情况下,以允许动态调用hire()
或promote()
等)我可以实现一个__getattribute__
接受HirePainter()
(由访问最初的Employee方法),同时仍然允许任何其他接口在必要时使用HireEmployee()
。
我想知道,假如可以延长我的问题,如果我认为PaintingFirm
中的代码会使可读性受益,那么这会被认为是不好的做法。再一次,我意识到这个例子很可怕,因为这里的可读性似乎并没有任何好处,但假设它是这样做的?
(我首先没有提出这个想法的唯一原因是我的__getattribute__
已经处理了很多,并且增加了额外的噪音并没有那么吸引人,但我仍然可以使用它,但这是一个问题,如果有更多神奇的(但不是哈希)解决方案,我不得不提问。)
您可以尝试在每个类的字典中添加。
class EngineeringFirm(Company):
ClassDict = {'HireEngineer':self.HireEmployee,
...
};
每当你想调用的函数,你会使用
<EngineeringFirmInstanc>.ClassDict['HireEngineer'](<arguments>)
这不是特别优雅,但它可能让你接近你所要求的。
谢谢!我有另一种解决方案,在某种程度上接近于此,但这是更好的,不污染像我的名字空间。在我决定回答之前,我会等一会儿,但我很高兴你投入。 – Eithos
我倾向于同意关于这个问题的评论:我怀疑你所要求的会给代码增加不必要的复杂性,使其更难以阅读&仅仅为了实现可疑利益的小“整容”特征。
不过,如果你真的要做到这一点,也许你可以创建出同义词现有的方法方法,这样你就可以调用的方法,其原有的名称或用“定制”的名字,当似乎是合适的
这是一个相当直接的方法来做到这一点。我想有一些时髦的方式来与类装饰器,但我不知道如何使用这些。 :)
#! /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
为后人的缘故,我张贴我自己的解决方案,我相信这是一个不错的选择。我不建议将其作为答案,因为事实是,我没有在我的问题中提到,我更喜欢不添加额外名称,或者保留将这些属性称为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
我会在下次概述要求时尝试做得更好。多谢你们。
[EEEEEEEEEEWWWWWWWWWWWWWWW](http://en.wikipedia.org/wiki/Liskov_substitution_principle) –
@Eithos问题是,您的公司应该有一个类似的界面(如果不是相同的话),以便您可以告诉任何公司对象聘请一个人,让它决定雇用谁。所以你可以在不知道“公司”究竟是什么的情况下做firm.hire()。 – glglgl
@glglgl有趣。这让我感到很无聊,因为在大多数其他情况下,这可能是我处理它的方式。非常有意义。我意识到这个问题很复杂,因为我没有真正发布我的真实代码,并且如果有任何其他类可以/应该有权访问'firm.hire()',很少有机会。换句话说,虽然使用“firm.hire”可以促进动态调用,而不必事先了解公司情况,但这种动态处理确实不是必要的。事实上,这些调用是由UI Events激活的...... – Eithos