Python【折腾 Python】如何用 Python 写一个常量成员变量呢?

头像
路小鹿
123阅读4评论

背景

假如,我们需要写一个创建 User 的方法,很自然地,我们写了一个 UserService 类,把需要实现的方法放进去。就像这样:

class UserService:
    @classmethod
    def create(cls, username: str, email: str):
        pass

接下来实现创建逻辑就好啦。
可是烦人的产品同学又加了一个要求:用户名长度不能超过 20 个字符。
好吧,我们需要加上一个判断了。

if len(username) > 20:
    raise Exception(....)

我们对代码颜值有严格的要求,绝对不允许把 20 这样随便地放在代码中。我们会声明一个“常量”,并且在需要它的地方使用它。

USERNAME_MAX_LENGTH = 20

if len(username) > USERNAME_MAX_LENGTH:
    raise Exception(....)

最终代码写成了这样

class UserService:
    USERNAME_MAX_LENGTH: int = 20

    @classmethod
    def create(cls, username: str, email: str):
        if len(username) > cls.USERNAME_MAX_LENGTH:
            raise Exception(....)
        pass

啰嗦了那么久,现在才说到了正题:Python 并不像其他语言有 “const” 关键字,这里的 USERNAME_MAX_LENGTH 并不是真的常量呀。怎么样从代码实现的层面彻底避免其他地方不小心修改它呢?(比如手误写了一个 if USERNAME_MAX_LENGTH = 10: ,少写了一个等号)

实现

众所周知,在 Python 中一切皆对象。 UserService 表面上是个浓眉大眼的类,实质上也只个被元类 type 实例化的对象罢了。
作为一个对象,有人要改它的属性 USERNAME_MAX_LENGTH ,就得通过它的 __setattr__ 方法来改。直接从元类入手,禁掉 __setattr__ ,我们的变量就会安全了。

很容易我们就完成需要的元类了:

class Const(type):
    def __setattr__(cls, key, value):
        raise Exception(f"variable '{key}' declared const here")

接下来,让我们自定义的元类来生成 UserService :

class UserService(metaclass=Const):
    USERNAME_MAX_LENGTH: = 20

    @classmethod
    def create(cls, username: str, email: str):
        if len(username) > cls.USERNAME_MAX_LENGTH:
            raise Exception(....)
        pass

大功告成!

其他

在 Python 3.8 版本中,增加了 Final 类型标示,如果有写常量的需求,记得加上它。

相关资料:

[1] What are metaclasses in Python? - stackoverflow.com
[2] typing.Final - docs.python.org

最后修改于

顶 1
收藏
举报
加载中…
精选评论
USERNAME_MAX_LENGTH: = 20

是不是有误?

头像
等级2

Final 这个妙啊,真是妙

版块详情

Python

33 帖子
132 评论
50 关注
本版块专注 Python 相关的一切。 1. 发布招聘 Python 相关的远程岗位信息 2. 提出编写 Python 遭遇的问题 3. 分享使用 Python 得到的心得 4. 讨论最新 Python 版本的 Feature
版主
Python | Ruby
远程全职推荐

扫码下载应用

下载APP以便及时收到回复或进展