翻譯:《實用的Python編程》04_01_Class

目錄 | 上一節 (3.6 設計討論) | 下一節 (4.2 繼承)python

4.1 類

本節介紹 class 語句以及建立新對象的方式。git

面向對象編程(OOP)

面向對象編程是一種將代碼組織成對象集合的編程技術。github

一個對象包括:編程

  • 數據。屬性
  • 行爲。方法——應用於對象的函數。

在本課程中,你已經使用了面向對象編程技術。segmentfault

例如,操做列表。數據結構

>>> nums = [1, 2, 3]
>>> nums.append(4)      # Method
>>> nums.insert(1,10)   # Method
>>> nums
[1, 10, 2, 3, 4]        # Data
>>>

nums 是列表的實例(instance)。app

方法(append()insert())被綁定到實例(nums)上。函數

class 語句

使用 class 語句定義一個新的對象。翻譯

class Player:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.health = 100

    def move(self, dx, dy):
        self.x += dx
        self.y += dy

    def damage(self, pts):
        self.health -= pts

簡而言之,類是一組函數,對所謂的 實例(instance) 執行各類操做。設計

實例

實例是你在程序中操做的實際對象。

經過像調用函數同樣調用類來建立實例。

>>> a = Player(2, 3)
>>> b = Player(10, 20)
>>>

ab 都是 Player 類的實例。

強調:class 語句僅僅是一個定義(它自己不執行任何操做)。相似於函數定義。

實例數據

每一個實例都擁有本身的局部數據。

>>> a.x
2
>>> b.x
10

數據經過 _init__() 方法進行初始化。

class Player:
    def __init__(self, x, y):
        # Any value stored on `self` is instance data
        self.x = x
        self.y = y
        self.health = 100

對屬性的總數或者類型沒有限制。

實例方法

應用於對象實例的函數稱爲實例方法。

class Player:
    ...
    # `move` is a method
    def move(self, dx, dy):
        self.x += dx
        self.y += dy

對象自己始終做爲第一個參數傳遞。

>>> a.move(1, 2)

# matches `a` to `self`
# matches `1` to `dx`
# matches `2` to `dy`
def move(self, dx, dy):

按照慣例,實例稱爲 self。可是,使用的實際名字不重要。對象始終做爲第一個參數傳遞。將這個參數稱爲 self 只是 Python 的編程風格。

類做用域

類未定義名稱的做用域。

class Player:
    ...
    def move(self, dx, dy):
        self.x += dx
        self.y += dy

    def left(self, amt):
        move(-amt, 0)       # NO. Calls a global `move` function
        self.move(-amt, 0)  # YES. Calls method `move` from above.

若是想要對實例進行操做,那麼你始終須要顯式地引用它(如: self)。

練習

從本組練習開始,咱們將對前面章節的現有代碼進行一系列更改。從練習 3.18 版本的代碼開始很是重要。若是你尚未這些代碼,請到 Solutions/3_18 目錄下查看,而後複製它。

練習 4.1:把對象當作數據結構

在第 2 和第 3 節中,咱們使用了了以元組和字典表示的數據。例如,持有的股票能夠用像下面這樣的元組表示:

s = ('GOOG',100,490.10)

或者使用像下面這樣的字典表示:

s = { 'name'   : 'GOOG',
      'shares' : 100,
      'price'  : 490.10
}

你甚至能夠編寫用於操做此類數據的函數。例如:

def cost(s):
    return s['shares'] * s['price']

可是,隨着程序規模的不斷擴大,你可能但願建立更好的代碼組織意識(sense)。所以,能夠定義一個類表示數據。請建立一個名爲 stock.py 的文件,並定義一個名爲 Stock 的類,用以表示持有的單支股票。Stock 類具備 name, shares,和 price 屬性。示例:

>>> import stock
>>> a = stock.Stock('GOOG',100,490.10)
>>> a.name
'GOOG'
>>> a.shares
100
>>> a.price
490.1
>>>

建立更多的 Stock 對象並對其進行操做。示例:

>>> b = stock.Stock('AAPL', 50, 122.34)
>>> c = stock.Stock('IBM', 75, 91.75)
>>> b.shares * b.price
6117.0
>>> c.shares * c.price
6881.25
>>> stocks = [a, b, c]
>>> stocks
[<stock.Stock object at 0x37d0b0>, <stock.Stock object at 0x37d110>, <stock.Stock object at 0x37d050>]
>>> for s in stocks:
     print(f'{s.name:>10s} {s.shares:>10d} {s.price:>10.2f}')

... look at the output ...
>>>

須要強調的一點是,在這裏, Stock 類充當建立實例對象的工廠。基本上,你能夠像調用函數同樣調用類爲你建立新對象。另外,必須強調的是,每個對象都是不一樣的——它們擁有各自的數據,這些數據與以建立的其它對象是分開的。

某種程度上,經過類定義的對象與字典相似——只是使用頗爲不一樣的語法。例如,使用的是 s.names.price,而不是 s['name']s['price']

練習 4.2:添加方法

擁有對象後,你能夠添加方法到對象上。衆所皆知,方法就是對存儲在對象內部的數據進行操做的函數。請給 Stock 對象添加 cost()sell() 方法。它們應該像下面這樣工做:

>>> import stock
>>> s = stock.Stock('GOOG', 100, 490.10)
>>> s.cost()
49010.0
>>> s.shares
100
>>> s.sell(25)
>>> s.shares
75
>>> s.cost()
36757.5
>>>

練習 4.3:建立實例列表

嘗試執行如下步驟,從列表字典中建立 Stock 的實例列表。而後計算總費用:

>>> import fileparse
>>> with open('Data/portfolio.csv') as lines:
...     portdicts = fileparse.parse_csv(lines, select=['name','shares','price'], types=[str,int,float])
...
>>> portfolio = [ stock.Stock(d['name'], d['shares'], d['price']) for d in portdicts]
>>> portfolio
[<stock.Stock object at 0x10c9e2128>, <stock.Stock object at 0x10c9e2048>, <stock.Stock object at 0x10c9e2080>,
 <stock.Stock object at 0x10c9e25f8>, <stock.Stock object at 0x10c9e2630>, <stock.Stock object at 0x10ca6f748>,
 <stock.Stock object at 0x10ca6f7b8>]
>>> sum([s.cost() for s in portfolio])
44671.15
>>>

練習 4.4:使用類

請修改 report.py 程序裏面的 read_portfolio() 函數,以便如練習 4.3 所示那樣,讀取股票投資組合到 Stock 的實例列表裏面。修改完後,修復(fix)report.pypcost.py 裏面全部的代碼,以便使用 Stock 的實例進行工做,而不是使用字典。

提示:你沒必要對代碼進行大量更改,主要是將字典訪問,如 s['shares'] 更改成 s.shares

修改完後應該可以像以前同樣運行函數:

>>> import pcost
>>> pcost.portfolio_cost('Data/portfolio.csv')
44671.15
>>> import report
>>> report.portfolio_report('Data/portfolio.csv', 'Data/prices.csv')
      Name     Shares      Price     Change
---------- ---------- ---------- ----------
        AA        100       9.22     -22.98
       IBM         50     106.28      15.18
       CAT        150      35.46     -47.98
      MSFT        200      20.89     -30.34
        GE         95      13.48     -26.89
      MSFT         50      20.89     -44.21
       IBM        100     106.28      35.84
>>>

目錄 | 上一節 (3.6 設計討論) | 下一節 (4.2 繼承)

注:完整翻譯見 https://github.com/codists/practical-python-zh

相關文章
相關標籤/搜索