Python - 覆盖父类属性而不实例化

如何在不使用任一类的对象实例的情况下覆盖子类中的父类属性?来自 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. 这样我就可以url = urljoin(host, path)在类中一劳永逸地使用base(并且避免必须在每个派生类中复制/粘贴相同的属性/计算)。


我无法弄清楚如何在不构造对象的情况下完成此任务(我希望避免)。有人有什么建议吗?提前致谢!


不负相思意
浏览 83回答 1
1回答

守着一只汪

子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是动态的。您还只需要一种print_url方法,base而不是每个类中使用不同的方法。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您可以在类的类(元类)中定义 a ,它的行为与任何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"
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python