为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

不负相思意 2023-09-12 16:52:14
如何在不使用任一类的对象实例的情况下覆盖子类中的父类属性?来自 Java/C++ 及其严格结构设计的世界,我发现自己受到 Python 做事方式的挑战。我想保持相对静止。例子:from urllib.parse import urljoinclass 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" insteadclass 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(并且避免必须在每个派生类中复制/粘贴相同的属性/计算)。我无法弄清楚如何在不构造对象的情况下完成此任务(我希望避免)。有人有什么建议吗?提前致谢!
查看完整描述

1 回答

?
守着一只汪

TA贡献1872条经验 获得超3个赞

子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"


查看完整回答
反对 回复 2023-09-12
  • 1 回答
  • 0 关注
  • 51 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信