一日一技:跟着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大的代码中学到非常多的东西。

目录
相关文章
|
2月前
|
数据可视化 Java
让星星月亮告诉你,通过反射创建类的实例对象,并通过Unsafe theUnsafe来修改实例对象的私有的String类型的成员属性的值
本文介绍了如何使用 Unsafe 类通过反射机制修改对象的私有属性值。主要包括: 1. 获取 Unsafe 的 theUnsafe 属性:通过反射获取 Unsafe类的私有静态属性theUnsafe,并放开其访问权限,以便后续操作 2. 利用反射创建 User 类的实例对象:通过反射创建User类的实例对象,并定义预期值 3. 利用反射获取实例对象的name属性并修改:通过反射获取 User类实例对象的私有属性name,使用 Unsafe`的compareAndSwapObject方法直接在内存地址上修改属性值 核心代码展示了详细的步骤和逻辑,确保了对私有属性的修改不受 JVM 访问权限的限制
56 4
|
6月前
|
Java
java反射-属性赋值取值
java反射-属性赋值取值
|
Java 程序员 PHP
C++的对象与类的含义
C++是一门面向对象的编程语言,理解C++需要掌握类(class)和对象(object)这两个概念。 C++ 中的类(Class)可以看做C语言中结构体(Struct)的升级版。结构体是一种构造类型,可以包含若干成员变量,每个成员变量的类型可以不同;可以通过结构体来定义结构体变量,每个变量拥有相同的性质。例如: #include <stdio.h> //定义结构体 Student struct Student{ //结构体包含的成员变量 char *name; int age; float score; }; //显示结构体的成员变量 void displ
|
Python
Python面向对象、类的抽象、类的定义、类名遵循大驼峰的命名规范创建对象、类外部添加和获取对象属性、类内部操作属性魔法方法__init__()__str__()__del__()__repr__()
面向对象和面向过程,是两种编程思想. 编程思想是指对待同一个问题,解决问题的套路方式.面向过程: 注重的过程,实现的细节.亲力亲为.面向对象: 关注的是结果, 偷懒.类和对象,是面向对象中非常重要的两个概念object 是所有的类基类,即最初始的类class 类名(object): 类中的代码PEP8代码规范:类定义的前后,需要两个空行 创建的对象地址值都不一样如dog和dog1的地址就不一样,dog的地址为2378043254528dog1的地址为2378044849840 8.类内部操作属性 sel
260 1
Python面向对象、类的抽象、类的定义、类名遵循大驼峰的命名规范创建对象、类外部添加和获取对象属性、类内部操作属性魔法方法__init__()__str__()__del__()__repr__()
|
算法 Java 编译器
如何理解对象赋值给接口的操作(关键在对象!)
如何理解对象赋值给接口的操作(关键在对象!)
如何理解对象赋值给接口的操作(关键在对象!)
|
开发者 Python
类属性和对象属性|学习笔记
快速学习类属性和对象属性
类属性和对象属性|学习笔记
第五周学习java 继承 在子类父类中有相同参数,子类继承分类后如何进行调用,判断创建的对象属性哪个类
第五周学习java 继承 在子类父类中有相同参数,子类继承分类后如何进行调用,判断创建的对象属性哪个类
第五周学习java 继承 在子类父类中有相同参数,子类继承分类后如何进行调用,判断创建的对象属性哪个类
|
存储 Kotlin
【Kotlin】属性 与 幕后字段 ( 属性声明 | 属性初始化器 | 属性访问器 | field 属性幕后字段 | lateinit 延迟初始化属性 )
【Kotlin】属性 与 幕后字段 ( 属性声明 | 属性初始化器 | 属性访问器 | field 属性幕后字段 | lateinit 延迟初始化属性 )
223 0
【Kotlin】属性 与 幕后字段 ( 属性声明 | 属性初始化器 | 属性访问器 | field 属性幕后字段 | lateinit 延迟初始化属性 )
|
Java
使用java反射机制读取任意类内部细节
使用java反射机制读取任意类内部细节
133 0
|
JavaScript 前端开发
证明函数是对象的特殊子类型和函数的对象属性
证明函数是对象的特殊子类型和函数的对象属性