V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
3085570450tt
V2EX  ›  Python

请教,关于 Python 库的接口设计

  •  1
     
  •   3085570450tt · 3 天前 · 1179 次点击

    背景

    网上划水时遇到了使用 Go 编写的另一个 Redis, 名为 DiceDB 。当时发现该数据库除了 go sdk 之外,并没有提供其他语言的,于是自己参考 reids-py 等库,发布了第一个版本dicedb 。这个版本很多功能是缺失的,比如 Connection Pool, 异步等。该数据库是使用 Protocol Buffers 作为数据序列化协议的,昨天突然注意到所编写的 pb 进行了变更,于是为了与最新版本保持一致,也更新了相关的代码

    具体问题

    DiceDB 对于请求命令的数据定义如下:

    message Command {
        string cmd = 1; // 具体的命令,比如 GET, SET...
        repeated string args = 2; // 命令参数
    }
    

    args 字段定义为 string, 所以在执行命令(或发送命令请求)时需将参数转化为字符串。

    GET 查询命令的返回的数据定义

    message GETRes {
        string value = 1;
    }
    

    返回的数据字段 value 为 string 类型,那么我从 tcp 读取字节流,转换成 GETRes 类型的数据时,value 会被转换成 python 中的 str 数据类型 。

    而我的提供的 get 操作代码实列如下:

    from dicedb import Dice
    
    dice = Dice('localhost', 7379)
    dice.set('k', 43)
    dice.decr('k')
    
    k = dice.get('k')
    ...
    

    对于 set,decr 暂时不关注其返回的数据

    在上面代码最后一行中, k 的结果会是字符串数字 '43', 但上面用户直接提供了字符串数字 43

    所以,我需要在库内部完成类型的转换还是丢给用户去处理这种情况?

    在 discord 中也发帖询问这种情况,还在等回复。

    5 条回复    2025-04-21 22:18:11 +08:00
    huangyezhufeng
        1
    huangyezhufeng  
       3 天前   ❤️ 1
    两者都不可取,建议和 redis-py 对齐: https://redis.io/docs/latest/develop/clients/redis-py/
    >All responses are returned as bytes in Python. To receive decoded strings, set decode_responses=True.

    也就是说把选择空间留给用户。
    w568w
        2
    w568w  
       3 天前   ❤️ 1
    粗略看了一下文档,感觉不是 Python 的问题,而像是 DiceDB 的问题。

    DiceDB 本身就不严格限制类型,看起来更像是「所有对象统一作为 string 存取。但如果 string 能被解析成整数,也支持数值操作」,甚至它的 GET 命令也是 returns the value as a string 。

    那你这里的设计和上游保持一致就行了,def get(key: str) -> Optional[str]。如果真需要转型,可以加一个命名参数:

    def get(key: str, auto_convert_type: bool = False) -> Optional[Union[str, int]]
    3085570450tt
        3
    3085570450tt  
    OP
       3 天前
    @huangyezhufeng 谢谢;在编写这个库时,看了 redis-py 的部分源码,不过你提到的这一点 `decode_responses=True` 真没注意到,我按照你提供的这个思路,再进行处理吧。
    sazima
        4
    sazima  
       3 天前   ❤️ 1
    T = TypeVar('T', bound=Any, default=str)

    def get(key, t: Optional[Type[T]] = str) -> T:
    ...
    3085570450tt
        5
    3085570450tt  
    OP
       3 天前
    @w568w 个人感觉 DiceDB 的 protobuf 定义的的不是很合理,如何能提前知道数据类型(对于 GETRes 等),那么我应该不用去考虑该不该从字符串转换成数字等情况。考虑到,有些响应自带具体的类型,那我就默认情况下,不进行类型转换,只给可能需要额外处理的命令,添加 auto_convert_type 命名参数。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4485 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 03:57 · PVG 11:57 · LAX 20:57 · JFK 23:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.