今天,谈谈python中的数据模型,当然你可以不了解这些东西,照样可以写出漂亮的python代码,但是“知其然知其所以然”是我的作风,总是不明白python的一些机制,心里很不爽。结合python的doc和一篇文章,差不多明白了python的哲理。

我觉得有必要将python中的文档的一些重要语句拿出来。

Objects are Python’s abstraction for data. All data in a Python program is represented by objects or by relations between objects.

Every object has an identity, a type and a value.

为什么我这里要强调这里的对象,有对象以为着有一些属性(函数也罢,变量也罢都是属性)与之关联,你操作一个对象,其实就是在和这些属性打交道。

在这里,我集中在python中的类,去弄明白python中的类究竟是怎么完成其功能的.

A class has a namespace implemented by a dictionary object. Class attribute references are translated to lookups in this dictionary.

这句话很重要,一个类有其自己的namespace(命名空间),而且这个命名空间的实现本质上是一个字典。换句话说,你对一个类的操作其实就是在对这个“特殊”的字典进行操作,那么怎么去区分类的实例和类呢,其实在python中,类的实例也有一个字典,去记录该实例的属性。

class T(object):

age = 21

t = T()

t.name = "ilovebaiyang"

print "dir(T):", dir(T)

print "dir(t):", dir(t)

这个打印的结果是:

dir(T): ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age']

dir(t): ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name']

其中有些属性是从object上继承来的,比如__doc__, __setattr__,__dict__等等,其中值得注意的是自定义属性,age和name,他们分别存在于类T中和类T的实例t中,那么为什么在dir(t)中出现了age的属性呢,原因是从它的类上复制过来的,而且如果我们打印他们的id,其实他们的id是一样的。在这里,我们出现了一个疑问,前面提到的命名空间的字典就是dir()函数产生的字典么,看上去貌似是,因为它的确记录了该对象的所有属性,其实这个是错误的,原因我们就要回到dir函数上了,它的作用是罗列出当前对象的所有属性,包括父类的。其实,前面提到的命名空间是的__dict__成员,所有与该对象对应的属性全部放在这个字典里。

我们打印出来看看

T.__dict__:  {'__dict__': , '__module__': '__main__', '__weakref__': , 'age': 21, '__doc__': None}

t.__dict__:  {'name': 'ilovebaiyang'}

这一下才会和我们想象的一样,name属性只存在实例中。

接下来是属性的查找:

如果我们要打印t.age,怎么搜索

1.先查找该实例的__dict__,如果有,返回,否则进行第二步

2.查找类的__dict__,如果有返回,没有的话,继续查找该类的父类,直到基类,如果还没有,抛出异常。

当然,其实python中的查找还做了很多其他事,特别是一些隐含的调用,如果我们重写这些隐含的调用,就可以写出符合我们的数据。

看下面的例子:

class T(object):

def __setattr__(self, name, value):

print "__setattr__ called "

object.__setattr__(self, name, value)

def __getattr__(self, name):

print "__getattr__ called "

def __getattribute__(self, name):

print "__getattribute__ called"

return object.__getattribute__(self, name)

t = T()

t.name = "baiyang"

print "t", t.name

t.baiyang

结果:

__setattr__ called

t __getattribute__ called

baiyang

__getattribute__ called

__getattr__ called

分析以上的结果,当t.name被执行时,先调用了__setattr__函数;当print “t”, t.name时,调用了__getattribute__函数;当t.baiyang时,调用了__getattr__函数,因为t没有baiyang这个属性,故调用这个函数。

其实简单的想一下,会明白,我们在操作namespace这个字典时,我们都会隐式的调用相应的函数,这些函数可以用来进行数据的验证。

总结一下,在操作类的实例的属性时,我们需要关注一下函数:

object.__setattr__(self, name, value)

object.__getattr__(self, name)

object.__delattr__(self, name)

object.__getattribute__(self, name)

其中你对任何对象的属性访问时,都会隐式的调用__getattribute__方法,比如你调用t.__dict__,其实你执行了t.__getattribute__(“__dict__”)函数。

神奇的python,把字典用的如此灵活,由此可以看出字典在python的地位是何其的重要。

在这里,我们或许想到了怎么不去隐式的调用这些函数,对,我们可以直接去操作类或者类实例的__dict__。看看下面的例子:

class T(object):

age = 21

def __setattr__(self, name, value):

print "__setattr__ called "

object.__setattr__(self, name, value)

def __getattr__(self, name):

print "__getattr__ called "

def __getattribute__(self, name):

print "__getattribute__ called"

return object.__getattribute__(self, name)

t = T()

t.__dict__["name"] = "baiyang"

print "t.__dict__: ", t.__dict__["name"]

print "t.age: ", t.age

print "t.__dict__['age']: ", t.__dict__["age"]

结果

__getattribute__ called

t.__dict__:  __getattribute__ called

baiyang

t.age:  __getattribute__ called

21

t.__dict__['age']:  __getattribute__ called

Traceback (most recent call last):

File "C:\Users\Administrator\Desktop\lab\SogouW\Freq\test.py", line 18, in

print "t.__dict__['age']: ", t.__dict__["age"]

KeyError: 'age'

我们来分析一下:

1.t__dict__["name"] = “baiyang”其中调用了__getattribute__函数,因为__dict__本身也是一个属性的,所以它必须会执行的;但是你会发现此时__setattr__并没有执行,达到了我们想要的效果;

