Python数据模型

引言

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

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

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

既然python的一致性是出了名的,来说一说命名风格。

一、命名风格

主要存在四种命名 核心:不要以下划线开头命名

1. object # 公用方法

2. __object__ # 内建方法,用户不要这样定义 例如__init__

3. __object # 全私有,全保护

4. _object # 半保护

"单下划线" 开始的成员变量叫做保护变量,意思是只有类对象和子类对象自己能访问到这些变量;

"双下划线" 开始的是私有成员,意思是只有类对象自己能访问,连子类对象也不能访问到这个数据。

一般来讲,变量名_object被看作是“私有的”,在模块或类外不可以使用,不能用'from module import * '导入。当变量是私有的时候,用_object来表示变量是很好的习惯。单下划线+类名,eg:_Class__object 机制就可以访问__object__了。因为变量名__object__对Python 来说有特殊含义,对于普通的变量应当避免这种命名风格。

class Foo:
  _foo = 3
def __init__(self): return Nonedef public_method(self): print('This is public method') def __fullprivate_method(self): print('This is fullprivate_method') def _halfprivate_method(self): print('This is halfprivate_method')
_foo # error
f._foo # 3 f
= Foo(1) f.public_method() # OK f.__fullprivate_method() # Error occur f._halfprivate_method() # OK f._Foo__fullprivate_method() # OK
class A:
  _a = 5
def __init__(self): self.__private() self.public() def __private(self): print('A.__private()') def public(self): print('A.public()') class B(A):
  _b = 6
def __private(self): print('B.__private()') def public(self): print('B.public()') b = B() b._a
b._B__B 输出 A.
__private() B.public()
5
6

二、搭建一摞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('7', 'diamonds')
>>> beer_card
Card(rank='7', 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='2', suit='spades')
>>> deck[-1]
Card(rank='A', suit='hearts')

常见的特殊方法

当然也可以使用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']
View Code
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']
View Code

猜你喜欢

转载自www.cnblogs.com/welan/p/9419230.html