【问题标题】:Can I create an alias to an inherited method in Python?我可以在 Python 中为继承的方法创建别名吗?
【发布时间】:2017-03-30 02:21:03
【问题描述】:

我的 Python 程序中有一个非常复杂的类层次结构。该程序有许多工具,要么是模拟器,要么是编译器。两种共享一些方法,所以有一个Shared 类作为所有类的基类。一个精简的示例如下所示:

class Shared:
  __TOOL__ = None

  def _Prepare(self):
    print("Preparing {0}".format(self.__TOOL__))


class Compiler(Shared):
  def _Prepare(self):
    print("do stuff 1")
    super()._Prepare()
    print("do stuff 2")

  def _PrepareCompiler(self):
    print("do stuff 3")
    self._Prepare()
    print("do stuff 4")


class Simulator(Shared):
  def _PrepareSimulator(self):   # <=== how to create an alias here?
    self._Prepare()           


class Tool1(Simulator):
  __TOOL__ = "Tool1"

  def __init__(self):
    self._PrepareSimulator()

  def _PrepareSimulator(self):
    print("do stuff a")
    super()._PrepareSimulator()
    print("do stuff b")

我可以将方法Simulator._PrepareSimulator 定义为Simulator/Shared._Prepare 的别名吗?

我知道我可以创建本地别名,例如:__str__ = __repr__,但在我的情况下,_Prepare 在上下文中是未知的。我没有self 也没有cls 来引用这个方法。

我可以写一个装饰器来返回_Prepare而不是_PrepareSimulator吗?但是如何在装饰器中找到_Prepare

我也需要调整方法绑定吗?

【问题讨论】:

  • 您可以将_PrepareSimulation 定义为Shared._Prepare 的别名,因此:_PrepareSimulation = Shared._Prepare。但我完全不确定你为什么要这样做。你到底想达到什么目的?
  • 你有 _PrepareSimulation_PrepareSimulator - 是不同的还是错字?
  • typo :) 更高级别的类可以覆盖方法,从而在需要时插入它们的逻辑。大多数类使用基类的功能
  • 你不需要一个基类来获取一些常用的方法,Python 有 Duck Typing。

标签: python python-3.x methods alias python-decorators


【解决方案1】:

我设法创建了一个基于装饰器的解决方案,以确保类型安全。第一个装饰器将别名注释为本地方法。需要保护别名目标。需要第二个装饰器来替换 Alias 实例并检查别名是否指向类型层次结构中的方法。

装饰器/别名定义:

from inspect import getmro

class Alias:
  def __init__(self, method):
    self.method = method

  def __call__(self, func):
    return self

def HasAliases(cls):
  def _inspect(memberName, target):
    for base in getmro(cls):
      if target.__name__ in base.__dict__:
        if (target is base.__dict__[target.__name__]):
          setattr(cls, memberName, target)
          return
      else:
        raise NameError("Alias references a method '{0}', which is not part of the class hierarchy: {1}.".format(
          target.__name__, " -> ".join([base.__name__ for base in getmro(cls)])
        ))

  for memberName, alias in cls.__dict__.items():
    if isinstance(alias, Alias):
      _inspect(memberName, alias.method)

  return cls

用法示例:

class Shared:
  __TOOL__ = None

  def _Prepare(self):
    print("Preparing {0}".format(self.__TOOL__))


class Shared2:
  __TOOL__ = None

  def _Prepare(self):
    print("Preparing {0}".format(self.__TOOL__))


class Compiler(Shared):
  def _Prepare(self):
    print("do stuff 1")
    super()._Prepare()
    print("do stuff 2")

  def _PrepareCompiler(self):
    print("do stuff 3")
    self._Prepare()
    print("do stuff 4")


@HasAliases
class Simulator(Shared):
  @Alias(Shared._Prepare)
  def _PrepareSimulatorForLinux(self):    pass

  @Alias(Shared._Prepare)
  def _PrepareSimulatorForWindows(self):  pass


class Tool1(Simulator):
  __TOOL__ = "Tool1"

  def __init__(self):
    self._PrepareSimulator()

  def _PrepareSimulator(self):
    print("do stuff a")
    super()._PrepareSimulatorForLinux()
    print("do stuff b")
    super()._PrepareSimulatorForWindows()
    print("do stuff c")

t = Tool1()

@Alias(Shared._Prepare) 设置为@Alias(Shared2._Prepare) 将引发异常:

NameError: Alias 引用了一个方法“_Prepare”,它不是类层次结构的一部分:模拟器 -> 共享 -> 对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-11
    • 1970-01-01
    • 2023-03-28
    • 2012-01-27
    • 2022-09-27
    相关资源
    最近更新 更多