2.print “t.age: “, t.age

print “t.__dict__['age']: “, t.__dict__["age"]这才是重点,第二条语句抛出了KeyError的异常,再一次证明了age只是存在于类的namespace中。

最后,我们与python中的descriptor进行比较:

可以看这篇文章,我就不细讲了。

主要一点就是descriptor对应的函数是

object.__get__(self, instance, owner)

object.__set__(self, instance, value)

object.__delete__(self, instance)

可以看出少了attr这个词,也以为着我们必须将他们区分看。descriptor是对类的实例进行的操作,内建函数property()就是通过这个方式实现的。看了此文,是不是对python的工作机制更加了解了呢?

好了,在这里提几个问吧,你可以去网上搜到答案

如何创建immutable的数据,我之前的一篇文章已经给出了答案。

如何创建singleton模式的数据

如果你明白了上面的文章,你就会明白,不论你想写出什么样的数据,只要去重写python中一些内在的函数即可。

-----------------打造高质量的文章 更多关注 把酒泯恩仇---------------

为了打造高质量的文章,请  推荐  一个吧。。。。谢谢了,我会写更多的好文章的。

把酒泯恩仇官方博客:http://www.ibaiyang.org 【推荐用google reader订阅】

python数据模型_#PYTHON#数据模型 | 学步园相关推荐

  1. 初识python 视频_#python day02 初识python 学习视频来源于 太白金星

    #python day02 初识python 学习视频来源于 太白金星 ''' 知识点:安装PyCharm''' # 设置鼠标条件字体大小:file ->settings # 搜索mouse E ...

  2. python发送notes邮件_使用python 驱动 lotus notes发送邮件 | 学步园

    因为最近做buildbot,想要使用公司的邮件系统 lotus notes发送邮件,但是网上一直没有比较完整的例子,都是vb的例子比较多,或者例子不完整,后来看到一个用visual foxpro 做的 ...

  3. python制作ico图标_用Python提取exe图标icon | 学步园

    这里使用Python win32包中的win32gui.ExtractIconEx方法来提取exe的图标,除了安装Python,还需要到这里下载Pywin. 第一份代码 将指定的a.exe图标保存为b ...

  4. python修改ip地址_用Python更改IP地址(转) | 学步园

    #-*- coding: cp936 -*-# #FileName: ModifyIP.py#Date    : 2008-01-15#importwmiprint'正在修改IP,请稍候 'wmiSe ...

  5. python快速查找_python应用_快速查找 | 学步园

    快速查找 import random def partition(list_object,start,end): random_choice = start#random.choice(range(s ...

  6. python 地址_python 解析地址 | 学步园

    socekt.getaddrinfo的返回值介绍 family: 表示socket使用的协议簇.常用的协议簇包括AF_UNIX(本机通信)/AF_INET(TCP/IP协议簇中的IPv4协议)/AF_ ...

  7. python开发服务程序_Python 编写Windows服务程序:将Python作为Windows服务启动 | 学步园...

    Python程序作为Windows服务启动,需要安装pywin32包.下载路径: #-*- coding:utf-8 -*- import win32serviceutil import win32s ...

  8. python里w_python vs pythonw | 学步园

    python解释器有2个版本,一个是python,另外一个是pythonw.那它们之间有什么区别呢?什么情况下用python什么情况下用pythonw? 先做个小实验,写2个小程序,一个只是输出字符串 ...

  9. python分形算法_python 分形 | 学步园

    代码如下: #!/usr/bin/env python # -*-coding:UTF-8-*-# from common import * import Image, ImageFilter, ma ...

最新文章

  1. 一款基于jquery和css3的头像恶搞特效
  2. Ui5 tool debug - ctrl alt shift s
  3. pthread-win32在VC2005下的使用
  4. 自己动手写符合自己业务需求的eslint规则
  5. 「Python基础知识」Python中常用的内建函数有哪些
  6. OpenGL 视图和颜色的概念
  7. python运维监控脚本_Python实现数通设备端口使用情况监控实例
  8. java 动态解析 xml_通过读取xml文件动态建表
  9. conda加入pytorch清华源
  10. Android 程序员计算器 开发记录-Git版本控制初步接触
  11. mappedby 详解
  12. SOC电源管理系统PMIC
  13. 阻滞增长模型求解_阻滞增长模型
  14. HTML <abbr> 标签
  15. 【sv】systemverilog之Automatic
  16. AUTOSAR OTA升级
  17. B站JavaScript从入门到精通智能社Blue石川老师视频部分代码_轮播图
  18. 14. Spring Boot定时任务的使用【从零开始学Spring Boot】
  19. 饥荒联机版-Centos7-阿里云服务器-搭建
  20. 使用adb命令清除预装内置的第三方app

热门文章

  1. SQL Server 2005 - 如何在预存程序中调用另外一个预存程序
  2. try except 异常捕获的方法、断言的使用
  3. C#利用phantomJS抓取AjAX动态页面
  4. asp.net core2.0中网站发布的时候,怎么样才配置才可以使视图文件不被打包进去?...
  5. shell自动交互之expect脚本_转
  6. Apache Spark 内存管理详解
  7. LeetCode -- Perfect Squares
  8. iOS开发之──传感器使用 (转载)
  9. SQL Server 内存中OLTP内部机制概述(二)
  10. [C++]二维数组还是一维数组?