Python-重写父类属性而不实例化

Python-重写父类属性而不实例化,python,oop,inheritance,overriding,subclass,Python,Oop,Inheritance,Overriding,Subclass,如何在不使用任何一个类的对象实例的情况下覆盖子类中的父类属性?来自Java/C++及其严格的结构设计的世界,我发现自己受到Python处理方式的挑战。我想保持相对静止 示例: from urllib.parse import urljoin class base: host = "/host/" path = "Override this in child classes" url = urljoin(host, path) c

如何在不使用任何一个类的对象实例的情况下覆盖子类中的父类属性?来自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"
请注意,您现在正在动态地引用实际类的
主机
路径
。您还只需要在
base
中使用一个
print\u url
方法,而不是在每个类中使用不同的方法

另一个选项是为
base
及其所有子级提供一个元类,并将
url
作为
属性

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类也是对象。您可以在类(元类)的类中定义
属性
,它的行为与任何
属性
对实例的行为相同。这一次,实例本身就是一个类

第三个选项是确保在每个子项中静态但正确地定义
url
。该方法允许您非常方便地直接从
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"

Python类也是对象。“你可以这样对待他们。”Mad_物理学家非常感谢你给出的详细答案,这正是我想要的!!我不知道元类或init_子类的存在,我现在要将它们添加到我的工具带中!