在 Python 对象上调用 "forward" 方法最简洁的方法是什么?
What's the most concise way to "forward" method calls on a Python object?
我正在编写一些报告生成代码,其中 class CoverageReporter
完成了所有繁重的工作,只有少数属性在 CoverageReporter
的不同实例之间发生变化。假设我们想要别名
SubsystemCoverageReporter(*args, **kwargs)
至
CoverageReporter('subsystem', *args, **kwargs)
以简洁的方式。目前,我是这样完成的:
class SubsystemCoverageReporter(object):
def __init__(self, *args, **kwargs):
self.reporter = CoverageReporter('subsystem', *args, **kwargs)
def __getattr__(self, name):
return getattr(self.reporter, name)
另一个子系统 2 具有几乎完全 相同的样板,例如:
class SubsystemTwoCoverageReporter(object):
def __init__(self, *args, **kwargs):
self.reporter = CoverageReporter('subsystem2', *args, **kwargs)
def __getattr__(self, name):
return getattr(self.reporter, name)
有没有更简洁+Python化的表达方式?我宁愿不依赖继承,但如果没有更好的方法,我愿意接受。
假设您的 class CoverageReporter
是这样的:
class CoverageReporter:
def __init__(self, _type, _name):
self.type = _type
self.name = _name
def do_something(self):
print(f"{self.type}:{self.name} did something")
def do_something_else(self):
print(f"{self.type}:{self.name} did something else")
您可以定义一个函数来创建 CoverageReporter
和 returns 该对象。
def SubsystemCoverageReporter(*args, **kwargs):
return CoverageReporter('subsystem', *args, **kwargs)
def SubsystemTwoCoverageReporter(*args, **kwargs):
return CoverageReporter('subsystem2', *args, **kwargs)
s1 = SubsystemCoverageReporter("Foo")
s2 = SubsystemTwoCoverageReporter("Bar")
s1.do_something() # subsystem:Foo did something
s2.do_something_else() # subsystem2:Bar did something else
请注意,这并不完全等同于您所拥有的,因为 SubsystemCoverageReporter
不是 class,所以您不会能够继承它。如果您希望该选项可用,那么我认为继承是您拥有的最佳解决方案。
class SubsystemCoverageReporter(CoverageReporter):
def __init__(self, *args, **kwargs):
super().__init__('subsystem', *args, **kwargs)
class SubsystemTwoCoverageReporter(CoverageReporter):
def __init__(self, *args, **kwargs):
super().__init__('subsystem2', *args, **kwargs)
s1 = SubsystemCoverageReporter("Foo")
s2 = SubsystemTwoCoverageReporter("Bar")
s1.do_something() # subsystem:Foo did something
s2.do_something_else() # subsystem2:Bar did something else
如果您想避免重复自己,请使用您总是会使用的相同解决方案,将重复的代码包装在一个函数中并参数化可以更改的部分:
def make_klass(subsystem):
class SubsystemCoverageReporter(object):
def __init__(self, *args, **kwargs):
self.reporter = CoverageReporter(subsystem, *args, **kwargs)
def __getattr__(self, name):
return getattr(self.reporter, name)
return SubsystemCoverageReporter
SubsystemCoverageReporter = make_klass("subsystem")
SubsystemTwoCoverageReporter = make_klass("subsystem2")
请注意,您创建的 类 将具有相同的 __name__
属性值。那是希望不重要,但你可以绕过它,例如:
SubsystemCoverageReporter.name = "SubsystemCoverageReporter"
SubsystemTwoCoverageReporter.name = "SubsystemTwoCoverageReporter"
虽然那很丑。
您可以直接使用 type
构造函数,或者如果 meta类 是一个问题,请改用 types.new_class
并且它会正确处理它。但在最简单的情况下,
def make_klass(name, subsystem):
def __init__(self, *args, **kwargs):
self.reporter = CoverageReporter(subsystem, *args, **kwargs)
def __getattr__(self, name):
return getattr(self.reporter, name)
klass = type(name, (object,), dict(__init__=__init__, __getattr__=__getattr__))
return klass
SubsystemCoverageReporter = make_klass("SubsystemCoverageReporter", "subsystem")
SubsystemTwoCoverageReporter = make_klass("SubsystemTwoCoverageReporter", "subsytem2")
请注意,您在这里重复了一点。
但是,通常你不应该关心 __name__
属性
我正在编写一些报告生成代码,其中 class CoverageReporter
完成了所有繁重的工作,只有少数属性在 CoverageReporter
的不同实例之间发生变化。假设我们想要别名
SubsystemCoverageReporter(*args, **kwargs)
至
CoverageReporter('subsystem', *args, **kwargs)
以简洁的方式。目前,我是这样完成的:
class SubsystemCoverageReporter(object):
def __init__(self, *args, **kwargs):
self.reporter = CoverageReporter('subsystem', *args, **kwargs)
def __getattr__(self, name):
return getattr(self.reporter, name)
另一个子系统 2 具有几乎完全 相同的样板,例如:
class SubsystemTwoCoverageReporter(object):
def __init__(self, *args, **kwargs):
self.reporter = CoverageReporter('subsystem2', *args, **kwargs)
def __getattr__(self, name):
return getattr(self.reporter, name)
有没有更简洁+Python化的表达方式?我宁愿不依赖继承,但如果没有更好的方法,我愿意接受。
假设您的 class CoverageReporter
是这样的:
class CoverageReporter:
def __init__(self, _type, _name):
self.type = _type
self.name = _name
def do_something(self):
print(f"{self.type}:{self.name} did something")
def do_something_else(self):
print(f"{self.type}:{self.name} did something else")
您可以定义一个函数来创建 CoverageReporter
和 returns 该对象。
def SubsystemCoverageReporter(*args, **kwargs):
return CoverageReporter('subsystem', *args, **kwargs)
def SubsystemTwoCoverageReporter(*args, **kwargs):
return CoverageReporter('subsystem2', *args, **kwargs)
s1 = SubsystemCoverageReporter("Foo")
s2 = SubsystemTwoCoverageReporter("Bar")
s1.do_something() # subsystem:Foo did something
s2.do_something_else() # subsystem2:Bar did something else
请注意,这并不完全等同于您所拥有的,因为 SubsystemCoverageReporter
不是 class,所以您不会能够继承它。如果您希望该选项可用,那么我认为继承是您拥有的最佳解决方案。
class SubsystemCoverageReporter(CoverageReporter):
def __init__(self, *args, **kwargs):
super().__init__('subsystem', *args, **kwargs)
class SubsystemTwoCoverageReporter(CoverageReporter):
def __init__(self, *args, **kwargs):
super().__init__('subsystem2', *args, **kwargs)
s1 = SubsystemCoverageReporter("Foo")
s2 = SubsystemTwoCoverageReporter("Bar")
s1.do_something() # subsystem:Foo did something
s2.do_something_else() # subsystem2:Bar did something else
如果您想避免重复自己,请使用您总是会使用的相同解决方案,将重复的代码包装在一个函数中并参数化可以更改的部分:
def make_klass(subsystem):
class SubsystemCoverageReporter(object):
def __init__(self, *args, **kwargs):
self.reporter = CoverageReporter(subsystem, *args, **kwargs)
def __getattr__(self, name):
return getattr(self.reporter, name)
return SubsystemCoverageReporter
SubsystemCoverageReporter = make_klass("subsystem")
SubsystemTwoCoverageReporter = make_klass("subsystem2")
请注意,您创建的 类 将具有相同的 __name__
属性值。那是希望不重要,但你可以绕过它,例如:
SubsystemCoverageReporter.name = "SubsystemCoverageReporter" SubsystemTwoCoverageReporter.name = "SubsystemTwoCoverageReporter"
虽然那很丑。
您可以直接使用 type
构造函数,或者如果 meta类 是一个问题,请改用 types.new_class
并且它会正确处理它。但在最简单的情况下,
def make_klass(name, subsystem):
def __init__(self, *args, **kwargs):
self.reporter = CoverageReporter(subsystem, *args, **kwargs)
def __getattr__(self, name):
return getattr(self.reporter, name)
klass = type(name, (object,), dict(__init__=__init__, __getattr__=__getattr__))
return klass
SubsystemCoverageReporter = make_klass("SubsystemCoverageReporter", "subsystem")
SubsystemTwoCoverageReporter = make_klass("SubsystemTwoCoverageReporter", "subsytem2")
请注意,您在这里重复了一点。
但是,通常你不应该关心 __name__
属性