Python - 在不实例化的情况下覆盖父 class 属性
Python - Override parent class attribute without instantiation
如何在不使用 class 的对象实例的情况下覆盖子 class 中的父 class 属性? 来自 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
class 中一劳永逸地使用 url = urljoin(host, path)
(并避免在每个派生 [=] 中都必须 copy/paste 相同的 attribute/calculation 41=]).
如果不构造对象(我希望避免),我无法弄清楚如何完成此操作。有人有什么建议吗?提前致谢!
child path
属性会覆盖 base.path
。您不覆盖的是 url
属性。当 base
的主体是 运行 创建 class object.
时计算一次
你有几个选择。无论哪种方式,您都需要使 url
动态计算,每次访问时,或者每个 child class.
至少一次
最简单的方法就是把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"
请注意,您现在指的是实际的 classe 的 host
和 path
。您还只需要 base
中的一个 print_url
方法,而不是每个 class.
中的一个不同的方法
另一种选择是给 base
,因此它的所有 children,元 class 与 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 class 也是 object。您可以在 class 的 class 中定义 property
(metaclass),它的行为与任何 property
对实例的行为相同.只是这一次实例本身就是一个class。
第三个选项是确保 url
在每个 child 中静态但正确地定义。 __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"
您也可以使用 metaclass 完成同样的事情:
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"
如何在不使用 class 的对象实例的情况下覆盖子 class 中的父 class 属性? 来自 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
class 中一劳永逸地使用 url = urljoin(host, path)
(并避免在每个派生 [=] 中都必须 copy/paste 相同的 attribute/calculation 41=]).
如果不构造对象(我希望避免),我无法弄清楚如何完成此操作。有人有什么建议吗?提前致谢!
child path
属性会覆盖 base.path
。您不覆盖的是 url
属性。当 base
的主体是 运行 创建 class object.
你有几个选择。无论哪种方式,您都需要使 url
动态计算,每次访问时,或者每个 child class.
最简单的方法就是把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"
请注意,您现在指的是实际的 classe 的 host
和 path
。您还只需要 base
中的一个 print_url
方法,而不是每个 class.
另一种选择是给 base
,因此它的所有 children,元 class 与 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 class 也是 object。您可以在 class 的 class 中定义 property
(metaclass),它的行为与任何 property
对实例的行为相同.只是这一次实例本身就是一个class。
第三个选项是确保 url
在每个 child 中静态但正确地定义。 __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"
您也可以使用 metaclass 完成同样的事情:
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"