Python練習:從入門到實踐——類(class)

目錄

一、創建和使用類

二、根據類創建實例

2.1 訪問屬性

2.2 調用方法

2.3 創建多個實例

三、使用類和實例

3.1 Car類

3.2  給屬性指定默認值

3.3 修改屬性的值

3.3.1 直接修改屬性的值

3.3.2 通過方法修改屬性的值

3.3.3 通過方法對屬性的值進行遞增

四、繼承

4.1  子類的方法 __init__()

4.2 Python 2.7中的繼承

4.3 給子類定義屬性和方法

4.4 重寫父類的方法

4.5 將實例用作屬性

五、導入類

5.1 導入單個類

5.2 在一個模塊中存儲多個類

5.3 從一個模塊中導入多個類

5.4 導入整個模塊

5.5 導入模塊中的所有類

5.6 在一個模塊中導入另一個模塊

六、Python標準庫

七、類編碼風格


編寫類時,定義一大類對象都有的通用行爲,基於類創建對象時,每個對象都自動具備這種通用行爲,然後可根據需要賦予每個對象獨特的個性。

根據類來創建對象被稱爲實例化。

一、創建和使用類

e.g 創建Dog類。根據Dog類創建的每個實例都將存儲名字和年齡,賦予每條小狗蹲下(sit())和打滾(roll_over())的能力:

class Dog():
    """一次模擬小狗的簡單嘗試"""
    def __init__(self, name, age):
        """初始化屬性name和age"""
        self.name = name
        self.age = age

    def sit(self):
        """模擬小狗命令時蹲下"""
        print(self.name.title() + " is now sitting.")

    def roll_over(self):
        """模擬小狗被命令時打滾"""
        print(self.name.title() + " rolled over!")

類的名稱需要首字母大寫。

1. 方法__init__()

類中的函數稱爲方法,有關函數的一切都適用於方法,唯一的差別在於調用方法的方式。

每次根據Dog類創建新實例時,Python都會自動運行方法__init__()。

形參self必不可少,且必須位於其他形參的前面;Python調用方法__init__()來創建Dog實例時,將自動傳入實參self,每個與類相關聯的方法調用都自動傳遞實參self,它是一個指向實例本身的引用,讓實例能夠訪問類中的屬性和方法。e.g 創建Dog實例時,Python將調用Dog類的方法__init__(),我們只需提供最後兩個形參(name、age),self會自動傳遞。

2. self.name

以self爲前綴的變量可供類中的所有方法使用,也可以通過類的任何實例來訪問這些變量。self.name = name獲取存儲在形參name中的值,並將其存儲到變量name中,然後該變量被關聯到當前創建的實例。像這樣,通過實例訪問的變量稱爲屬性。

二、根據類創建實例

class Dog():
    ---snip---

my_dog = Dog('while',6)
print("My dog's name is " + my_dog.name.title() +".")
print("My dog is " + str(my_dog.age) +" years old.")
  • 方法__init__()創建一個表示特定小狗的實例,並使用我們提供的值來設置屬性name和age。
  • 方法__init__()並未顯式地包含return語句,但python自動返回一個表示這條小狗的實例,並將該實例存儲在變量my_dog中
  • 通常認爲首字母大寫的名稱(e.g Dog)爲類,而小寫的名稱(e.g my_dog)爲根據類創建的實例。

2.1 訪問屬性

句點表示法。

my_dog.name
my_dog.age

2.2 調用方法

根據Dog類創建實例後,可以使用句點表示法來調用Dog類中定義的任何方法。

my_dog.sit()
my_dog.roll_over()

2.3 創建多個實例

可根據需求創建任意數量的實例,前提是將每個實例都存儲在不同的變量中,或佔用列表或字典的不同位置。

三、使用類和實例

修改實例的屬性,可以直接修改也可以編寫方法以特定的方式修改。

3.1 Car類

class Car():
    def __init__(self, make, model, year):
        """初始化描述汽車的屬性"""
        self.make = make
        self.model = model
        self.year = year

    def get_descriptive_name(self):
        """返回整潔的描述性信息"""
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()

my_new_car = Car('audi','a4',2016)
print(my_new_car.get_descriptive_name())

3.2  給屬性指定默認值

類中的每個屬性都必須有初始值,哪怕這個值是0或空字符串。在有些情況下,如設置默認值時,在方法__init__()內指定這種初始值時是可行的,如果對某個屬性這樣做了,就無需包含爲它提供初始值的形參。

e.g 添加一個名爲odometer_reading的屬性,其初始值總是0,同時添加一個read_odometer()的方法,用於讀取汽車的里程錶。

class Car():
    def __init__(self, make, model, year):
        """初始化描述汽車的屬性"""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0

    def get_descriptive_name(self):
        """返回整潔的描述性信息"""
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()

    def read_odometer(self):
        """打印汽車的里程"""
        print("This car has " + str(self.odometer_reading) + " miles on it.")

