引言

像大多数人一样,我在对一直传统的面向过程语言C一知半解之后,走进了面向对象的世界,尽管对OOP一无所知,还好Python还保留有函数式编程,这使得我才不那么抵触,直到现在,习惯了面向对象之后,也习惯了接口这些叫法,而不是函数。

在看到len(collection)与collection.len(),也越来越习惯后者,他所代表的强大的思想,(其实是调用的collection对象的内部__len__方法),这种设计思想完全体现在 Python 的数据模型上,而数据模型所描述的 API,为使用最地道的语言特性来构建你自己的

对象提供了工具。数据模型其实是对 Python 框架的描述,它规范了这门语言自身构建模块的接口,这些模块包括但不限于序列、迭代器、函数、类等。

一、私有和被保护的属性

类的私有属性:

  1. __private_attrs:两个下划线开头,声明该属性为私有,不能在类地外部被使用或直接访问。
  2. 在类内部的方法中使用时 self.__private_attrs

类的方法:

  1. 在类地内部,使用def关键字可以为类定义一个方法,与一般函数定义不同,类方法必须包含参数self,且为第一个参数

类的私有方法 :

  1. __private_method:两个下划线开头,声明该方法为私有方法,不能在类地外部调用。
  2. 在类的内部调用 self.__private_methods

默认情况下,Python中的成员函数和成员变量都是公开的(public),在python中没有类似public,private等关键词来修饰成员函数和成员变量。
在python中定义私有变量只需要在变量名或函数名前加上 ”__“两个下划线,那么这个函数或变量就是私有的了。
在内部,python使用一种 name mangling 技术,将 __membername替换成 _classname__membername,也就是说,类的内部定义中,
所有以双下划线开始的名字都被"翻译"成前面加上单下划线和类名的形式。

例如:为了保证不能在class之外访问私有变量,Python会在类的内部自动的把我们定义的__spam私有变量的名字替换成为
_classname__spam(注意,classname前面是一个下划线,spam前是两个下划线),因此,用户在外部访问__spam的时候就会
提示找不到相应的变量。   python中的私有变量和私有方法仍然是可以访问的;访问方法如下:

  1. 私有变量:实例._类名__变量名
  2. 私有方法:实例._类名__方法名()
  1. class people():
  2. __place = "nanjing"
  3. _age1 = 20
  4.  
  5. def __init__(self, name):
  6. self.name = name
  7.  
  8. def __sayhello(self):
  9. print("%s say hello" % self.name)
  10.  
  11. class teacher(people):
  12. pass
  13.  
  14. t1 = teacher("cmz")
  15. print(t1._people__place) # 访问私有变量
  16. t1._people__sayhello() # 访问私有方法
  17.  
  18. 结果是
  19. nanjing
  20. cmz say hello
  21.  
  22. python私有属性和方法案例

其实,Python并没有真正的私有化支持,但可用下划线得到伪私有。   尽量避免定义以下划线开头的变量!

  1. 1_xxx "单下划线" 开始的成员变量叫做保护变量,意思是只有类实例和子类实例能访问到这些变量,
  2. 需通过类提供的接口进行访问;不能用'from module import *'导入
  3. 2__xxx 类中的私有变量/方法名 Python的函数也是对象,所以成员方法称为成员变量也行得通。),
  4. " 双下划线 " 开始的是私有成员,意思是只有类对象自己能访问,连子类对象也不能访问到这个数据。
  5. 3__xxx__ 系统定义名字,前后均有一个“双下划线” 代表python里特殊方法专用的标识,如 __init__()代表类的构造函数。
  1. class people():
  2. __place = "nanjing"
  3. _age = 20
  4.  
  5. def __init__(self, name):
  6. self.name = name
  7.  
  8. def _test(self):
  9. print("from people test")
  10.  
  11. def __sayhello(self):
  12. print("%s say hello" % self.name)
  13.  
  14. class teacher(people):
  15. pass
  16.  
  17. t1 = teacher("cmz")
  18. print(t1._age)
  19. print(people._age)
  20. t1._test()
  21. people._test(t1) # 传入对象t1
  22.  
  23. 结果是
  24. 20
  25. 20
  26. from people test
  27. from people test
  1. class people():
  2. __place = "nanjing"
  3. _age = 20
  4.  
  5. def __init__(self, name):
  6. self.name = name
  7.  
  8. def __sayhello(self):
  9. print("%s say hello" % self.name)
  10.  
  11. class teacher(people):
  12. pass
  13.  
  14. t1 = teacher("cmz")
  15. print(t1._people__place)
  16. t1._people__sayhello()
  17.  
  18. 结果是
  19. nanjing
  20. 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)

  1. #打印十张纸牌
  1. Card(rank='2', suit='spades')
  2. Card(rank='3', suit='spades')
  3. Card(rank='4', suit='spades')
  4. Card(rank='5', suit='spades')
  5. Card(rank='6', suit='spades')
  6. Card(rank='7', suit='spades')
  7. Card(rank='8', suit='spades')
  8. Card(rank='9', suit='spades')
  9. Card(rank='10', suit='spades')
  10. Card(rank='J', suit='spades')
  1. # 对纸牌进行排序
  2.  
  3. suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)
  4. def spades_high(card):
  5. rank_value = FrenchDeck.ranks.index(card.rank)
  6. return rank_value * len(suit_values) + suit_values[card.suit]
  7.  
  8. for card in sorted(deck, key=spades_high):
  9. print(card)
  10.  
  11. Card(rank='2', suit='clubs')
  12. Card(rank='2', suit='diamonds')
  13. Card(rank='2', suit='hearts')
  14. ... (46 cards ommitted)
  15. Card(rank='A', suit='diamonds')
  16. Card(rank='A', suit='hearts')
  17. Card(rank='A', suit='spades')

  

