如何在Python中使用点表示法组织分层字符串常量?

ozxc1zmp  于 12个月前  发布在  Python
关注(0)|答案(1)|浏览(80)

我正在编写一个Python客户端,它可以命中HTTP端点。端点具有树结构,其中几乎任何点都可以是端点。我希望能够命中该层次结构沿着的任何点,并让它根据定义的常量构建字符串。
例如,我希望将Endpoints.CONFIGURATION扩展为/configuration,并将Endpoints.CONFIGURATION.ACTIVE扩展为/configuration/active
我想通过编程的方式来实现,这样我就可以编写更少的代码。我还想避免将这些定义为最终用户必须调用的函数,所以可能有一些类是理想的,这些类都是通过覆盖__str__派生的。
我试着操纵Python的类系统来完成这样的事情。

class EndpointClass:
    class CONFIGURATION:
        ACTIVE = '/configuration/active'

字符串
但是,这缺少了我定义的功能,我需要.CONFIGURATION扩展到/configuration。我还必须手动编写/configuration,我希望它能根据定义它的类自动扩展。
我考虑过一个基于字典的解决方案,但据我所知,它不允许使用自动完成的点标记法,并且可能不会返回层次结构中任何级别的值。
我考虑过What is the best way to define a (maybe hierarchical) set of constants in python?,但它的层次结构没有我可能达到的那么深,它没有自动扩展功能,它不支持在层次结构的不同级别停止并仍然返回一些东西。

rwqw0loc

rwqw0loc1#

我想这可能是你正在寻找的?它是一个简单的父/子跟踪类,可以为子项启用点完成。当传递到str时,它还扩展了端点的祖先链。

from collections.abc import Iterable

class Endpoint:
    def __init__(self, name: str) -> None:
        self._name = name
        self._children = {}
        self._parent = None

    def __dir__(self) -> Iterable[str]:
        cls_attrs = object.__dir__(self)
        return [n for n in self._children] + cls_attrs
    
    def __repr__(self) -> str:
        return f'<Endpoint({self._name!r})>'
    
    def __str__(self) -> str:
        if self._parent:
            up = f'{str(self._parent)}/'
        else:
            up = ''
        return f'{up}{self._name.lower()}'
    
    def append_endpoint(self, endpoint_name: str):
        if any(c.lower()==endpoint_name for c in self._children):
            raise KeyError(f'A sub-endpoint {endpoint_name!r} already exists.')
        new_endpoint = self.__class__(endpoint_name)
        new_endpoint._parent = self
        self._children[endpoint_name] = new_endpoint

    def __getattr__(self, _attr: str):
        if _attr in self._children:
            return self._children[_attr]
        return object.__getattribute__(self, _attr)
    
    def __iadd__(self, endpoint_name: str):
        if not isinstance(endpoint_name, str):
            return NotImplemented
        self.append_endpoint(endpoint_name)
        return self

字符串
使用类看起来像:

config = Endpoint('CONFIGURATION')
config += 'ACTIVE'         # ACTIVE will appear in the dot completion
config.ACTIVE += 'LAST'
config += 'INACTIVE'
config.INACTIVE += 'HISTORY'
config.INACTIVE.HISTORY += 'Y2020'
config.INACTIVE.HISTORY += 'Y2021'
config.INACTIVE.HISTORY += 'Y2022'
config.INACTIVE.HISTORY += 'Y2023'

str(config.ACTIVE.LAST)
# returns: 'configuration/active/last'

相关问题