[英]Python - Override parent class attribute without instantiation
如何在不使用任一类的对象实例的情况下覆盖子类中的父类属性? 来自 Java/C++ 世界及其严格的结构设计,我发现自己受到 Python 做事方式的挑战。 我想保持相对静止。
例子:
from urllib.parse import urljoin
class base:
host = "/host/"
path = "Override this in child classes"
url = urljoin(host, path)
class config(base):
path = "config"
@classmethod
def print_url(cls):
print(cls.url) # Currently prints "/host/Override this in child classes"
# Would like to print "/host/config" instead
class log(base):
path = "log"
@classmethod
def print_url(cls):
print(cls.url) # Currently prints "/host/Override this in child classes"
# Would like to print "/host/log" instead
预期用途:
>>> config.print_url()
/host/config
>>> log.print_url()
/host/log
我希望config.path
和log.path
属性覆盖base.path
。 这样我就可以在base
类中一劳永逸地使用url = urljoin(host, path)
(并避免在每个派生类中复制/粘贴相同的属性/计算)。
我无法弄清楚如何在不构造对象的情况下完成此操作(我希望避免这种情况)。 有人有什么建议吗? 提前致谢!
子path
属性会覆盖base.path
。 您没有覆盖的是url
属性。 当运行base
的主体以创建类对象时,它会被计算一次。
您有几个选择。 无论哪种方式,您都需要动态计算url
,无论是每次访问它时,还是每个子类至少一次。
最简单的方法是将url
变成classmethod
:
class base:
host = "/host/"
path = "Override this in child classes"
@classmethod
def url(cls):
return urljoin(cls.host, cls.path)
@classmethod
def print_url(cls):
print(cls.url())
class config(base):
path = "config"
class log(base):
path = "log"
请注意,您现在指的是实际类的host
和path
。 您还只需要在base
一个print_url
方法,而不是在每个类中使用一个不同的方法。
另一种选择是为base
及其所有子类提供一个以url
作为property
的元类:
class url_meta(type):
@property
def url(cls):
return urljoin(cls.host, cls.path)
class base(metaclass=url_meta):
host = "/host/"
path = "Override this in child classes"
@classmethod
def print_url(cls):
print(cls.url)
class config(base):
path = "config"
class log(base):
path = "log"
这是有效的,因为 python 类也是对象。 您可以在类的类(元类)中定义一个property
,它的行为就像任何property
对实例所做的一样。 只是这次实例本身是一个类。
第三个选项是确保url
在每个孩子中都是静态但正确定义的。 __init_subclass__
方法允许您直接从base
非常方便地执行此操作:
class base:
host = "/host/"
path = "Override this in child classes"
url = urljoin(host, path)
@classmethod
def __init_subclass__(cls):
cls.url = urljoin(cls.host, cls.path)
@classmethod
def print_url(cls):
print(cls.url)
class config(base):
path = "config"
class log(base):
path = "log"
你也可以用元类完成同样的事情:
class url_meta2(type):
def __init__(cls, *args, **kwargs):
cls.url = urljoin(cls.host, cls.path)
class base(metaclass=url_meta2):
host = "/host/"
path = "Override this in child classes"
@classmethod
def print_url(cls):
print(cls.url)
class config(base):
path = "config"
class log(base):
path = "log"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.