三、特殊方法

下面来看看特殊方法

  1. beer_card = Card('', 'diamonds')
  2. >>> beer_card
  3. 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 语言结构体。直接读取这

个值比调用一个方法要快很多。

  1. >>> deck = FrenchDeck()
  2. >>> len(deck)
  3. 52

从一叠牌中抽取特定的一张纸牌,比如说第一张或最后一张,是很容易的:deck[0] 或 deck[-1]。这都是由 __getitem__ 方法提供的

字典中也有这种用法,类似dic[k], 其背后也是__getitem__在默默支持,不过这里返回的值而是键k所对应的值value

  1. >>> deck[0]
  2. Card(rank='', suit='spades')
  3. >>> deck[-1]
  4. Card(rank='A', suit='hearts'

3.1、运算符重载

说到特殊方法来看一下运算符重载,运算符重载只是意味着在类方法中拦截内置的操作——当类的实例出现在内置操作中,Python自动调用你的方法,并且你的方法的返回值变成了相应操作的结果。

  1. # Number类提供了一个方法来拦截实例的构造函数(__init__),此外还有一个方法捕捉减法表达式(__sub__)。这种特殊的方法是钩子,可与内置运算绑定。
    >>> class Number:
  2. def __init__(self,start):
  3. self.data = start
  4. def __sub__(self,other):
  5. return Number(self.data - other)
  6.  
  7. >>> X = Number(5)
  8. >>> X.data
  9. 5
  10. >>> Y = X - 2
  11. >>> Y.data
  12. 3

3.2、 方法重载

overloading method:是在一个类里面,方法名字相同,而参数不同。返回类型呢?可以相同也可以不同。重载是让类以统一的方式处理不同类型数据的一种手段。
函数重载主要是为了解决两个问题。
1.可变参数类型。
2.可变参数个数。

另外,一个基本的设计原则是,仅仅当两个函数除了参数类型和参数个数不同以外,其功能是完全相同的,此时才使用函数重载,如果两个函数的功能其实不同,那么不应当使用重载,而应当使用一个名字不同的函数。
 
对于情况 1 ,函数功能相同,但是参数类型不同,python 如何处理?答案是根本不需要处理,因为 python 可以接受任何类型的参数,如果函数的功能相同,那么不同的参数类型在 python 中很可能是相同的代码,没有必要做成两个不同函数。

对于情况 2 ,函数功能相同,但参数个数不同,python 如何处理?大家知道,答案就是缺省参数。对那些缺少的参数设定为缺省参数即可解决问题。因为你假设函数功能相同,那么那些缺少的参数终归是需要用的。

鉴于情况 1 跟 情况 2 都有了解决方案,python 自然就不需要函数重载了。

子类不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写(overriding method)又称方法覆盖。

 

3.3、常见的特殊方法

当然也可以使用dir内置函数来查看常见并比较的数据结构的特殊方法,如list,dict等。

  1. dir(list)
  2. ['__add__',
  3. '__class__',
  4. '__contains__',
  5. '__delattr__',
  6. '__delitem__',
  7. '__dir__',
  8. '__doc__',
  9. '__eq__',
  10. '__format__',
  11. '__ge__',
  12. '__getattribute__',
  13. '__getitem__',
  14. '__gt__',
  15. '__hash__',
  16. '__iadd__',
  17. '__imul__',
  18. '__init__',
  19. '__iter__',
  20. '__le__',
  21. '__len__',
  22. '__lt__',
  23. '__mul__',
  24. '__ne__',
  25. '__new__',
  26. '__reduce__',
  27. '__reduce_ex__',
  28. '__repr__',
  29. '__reversed__',
  30. '__rmul__',
  31. '__setattr__',
  32. '__setitem__',
  33. '__sizeof__',
  34. '__str__',
  35. '__subclasshook__',
  36. 'append',
  37. 'clear',
  38. 'copy',
  39. 'count',
  40. 'extend',
  41. 'index',
  42. 'insert',
  43. 'pop',
  44. 'remove',
  45. 'reverse',
  46. 'sort']
  1. dir(tuple)
  2. ['__add__',
  3. '__class__',
  4. '__contains__',
  5. '__delattr__',
  6. '__dir__',
  7. '__doc__',
  8. '__eq__',
  9. '__format__',
  10. '__ge__',
  11. '__getattribute__',
  12. '__getitem__',
  13. '__getnewargs__',
  14. '__gt__',
  15. '__hash__',
  16. '__init__',
  17. '__iter__',
  18. '__le__',
  19. '__len__',
  20. '__lt__',
  21. '__mul__',
  22. '__ne__',
  23. '__new__',
  24. '__reduce__',
  25. '__reduce_ex__',
  26. '__repr__',
  27. '__rmul__',
  28. '__setattr__',
  29. '__sizeof__',
  30. '__str__',
  31. '__subclasshook__',
  32. 'count',
  33. 'index']

Python数据模型的更多相关文章

  1. Python数据模型及Pythonic编程

    Python作为一种多范式语言,它的很多语言特性都能从其他语言上找到参照,但是Python依然形成了一套自己的“Python 风格”(Pythonic).这种Pythonic风格完全体现在 Pytho ...

  2. 第1章 Python数据模型

    #<流畅的Python>读书笔记 # 第一部分 序幕 # 第1章 Python数据模型 # 魔术方法(magic method)是特殊方法的昵称.于是乎,特殊方法也叫双下方法(dunder ...

  3. gj3 Python数据模型(魔法函数)

    3.1 什么是魔法函数 类里面,实现某些特性的内置函数,类似 def __xx__(): 的形式. 不要自己定义XX,并不是和某个类挂钩的 class Company(object): def __i ...

  4. python高级(一)—— python数据模型(特殊方法)

    本文主要内容 collections.namedtuple __getitem__ 和 __len__ __repr__和__str__ __abs__.__add__和__mul__ __bool_ ...

  5. Python数据模型与Python对象模型

    数据模型==对象模型 Python官方文档说法是"Python数据模型",大多数Python书籍作者说法是"Python对象模型",它们是一个意思,表示&quo ...

  6. Python数据模型建立

    基本结构AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列,必须填入参数 pri ...

  7. Python 数据模型

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 25.0px Helvetica } 一摞Python风格的纸牌 from collections impo ...

  8. (一)python 数据模型

    1.通过实现特殊方法,自定义类型可以表现的跟内置类型一样: 如下代码,实现len, getitem,可使自定义类型表现得如同列表一样. import collections from random i ...

  9. 流畅的python第一章python数据模型学习记录

    python中有些特殊的方法,以双上下划线开头,并以双下划线结束的方法.如__getitem__,这些方法是特殊的方法,供python解释权内部使用,一般来说不需要调用 还有一种是以双下划线开头的,如 ...

