一日一技:跟着Kenneth Reitz大神学习读取类属性的三种方法

简介: 一日一技:跟着Kenneth Reitz大神学习读取类属性的三种方法

在看Kenneth Reitz大神的Records项目时,注意到在Readme中,读取数据有三种写法:

Values can be accessed many ways: row.user_email, row['user_email'], or row[3]

假设一个数据表如下所示:

username active name user_email timezone
model-t True Henry Ford model-t@gmail.com 2016-02-06 22:28:23.894202

那么,如果你想读取user_email的值,除了可以使用 row.user_emailrow['user_email']以外,由于 user_email在第3列(username是第0列),所以还可以使用 row[3]来读取。

今天我们就来研究一下,他是如何实现这个功能的。

假设我们现在有一个类:

class People:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def walk(self):
        print('i am walk')

基于这个类初始化一个对象kingname:

kingname = People('kingname', 26)
print(kingname.age)

运行效果如下图所示:

可以看到,我们已经实现了类似于records项目中的 row.user_email的写法。

但是当我们想像字典一样取读取的时候,就会报错,如下图所示。

此时,为了让一个对象可以像字典一样被读取,我们需要实现它的 __getitem__方法:

class People:
    def __init__(self, name, age):
        self.info = {'name': name,
                     'age': age}
    def walk(self):
        print('i am walk')
    def __getitem__(self, key):
        return self.info.get(key, '不存在')

此时就可以像字典一样去读取了,运行效果如下图所示:

但新的问题又来了,不能直接使用 kinganme.age读取数据了,这样写会导致报错,如下图所示:

为了解决这个问题,我们再来实现这个类的 __getattr__方法:

class People:
    def __init__(self, name, age):
        self.info = {'name': name,
                     'age': age}
    def walk(self):
        print('i am walk')
    def __getitem__(self, key):
        return self.info.get(key, '不存在')
    def __getattr__(self, key):
        return self.info.get(key, '不存在')

运行效果如下图所示:

那么如何实现records里面的 row[3]这种写法呢?

这就需要先解释一下,records这个库是用来做什么的,以及它的数据是如何存放的。

K大写的records,是用于来更加方便地读写SQL数据库,避免繁琐地写各种SQL语句。

我们今天要研究的这个写法,在 Record这个类里面。这个类用来保存MySQL中的一行数据。Record这个类包含两个属性,分别为 _keys_values,其中 _keys用于记录所有的字段名, _values用于记录一行的所有值。字段名和值是按顺序一一对应的。

例如 _keys里面下标为3表示字段名 user_email,那么 _values里面下标为3的数据就是 user_email的值。

正是由于这样一个一一对应的关系,所以 row[3]才能实现 row['user_email']row.user_email相同的效果。

回到我们的People类,为了实现相同的目的,我们再次修改代码:

class People:
    def __init__(self, name, age):
        self._keys = ['name', 'age']
        self._values = [name, age]
    def walk(self):
        print('i am walk')
    def __getitem__(self, key):
        if isinstance(key, int):
            if 0 <= key < len(self._keys):
                return self._values[key]
            return '索引超出边界'
        index = self._keys.index(key)
        if index == -1:
            return 'Key不存在'
        return self._values[index]
    def __getattr__(self, key):
        return self.__getitem__(key)

运行效果如下图所示:

需要说明的是,无论是使用 kingname['key']还是 kingname[1],他们都会进入到 __getitem__方法中去。

我这里给出的例子相较于 records项目的代码做了简化,不过关键的部分都已经囊括了进来。

最后,推荐有兴趣的同学通读records这个项目的源代码,这个项目只有一个文件,包括注释和空行才500多行代码,但你将会从K大的代码中学到非常多的东西。

目录
相关文章
|
6月前
|
存储 弹性计算 数据管理
阿里云对象存储OSS收费标准:500G存储118元1年、
阿里云对象存储OSS 2025年收费标准涵盖存储、流量及请求等费用,支持按量付费与包年包月两种模式。标准型存储按量价格为0.09元/GB/月,包年包月如9元享40GB体验价。流量费仅收取公网出方向,忙时0.50元/GB,闲时0.25元/GB。此外提供多种存储类型(低频、归档等)及流量包优惠方案,未使用功能不收费。详情见阿里云OSS官网。
5778 6
|
SQL 存储 Go
【译】SQLAlchemy文档:SQLAlchemy 统一教程
【译】SQLAlchemy文档:SQLAlchemy 统一教程
359 1
|
JavaScript
tailwindcss使用教程
【8月更文挑战第1天】
478 3
|
数据采集 数据可视化 安全
2023年最有用的数据清洗 Python 库
2023年最有用的数据清洗 Python 库
236 1
2023年最有用的数据清洗 Python 库
|
JSON JavaScript 前端开发
Danfo.js专题 - 附:Dnotebook(Danfo Notebook)单机资源与汉化文档
Danfo.js专题 - 附:Dnotebook(Danfo Notebook)单机资源与汉化文档
240 0
|
5天前
|
弹性计算 人工智能 安全
云上十五年——「弹性计算十五周年」系列客户故事(第二期)
阿里云弹性计算十五年深耕,以第九代ECS g9i实例引领算力革新。携手海尔三翼鸟、小鹏汽车、微帧科技等企业,实现性能跃升与成本优化,赋能AI、物联网、智能驾驶等前沿场景,共绘云端增长新图景。
|
11天前
|
存储 弹性计算 人工智能
【2025云栖精华内容】 打造持续领先,全球覆盖的澎湃算力底座——通用计算产品发布与行业实践专场回顾
2025年9月24日,阿里云弹性计算团队多位产品、技术专家及服务器团队技术专家共同在【2025云栖大会】现场带来了《通用计算产品发布与行业实践》的专场论坛,本论坛聚焦弹性计算多款通用算力产品发布。同时,ECS云服务器安全能力、资源售卖模式、计算AI助手等用户体验关键环节也宣布升级,让用云更简单、更智能。海尔三翼鸟云服务负责人刘建锋先生作为特邀嘉宾,莅临现场分享了关于阿里云ECS g9i推动AIoT平台的场景落地实践。
【2025云栖精华内容】 打造持续领先,全球覆盖的澎湃算力底座——通用计算产品发布与行业实践专场回顾
|
2天前
|
云安全 人工智能 安全
Dify平台集成阿里云AI安全护栏,构建AI Runtime安全防线
阿里云 AI 安全护栏加入Dify平台,打造可信赖的 AI
|
10天前
|
人工智能 自然语言处理 自动驾驶
关于举办首届全国大学生“启真问智”人工智能模型&智能体大赛决赛的通知
关于举办首届全国大学生“启真问智”人工智能模型&智能体大赛决赛的通知