专栏首页未闻Code一日一技:跟着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大的代码中学到非常多的东西。

在本公众号回复:records 就可以获得这个项目的Github地址。

本文分享自微信公众号 - 未闻Code(itskingname),作者:kingname

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-07-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 我为什么要创建一个不能被实例化的类

    Python 由于多继承的原因,可能会出现钻石继承[1]又叫菱形继承。为了保留多继承的优点,但又摒除缺点,于是有了混入这种编程模式。

    青南
  • 一日一技:为什么年代久远的 Python 项目里面那么多默认参数?

    在写 Python 代码的时候,大家可能会在不知不觉中使用一些设计范式。我们来看两个例子。

    青南
  • 一日一技:在Python类里面初始化自己

    这里的 __init__叫做 构造函数。它负责在类初始化为实例的时候,初始化必要的数据。如下图所示:

    青南
  • 自定义异常并抛出,捕获

    skylark
  • 我为什么要创建一个不能被实例化的类

    Python 由于多继承的原因,可能会出现钻石继承[1]又叫菱形继承。为了保留多继承的优点,但又摒除缺点,于是有了混入这种编程模式。

    青南
  • 【多目标跟踪】搞不懂MOT数据集,会跑代码有啥用!

    数据集用的最多的是 MOTChallenge,专注于行人追踪的。https://motchallenge.net/

    机器视觉CV
  • Django实现验证码

    Django实现验证码 背景知识 1. 验证码的作用 防恶意破解密码:防止,使用程序或机器人恶意去试密码.为了提高用户的体验,用户输入错误以后,才会要求输入验证...

    若与
  • Python 魔法方法连载五 实现算术运算

    我们知道,当变量类型为数字类型如整数,浮点型的时候,我们可以对变量算术运算,但当变量类型是自定义的类时,还可不可以进行算术运算呢?答案是肯定的,但必须通过实现特...

    cctester
  • 数据结构学习-python实现-优先队列--0417

    到不了的都叫做远方
  • iOS自动布局——Masonry详解

    UI布局是整个前端体系里不可或缺的一环。代码的布局是设计语言与用户视觉感受沟通的桥梁,不论它看起来多么简单或是琐碎,但不得不承认,绝大部分软件开发的问题,都是界...

    鹅厂新鲜事儿

扫码关注云+社区

领取腾讯云代金券