随机推荐

  1. 学习使用Apollo配置中心

    Apollo(阿波罗)是携程框架部门研发的配置管理平台,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端. Apollo官网地址 如何安装服务端可以按照上面官网的步骤. 这里 ...

  2. InfluxDB配置文件详解

    全局配置 # 该选项用于上报influxdb的使用信息给InfluxData公司,默认值为false reporting-disabled = false # 备份恢复时使用,默认值为8088 bin ...

  3. centos 安装nginx笔记

    添加nginx 存储库 yum install epel-release 安装 yum install nginx 启动 systemctl start nginx

  4. sync.Pool 资源池

    sync.Pool type Pool struct { // 可选参数New指定一个函数在Get方法可能返回nil时来生成一个值 // 该参数不能在调用Get方法时被修改 New func() in ...

  5. vue10行代码实现上拉翻页加载更多数据,纯手写js实现下拉刷新上拉翻页不引用任何第三方插件

    vue10行代码实现上拉翻页加载更多数据,纯手写js实现下拉刷新上拉翻页不引用任何第三方插件/库 一提到移动端的下拉刷新上拉翻页,你可能就会想到iScroll插件,没错iScroll是一个高性能,资源 ...

  6. StringBuffer、StringBuilder、冒泡与选择排序、二分查找、基本数据类型包装类_DAY13

    1:数组的高级操作(预习) (1)数组:存储同一种数据类型的多个元素的容器. (2)特点:每个元素都有从0开始的编号,方便我们获取.专业名称:索引. (3)数组操作: A:遍历 public stat ...

  7. 剑指offer一之二维数组中的查找

    一.题目: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 二.解答方法: 方法 ...

  8. Elasticsearch Java Client连接池

    按照Elasticsearch API,在Java端使用是ES服务需要创建Java Client,但是每一次连接都实例化一个client,对系统的消耗很大,即使在使用完毕之后将client close ...

  9. Java之ServiceLoader

    转载请注明源出处:http://www.cnblogs.com/lighten/p/6946683.html 1.简介 JDK1.6之后,java.util包下多了一个类ServiceLoader,其 ...

  10. sql左右连接的区别

    数据表的连接有: 1.内连接(自然连接): 只有两个表相匹配的行才能在结果集中出现 2.外连接: 包括 (1)左外连接(左边的表不加限制) (2)右外连接(右边的表不加限制) (3)全外连接(左右两表 ...