my_new_car = Car('audi','a4',2016)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()

屬性odometer_reading被賦予的初始值,沒有包含在__init__()方法的形參中。

3.3 修改屬性的值

3.3.1 直接修改屬性的值

通過實例直接訪問。

class Car():
    ---snip---

my_new_car = Car('audi','a4',2016)
print(my_new_car.get_descriptive_name())

# 直接使用句點表示法訪問並設置汽車的屬性odometer_reading,並將其設置爲23
my_new_car.odometer_reading = 23
my_new_car.read_odometer()

3.3.2 通過方法修改屬性的值

無需直接訪問屬性,可將值傳遞給一個方法,由它在內部進行更新。

class Car():
    ---snip---

    def update_odometer(self,mileage):
        self.odometer_reading = mileage

my_new_car = Car('audi','a4',2016)
print(my_new_car.get_descriptive_name())

my_new_car.update_olometer(23)
my_new_car.read_odometer()

對方法update_odometer()進行擴展,禁止將里程錶讀數往回調。

def update_odometer(self, mileage):
    """
    將里程錶讀數設置爲指定的值
    禁止將里程錶讀數往回調
    """
    if mileage >= self.odometer_reading:
        self.odometer_reading = mileage
    else:
        print("You can't roll back an odometer!")

3.3.3 通過方法對屬性的值進行遞增

e.g 將屬性值遞增特定的量,而不是將其設置爲全新的值。

假如我們購買了一輛二手車,且從購買到登記期間增加了100英里的里程。

