python数据模型其实就是python中内置的对象模型,那些内置的对象模型我们在之前进行过说明。python中内置的对象模型具有一些特殊方法,也就是我们前面说的魔法函数。

简单来说,Python数据模型就是Python内置的数据类型及其包含的特殊方法(魔法函数)。举个例子来说,我们在使用len()这个函数时,会调用__len__这个魔法函数;使用list[]时会调用__getitem__魔法函数;使用各类运算符也会调用其相对应的魔法函数。从根本上来说,list[ ]、+、-、*、/、for i in x这些写法只是为了更简洁和更具有可读性,但内部跟其他操作是一样的,也是通过特定方法(算法)来实现的,这就是魔法函数。

我们来看下面的一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Company(object):
def __init__(self, employee_list):
self.employee = employee_list

def __getitem__(self, item):
return self.employee[item]


company = Company(["tom", "bob", "jane"])
company1 = company[:2]
print(company1)

# 输出结果:
['tom', 'bob']

我们上面并没有把company 这个对象转成列表,但是我们却依然可以对其进行切片处理,那是因为我们在前面说了:使用list[ ]时会调用__getitem__魔法函数,也就是说如果具有了__getitem__这个魔法函数,我们就可以把它当做一个list,然后就可以对它进行切片处理(这就是我们后面要讲的鸭子模型)。

现在我们尝试打印一下这个对象的长度:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Company(object):
def __init__(self, employee_list):
self.employee = employee_list

def __getitem__(self, item):
return self.employee[item]


company = Company(["tom", "bob", "jane"])

print(len(company))

# 结果输出: TypeError: object of type 'Company' has no len()

现在我们尝试修改一下最后一行的代码:

1
2
3
print(len(company.employee))

# 结果输出:3

为什么会这样,不是说只有实现了__len__这个魔法函数,对象才具有输出长度的功能么:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Company(object):
def __init__(self, employee_list):
self.employee = employee_list

def __getitem__(self, item):
return self.employee[item]

def __len__(self):
return len(self.employee)


company = Company(["tom", "bob", "jane"])

print(len(company))

# 结果输出:3

是的,的确是那样,但是你注意到没有,添加了__len__这个魔法函数之后这个类的实例化对象就直接具有了输出长度的功能。我们前面输出长度的功能不是这个类的实例化对象具有的,而是实例化对象的employee才具有的,因为Python解释器首先会去寻找__len__这个魔法函数,不存在就去寻找__getitem__,找到之后就可以输出实例化对象的employee的长度了。

还有一点,不知道你注意没有:

1
2
def __len__(self):
return len(self.employee)

在魔法函数__len__里面,我们还是使用了len()函数。前面说了我们print(len(company))调用的就是这个__len__魔法函数,考虑到这里有len(),怕你看不清楚,我们修改一下代码,看看是不是真的调用了__len__这个魔法函数,我们通过return的返回值来进行判断:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Company(object):
def __init__(self, employee_list):
self.employee = employee_list

def __getitem__(self, item):
return self.employee[item]

def __len__(self):
return self.employee


company = Company(["tom", "bob", "jane"])

print(len(company))

# 输出结果:
print(len(company))
TypeError: 'list' object cannot be interpreted as an integer

看到没有,上面返回的self.employee其实就是employee_list这个列表,从而验证和加深了我们的理解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Company(object):
def __init__(self, employee_list):
self.employee = employee_list

def __getitem__(self, item):
return self.employee[item]

def __len__(self):
return len(self.employee)


company = Company(["tom", "bob", "jane"])

print(len(company))

再来看一下这个,你就更加明白了这一点:

1
2
3
4
5
6
7
8
9
10
11
>>> a= 123
>>> len(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'int' has no len()



>>> a ="123"
>>> len(a)
3

通过查找源码,我发现str这个类里面包含了__len__这个魔法函数,而int类里面就没有,所以就不能调用len()方法:

1
2
3
def __len__(self, *args, **kwargs): # real signature unknown
""" Return len(self). """
pass

[ - ] 参考文章: python高级(一)—— python数据模型(特殊方法)