Python数据模型
引言
像大多数人一样,我在对一直传统的面向过程语言C一知半解之后,走进了面向对象的世界,尽管对OOP一无所知,还好Python还保留有函数式编程,这使得我才不那么抵触,直到现在,习惯了面向对象之后,也习惯了接口这些叫法,而不是函数。
在看到len(collection)与collection.len(),也越来越习惯后者,他所代表的强大的思想,(其实是调用的collection对象的内部__len__方法),这种设计思想完全体现在 Python 的数据模型上,而数据模型所描述的 API,为使用最地道的语言特性来构建你自己的
对象提供了工具。数据模型其实是对 Python 框架的描述,它规范了这门语言自身构建模块的接口,这些模块包括但不限于序列、迭代器、函数、类等。
一、私有和被保护的属性
类的私有属性:
__private_attrs:两个下划线开头,声明该属性为私有,不能在类地外部被使用或直接访问。
在类内部的方法中使用时 self.__private_attrs。
类的方法:
在类地内部,使用def关键字可以为类定义一个方法,与一般函数定义不同,类方法必须包含参数self,且为第一个参数
类的私有方法 :
__private_method:两个下划线开头,声明该方法为私有方法,不能在类地外部调用。
在类的内部调用 self.__private_methods
默认情况下,Python中的成员函数和成员变量都是公开的(public),在python中没有类似public,private等关键词来修饰成员函数和成员变量。
在python中定义私有变量只需要在变量名或函数名前加上 ”__“两个下划线,那么这个函数或变量就是私有的了。
在内部,python使用一种 name mangling 技术,将 __membername替换成 _classname__membername,也就是说,类的内部定义中,
所有以双下划线开始的名字都被"翻译"成前面加上单下划线和类名的形式。
例如:为了保证不能在class之外访问私有变量,Python会在类的内部自动的把我们定义的__spam私有变量的名字替换成为
_classname__spam(注意,classname前面是一个下划线,spam前是两个下划线),因此,用户在外部访问__spam的时候就会
提示找不到相应的变量。 python中的私有变量和私有方法仍然是可以访问的;访问方法如下:
私有变量:实例._类名__变量名
私有方法:实例._类名__方法名()
class people():
__place = "nanjing"
_age1 = 20 def __init__(self, name):
self.name = name def __sayhello(self):
print("%s say hello" % self.name) class teacher(people):
pass t1 = teacher("cmz")
print(t1._people__place) # 访问私有变量
t1._people__sayhello() # 访问私有方法 结果是
nanjing
cmz say hello python私有属性和方法案例
其实,Python并没有真正的私有化支持,但可用下划线得到伪私有。 尽量避免定义以下划线开头的变量!
(1)_xxx "单下划线" 开始的成员变量叫做保护变量,意思是只有类实例和子类实例能访问到这些变量,
需通过类提供的接口进行访问;不能用'from module import *'导入
(2)__xxx 类中的私有变量/方法名 (Python的函数也是对象,所以成员方法称为成员变量也行得通。),
" 双下划线 " 开始的是私有成员,意思是只有类对象自己能访问,连子类对象也不能访问到这个数据。
(3)__xxx__ 系统定义名字,前后均有一个“双下划线” 代表python里特殊方法专用的标识,如 __init__()代表类的构造函数。
class people():
__place = "nanjing"
_age = 20 def __init__(self, name):
self.name = name def _test(self):
print("from people test") def __sayhello(self):
print("%s say hello" % self.name) class teacher(people):
pass t1 = teacher("cmz")
print(t1._age)
print(people._age)
t1._test()
people._test(t1) # 传入对象t1 结果是
20
20
from people test
from people test
class people():
__place = "nanjing"
_age = 20 def __init__(self, name):
self.name = name def __sayhello(self):
print("%s say hello" % self.name) class teacher(people):
pass t1 = teacher("cmz")
print(t1._people__place)
t1._people__sayhello() 结果是
nanjing
cmz say hello
二、搭建一摞pythonic的纸牌
python的另一强大之处就是丰富的标准库,还有许许多多的第三方库,这使得不用重复造轮子
import collections
Card = collections.namedtuple('Card', ['rank', 'suit'])
class FrenchDeck:
ranks = [str(n) for n in range(2, 11)] + list('JQKA')
suits = 'spades diamonds clubs hearts'.split()
def __init__(self):
self._cards = [Card(rank, suit) for suit in self.suits
for rank in self.ranks]
def __len__(self):
return len(self._cards)
def __getitem__(self, position):
return self._cards[position]
deck = FrenchDeck()
for i in deck[:10]: # 其实这里调用的是deck这个可迭代对象背后其实用的是 iter(x),而这个函数的背后则是 x.__iter__() 方法
print(i)
#打印十张纸牌
Card(rank='2', suit='spades')
Card(rank='3', suit='spades')
Card(rank='4', suit='spades')
Card(rank='5', suit='spades')
Card(rank='6', suit='spades')
Card(rank='7', suit='spades')
Card(rank='8', suit='spades')
Card(rank='9', suit='spades')
Card(rank='10', suit='spades')
Card(rank='J', suit='spades')
# 对纸牌进行排序 suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)
def spades_high(card):
rank_value = FrenchDeck.ranks.index(card.rank)
return rank_value * len(suit_values) + suit_values[card.suit] for card in sorted(deck, key=spades_high):
print(card) Card(rank='2', suit='clubs')
Card(rank='2', suit='diamonds')
Card(rank='2', suit='hearts')
... (46 cards ommitted)
Card(rank='A', suit='diamonds')
Card(rank='A', suit='hearts')
Card(rank='A', suit='spades')
三、特殊方法
下面来看看特殊方法
beer_card = Card('', 'diamonds')
>>> beer_card
Card(rank='', suit='diamonds')
len()方法与特殊方法__len__,
特殊方法的存在是为了被 Python 解释器调用的,你自己并不需要调用它们。也就是说没有 my_object.__len__() 这种写法,而应该使用 len(my_object)。在执行 len(my_object) 的时候,如果my_object 是一个自定义类的对象,那么 Python 会自己去调用其中由
你实现的 __len__ 方法。abs也是同理,
如果是 Python 内置的类型,比如列表(list)、字符串(str)、字节序列(bytearray)等,那么 CPython 会抄个近路,__len__ 实际上会直接返回 PyVarObject 里的 ob_size 属性。PyVarObject 是表示内存中长度可变的内置对象的 C 语言结构体。直接读取这
个值比调用一个方法要快很多。
>>> deck = FrenchDeck()
>>> len(deck)
52
从一叠牌中抽取特定的一张纸牌,比如说第一张或最后一张,是很容易的:deck[0] 或 deck[-1]。这都是由 __getitem__ 方法提供的
字典中也有这种用法,类似dic[k], 其背后也是__getitem__在默默支持,不过这里返回的值而是键k所对应的值value
>>> deck[0]
Card(rank='', suit='spades')
>>> deck[-1]
Card(rank='A', suit='hearts'
3.1、运算符重载
说到特殊方法来看一下运算符重载,运算符重载只是意味着在类方法中拦截内置的操作——当类的实例出现在内置操作中,Python自动调用你的方法,并且你的方法的返回值变成了相应操作的结果。
# Number类提供了一个方法来拦截实例的构造函数(__init__),此外还有一个方法捕捉减法表达式(__sub__)。这种特殊的方法是钩子,可与内置运算绑定。
>>> class Number:
def __init__(self,start):
self.data = start
def __sub__(self,other):
return Number(self.data - other) >>> X = Number(5)
>>> X.data
5
>>> Y = X - 2
>>> Y.data
3
3.2、 方法重载
overloading method:是在一个类里面,方法名字相同,而参数不同。返回类型呢?可以相同也可以不同。重载是让类以统一的方式处理不同类型数据的一种手段。
函数重载主要是为了解决两个问题。
1.可变参数类型。
2.可变参数个数。
对于情况 2 ,函数功能相同,但参数个数不同,python 如何处理?大家知道,答案就是缺省参数。对那些缺少的参数设定为缺省参数即可解决问题。因为你假设函数功能相同,那么那些缺少的参数终归是需要用的。
鉴于情况 1 跟 情况 2 都有了解决方案,python 自然就不需要函数重载了。
子类不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写(overriding method)又称方法覆盖。
3.3、常见的特殊方法

当然也可以使用dir内置函数来查看常见并比较的数据结构的特殊方法,如list,dict等。
dir(list)
['__add__',
'__class__',
'__contains__',
'__delattr__',
'__delitem__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getitem__',
'__gt__',
'__hash__',
'__iadd__',
'__imul__',
'__init__',
'__iter__',
'__le__',
'__len__',
'__lt__',
'__mul__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__reversed__',
'__rmul__',
'__setattr__',
'__setitem__',
'__sizeof__',
'__str__',
'__subclasshook__',
'append',
'clear',
'copy',
'count',
'extend',
'index',
'insert',
'pop',
'remove',
'reverse',
'sort']
dir(tuple)
['__add__',
'__class__',
'__contains__',
'__delattr__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getitem__',
'__getnewargs__',
'__gt__',
'__hash__',
'__init__',
'__iter__',
'__le__',
'__len__',
'__lt__',
'__mul__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__rmul__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'count',
'index']
Python数据模型的更多相关文章
- Python数据模型及Pythonic编程
Python作为一种多范式语言,它的很多语言特性都能从其他语言上找到参照,但是Python依然形成了一套自己的“Python 风格”(Pythonic).这种Pythonic风格完全体现在 Pytho ...
- 第1章 Python数据模型
#<流畅的Python>读书笔记 # 第一部分 序幕 # 第1章 Python数据模型 # 魔术方法(magic method)是特殊方法的昵称.于是乎,特殊方法也叫双下方法(dunder ...
- gj3 Python数据模型(魔法函数)
3.1 什么是魔法函数 类里面,实现某些特性的内置函数,类似 def __xx__(): 的形式. 不要自己定义XX,并不是和某个类挂钩的 class Company(object): def __i ...
- python高级(一)—— python数据模型(特殊方法)
本文主要内容 collections.namedtuple __getitem__ 和 __len__ __repr__和__str__ __abs__.__add__和__mul__ __bool_ ...
- Python数据模型与Python对象模型
数据模型==对象模型 Python官方文档说法是"Python数据模型",大多数Python书籍作者说法是"Python对象模型",它们是一个意思,表示&quo ...
- Python数据模型建立
基本结构AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列,必须填入参数 pri ...
- Python 数据模型
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 25.0px Helvetica } 一摞Python风格的纸牌 from collections impo ...
- (一)python 数据模型
1.通过实现特殊方法,自定义类型可以表现的跟内置类型一样: 如下代码,实现len, getitem,可使自定义类型表现得如同列表一样. import collections from random i ...
- 流畅的python第一章python数据模型学习记录
python中有些特殊的方法,以双上下划线开头,并以双下划线结束的方法.如__getitem__,这些方法是特殊的方法,供python解释权内部使用,一般来说不需要调用 还有一种是以双下划线开头的,如 ...
随机推荐
- 移动端测试接口--Fiddler抓包工具
Fiddler抓包工具是一款免费且功能强大的数据包抓取软件.它通过代理的方式获取程序http通讯的数据,可以用其检测网页和服务器的交互情况,能够记录所有客户端和服务器间的http请求,支持监视.设置断 ...
- javascript之快速排序
快速排序思想其实还是挺简单的,分三步走: 1.在数组中找到基准点,其他数与之比较. 2.建立两个数组,小于基准点的数存储在左边数组,大于基准点的数存储在右边数组. 3.拼接数组,然后左边数组与右边数组 ...
- python粘包分析与解决
TCP与UDP协议 TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务.收发两端(客户端和服务器端)都要有一一成对的socket,因此 ...
- css 图片文字居中
1.单行文字居中 2.多行文字居中 3.利用background-position:center;的图片居中 4.利用display:table-cell;属性的图片居中 <!DOCTYPE h ...
- 【xsy3355】图 思维
题目大意:给你一个n个点m条无向边的图,问这个图是否能够: 1,被四染色(用四种颜色给图染色,且相邻点颜色不同). 2,找出一个奇环,满足在原图中去掉这个奇环后每个点依然相邻. 请输出1或者2中的任意 ...
- KVM的VPS主机在Centos6.x下修改系统时间
显示系统时间 # date "+%Y-%m-%d %H:%M:%S" 修改系统时区 # cp /usr/share/zoneinfo/Asia/Shanghai /etc/loca ...
- android开发学习——day5
活动跳转部分代码显式intent @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(saved ...
- 自动化部署-从maven到shell脚本到jenkins
Java代码自动部署 [ ①Java代码自动部署-总结简介] 代码部署是每一个软件开发项目组都会有的一个流程,也是从开发环节到发布功能必不可少的环节.对于Java开发者来说,Java代码的发布部署也是 ...
- 手把手教你整合最优雅SSM框架
我们看招聘信息的时候,经常会看到这一点,需要具备 SSM 框架的技能, SpringMVC 可以完全替代 Struts,配合注解的方式,编程非常快捷,而且通过 restful 风格定义 url,让地址 ...
- 前端通信:ajax设计方案(六)--- 全局配置、请求格式拓展和优化、请求二进制类型、浏览器错误搜集以及npm打包发布
距离上一次博客大概好多好多时间了,感觉再不搞点东西出来,感觉就废了的感觉.这段时间回老家学习驾照,修养,然后7月底来上海求职(面了4家,拿了3家office),然后入职同程旅游,项目赶进度等等一系列的 ...