class Car():
    ---snip---

    def update_odometer(self, mileage):
        ---snip---
    
    def increment_odometer(self,miles):
        """將里程錶讀數增加指定的量"""
        if miles >= 0:
            self.odometer_reading += miles
        else:
            print("You can't increase the minus odometer!"


my_used_car = Car('subaru','outback',2013)
print(my_used_car.get_descriptive_name())

my_used_car.update_odometer(23500)
my_used_car.read_odometer()

my_used_car.increment_odometer(100)
my_used_car.read_odometer()

四、繼承

  • 如果要編寫的類是另一個現成類的特殊版本,可以使用繼承;
  • 一個類繼承另一個類,它將自動獲得另一個類的所有屬性和方法;
  • 原有的類稱爲父類,新類稱爲子類,子類繼承了父類的所有屬性和方法,同時還可以定義自己的屬性和方法

4.1  子類的方法 __init__()

e.g 模擬電動汽車。創建一個簡單的ElecticCar類版本,具備Car類的所有功能。

class Car():
    def __init__(self, make, model, year):
        """初始化描述汽車的屬性"""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0

    def get_descriptive_name(self):
        """返回整潔的描述性信息"""
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()

    def read_odometer(self):
        """打印汽車的里程"""
        print("This car has " + str(self.odometer_reading) + " miles on it.")

    def update_odometer(self, mileage):
        """
        將里程錶讀數設置爲指定的值
        禁止將里程錶讀數往回調
        """
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")

    def increment_odometer(self, miles):
        """將里程錶讀數增加指定的量"""
        self.odometer_reading += miles


class ElectricCar(Car):
    """電動汽車的獨特之處"""
    def __init__(self, make, model, year):
        """ 初始化父類的屬性"""
        super().__init__(make,model,year)

my_tesla = ElectricCar('tesla','model s',2016)
print(my_tesla.get_descriptive_name())
  1. 創建子類時,父類必須包含在當前文件中,且位於子類的前面;
  2. 定義子類時,必須在括號內指定父類的名稱 class ElectricCar(Car);
  3. super()是一個特殊的函數,幫助Python將父類和子類關聯起來,super().__init__(make, model, year)調用父類的方法__init__(),讓ElectricCar實例包含父類的所有屬性,父類也稱爲超類(super因此得名)。

4.2 Python 2.7中的繼承

class Car(object):
    def __init__(self, make, model, year):
        ---snip---

class ElectricCar(Car):
    def __init__(self, make, model, year):
        super(ElectricCar,self).__init__(make, model, year)
        ---snip---
  • super()需要兩個實參:子類名和對象self
  • 在Python2.7中使用繼承時,務必在定義父類時在括號內指定object

4.3 給子類定義屬性和方法

讓一個類繼承另一個類後,可添加區分子類和父類所需的新屬性和方法

e.g 添加電動汽車的特有屬性(電瓶),以及一個描述該屬性的方法;存儲電瓶容量並編寫一個打印電瓶描述的方法。

class Car():
    ---snip---

class ElectricCar(Car):
    
    def __init__(self, make, model, year):
        """
        電動汽車的獨特之處
        初始化父類的屬性,再初始化電動汽車特有的屬性
        """
        super().__init__(make, model, year)
        self.battery_size = 70

    def describe_battery(self):
        """打印一條描述電瓶容量的消息"""
        print("This car has a " + str(self.battery_size) + "-kWh battery.")

my_tesla = ElectricCar('tesla','model s',2016)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery()   

4.4 重寫父類的方法

  • 對於父類的方法,只要它不符合子類模擬的實例的行爲,都可對其進行重寫;
  • 重寫,即子類中的方法與父類中的方法同名,這樣Python不會考慮父類中的這個方法,而只關注子類中定義的方法。

4.5 將實例用作屬性

可以將類的一部分作爲一個獨立的類提取出來,即將一個大型類拆分成多個協同工作的小類。

e.g 將針對汽車電瓶的屬性和方法,放到另一個類Battery()中,並將Battery實例用作ElectricCar類的一個屬性。

class Car():
    ---snip---

class Battery():
    """模擬電動汽車的電瓶"""
    def __init__(self, battery_size=70):
        self.battery_size = battery

    def describe_battery():
        print("This car has a " + str(battery_size) +"-kWh battery.")

class ElectricCar():
    
    def __init__(self, make, model, year):
        super().__init__(make, model, year)
        self.battery = Battery(80)

my_tesla = ElectricCar('Tesla','model s',2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
        

e.g 再給Battery類添加一個方法,根據其電瓶容量報告汽車的續航里程。

class Car():
    --snip--

class Battery():
    --snip--
    
    def get_range(self):
        """打印一條消息,指出電瓶的續航里程"""
        if self.battery_size == 70:
            range = 240
        elif self.battery_size ==85:
            range = 270

        message = "This car can go approximately " + str(range)
        message +=" miles on a full charge."
        print(message)

class ElectricCar(Car):
    --snip--

my_tesla = ElectricCar('Tesla','model s',2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()

五、導入類

5.1 導入單個類

可以將類Car 放在一個單獨的文件car.py中,然後使用語句:

from car import Car

導入類Car。

5.2 在一個模塊中存儲多個類

import 後加不同的類名,導入不同的類。

from car import Car
from car import ElectricCar
from car import Battery
from car import ElectricCar

my_tesla = ElectricCar('tesla','model s',2016)

print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()

5.3 從一個模塊中導入多個類

可根據需要在程序文件中導入任意數量的類,使用逗號,分隔各個類。

from car import Car,ElectricCar

5.4 導入整個模塊

使用句點表示法訪問需要的類。

import car

my_car = car.Car('audi','a4',2016)

5.5 導入模塊中的所有類

要導入模塊中的每個類,使用*

from module_name import *
  • 不建議使用這種方法,容易引發名稱錯誤
  • 需要從一個模塊導入很多類時,最好導入整個模塊,然後使用句點法來訪問類module_name.class_name

5.6 在一個模塊中導入另一個模塊

  • 有時,需要將類分散到多個模塊中,以免模塊太大,或在同一個模塊中存儲不相關的類;
  • 將類存儲在多個模塊中時,一個模塊中的類kennel依賴於另一個模塊中的類,在這種情況下就有必要在前一個模塊中導入必要的類

e.g 將Car類存儲在car.py模塊中,將ElectricCar和Battery類存儲在另一個模塊electric_car.py中。

from car import Car

class Battery():
    --snip--


class ElectricCar(Car):
    --snip--

六、Python標準庫

  • 模塊collection中的一個類OrderedDict,創建的字典與普通字典的區別是可以記錄鍵-值對的添加順序
  • 模塊random包含以各種方式生成隨機數的函數,其中randint()返回位於指定範圍內的整數。

e.g 創建一個Die類,它包含一個名爲sides的屬性,該屬性的默認值爲6,編寫一個名爲roll_die()的方法,它位於1和骰子面數之間的一個隨機數,創建一個6面的骰子,擲10次。創建一個10面和一個20面的骰子,並將他們都擲10次。

from random import randint

class Die():

    def __init__(self, sides=6):
        self.sides = sides

    def roll_die(self):
        print(str(randint(1,self.sides)))


my_die_6 = Die()
print("\n Roll Die-6:")
for i in range(0,10):
    my_die_6.roll_die()

my_die_10 = Die(10)
print("\nRoll Die-10:")
for i in range(0,10):
    my_die_10.roll_die()

my_die_20 =Die(20)
print('\nRoll Die-20:')
for i in range(0,10):
    my_die_20.roll_die()

七、類編碼風格

  • 類名採用駝峯命名法,每個單詞的首字母大寫,單詞之間不使用下劃線;實例名和模塊名採用小寫格式,單詞之間使用下劃線;
  • 類定義後包含文檔字符串簡要描述類的功能;
  • 在類中,使用一個空行分隔方法;在模塊中,使用兩個空行分隔類;
  • 需要同時導入標準庫中的模塊和自己編寫的模塊時,先編寫導入標準庫模塊的import語句,添加一個空行,再編寫導入自己編寫的模塊的import語句。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章