1. 程式人生 > >Python數據模型

Python數據模型

dex 工具 技術分享 機制 error view attr 用法 既然

引言

像大多數人一樣,我在對一直傳統的面向過程語言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

Python數據模型