Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/359.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:重命名超类';s方法及其函数范围引用_Python_Inheritance_Methods_Metaclass_Renaming - Fatal编程技术网

Python:重命名超类';s方法及其函数范围引用

Python:重命名超类';s方法及其函数范围引用,python,inheritance,methods,metaclass,renaming,Python,Inheritance,Methods,Metaclass,Renaming,考虑以下示例: class Company(): def hireEmployee(): def fireEmployee(): def promoteEmployee(): etc... class EngineeringFirm(Company): pass class PaintingFirm(Company): pass 假设Company类有更多的方法。如果我想从超类重命名这些方法,那么我可以得到以下结果: class En

考虑以下示例:

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():
    ...
……等等。虽然在这个场景中使用“Employee”不会有任何伤害,但这只是为了说明这个想法。我该怎么做呢

我的想法是使用classFactory函数,该函数将employee的类型作为参数并生成一个Company类,而元类将通过迭代属性字典并用所述类型替换“employee”来处理重命名

class EngineeringFirm(companyFactory('Engineer'))
    ...
唯一的问题是:如果公司内部的方法以默认的“雇员”姓名相互调用,会怎么样?这就是我被难倒的地方。我的想法是,重命名方法所涉及的元类还可以获取每个函数的源(通过inspect模块),并搜索其中是否存在已知的方法属性,如果是,则替换该部分,并通过exec创建一个新函数,并将其分配回正确的属性键

…但这看起来真的有点老套。我对替代方案持开放态度,尽管我意识到这个问题可能存在与设计相关的问题(我也对这方面的建议持开放态度),但我有兴趣找出这个问题是否有更优雅的解决方案

谢谢

编辑:另一种解决方案

为了便于讨论,我假设上面的代码就是我正在使用的代码;我想我可以用另一个我想到的解决方案来解决评论中的一些问题,一个我已经考虑过的解决方案,我会解释原因

如果从公司继承的
公司
类和我希望维护一个相同的接口(在这种情况下通常允许动态调用
hire()
promote()
等),我可以实现一个接受
HirePainter()
getattribute
(通过访问原始的Employee方法),同时仍允许任何其他接口在必要时使用
HireEmployee()

# 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
我想知道,假设可以扩展我的问题,如果我计划这样做是因为我认为
PaintingFirm
中的代码在可读性方面会有好处,那么这是否会被认为是一种不好的做法?再次,我意识到这个例子很可怕,因为这里的可读性似乎在任何方面都没有好处是的,但假设是这样


(我最初没有提出这个想法的唯一原因是我的
\uuu getattribute\uuuu
已经处理了相当多的问题,并且添加额外的噪音并没有那么吸引人。尽管如此,我还是可以解决这个问题,但这是一个我不得不问的问题,以防有更神奇(但不是黑客)的解决方案。)

您可以尝试为每个类添加字典

class EngineeringFirm(Company):
  ClassDict = {'HireEngineer':self.HireEmployee,
               ...
               };
无论何时您想要调用您将使用的函数

<EngineeringFirmInstanc>.ClassDict['HireEngineer'](<arguments>)
.ClassDict['HireEngineer']()

它不是特别优雅,但它可能会让你更接近你所问的问题。

我倾向于同意关于这个问题的评论:我怀疑你所问的问题会给代码增加不必要的复杂性,使它更难阅读和维护,仅仅是为了实现一个微不足道的“装饰性”功能,其好处是可疑的

但是,如果您确实想这样做,也许可以创建与现有方法同义的方法,这样您就可以在适当的时候使用其原始名称或“自定义”名称调用方法

这里有一个相当直接的方法可以做到这一点。我想有一些巧妙的方法可以使用类装饰器,但我不知道如何使用它们。:)

输出

5
15
60
121
--------------------
6
16
64
129
--------------------
5
15
60
121

为了子孙后代,我发布了一个我自己的解决方案,我相信这是一个不错的选择。我不建议将此作为答案,因为事实上我在问题中没有提到我更喜欢不添加额外的名称,或者保留将这些属性称为
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

下次在概述需求时,我会努力做得更好。谢谢,伙计们。

@Eithos好吧,关键是,你们的公司应该有一个类似的界面,如果不是完全相同的话,这样你们就可以告诉任何公司的目标雇佣某人,并让它决定雇佣谁。所以你可以做
firm.hire()
而不知道
firm
到底是什么。@glglgl。这让我觉得很傻,因为在大多数其他情况下,这可能是我处理问题的方式。这很有道理。我意识到问题是复杂的,因为我没有真正发布我的真实代码,而且任何其他类访问
firm.hire()
的可能性很小(如果有的话)。换句话说,当使用
firm.hire
可以在事先不知道公司的情况下促进动态呼叫雇用时,这种动态处理实际上是不必要的。事实上,这些调用是由特定于一个类的UI事件激活的;因此,他们不会称不同类型的“雇佣者”,