十八、類

面向?qū)ο缶幊淌亲钣行У能浖帉懛椒ㄖ?/p>

在面向?qū)ο缶幊讨校帉懕硎粳F(xiàn)實(shí)世界中的事物和情景的類,并基于這些類來創(chuàng)建對(duì)象,根據(jù)類來創(chuàng)建對(duì)象被稱為實(shí)例化,這讓你能夠使用類的實(shí)例;

理解面向?qū)ο缶幊逃兄谙癯绦騿T一樣看世界,還可以幫助自己明白編寫的代碼,使你與其他程序員合作更輕松。

1.1、創(chuàng)建和使用類

使用類幾乎可以模擬任何東西,類名必須大寫,一個(gè)類由方法和屬性組成,類中的函數(shù)稱為方法,可以通過實(shí)例訪問的變量稱為屬性

1.1.1、創(chuàng)建類

下面將創(chuàng)建一個(gè)dog 類,這個(gè)dog 類不是指特定的狗,而是任何的狗,對(duì)于大多數(shù)狗來說,它們都有名字和年齡,可能還會(huì)蹲下和打滾,列子如下:

# 根據(jù)dog 類創(chuàng)建的每個(gè)實(shí)例都將存儲(chǔ)名字、年齡,我們還賦予了每條狗蹲下和打滾的能力
class Dog():     # 類名必須大寫
  """一只小狗的簡單嘗試"""
  def __init__(self, name, age):  # 一個(gè)特殊的方法
    """初始化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() + ' roll over!')

上面列子中,init()方法,是一種特殊方法,包含了三個(gè)形參,self、name和age,self必不可少,而且必須在氣體形參之前,python調(diào)用這個(gè)方法時(shí),將自動(dòng)傳入實(shí)參self,每個(gè)與類關(guān)聯(lián)的方法調(diào)用都自動(dòng)傳遞實(shí)參self,它是一個(gè)指向?qū)嵗旧淼囊茫寣?shí)例能訪問類中的屬性和方法,調(diào)用Dog類的init方法時(shí),通過實(shí)參向Dog()傳遞名字和年齡,self自動(dòng)傳遞,不需要傳遞,因此只需給name和age提供值。

由一個(gè)類可以生成無數(shù)個(gè)對(duì)象,當(dāng)一個(gè)對(duì)象的方法被調(diào)用的時(shí)候,對(duì)象會(huì)將自身的引用作為第一個(gè)參數(shù)傳遞給該方法。

以self 為前綴的變量,可以供類中所有方法使用,我們可以通過類的任何實(shí)例來訪問這些變量,它們是類的屬性。

1.1.2、根據(jù)類創(chuàng)建實(shí)例

根據(jù)類可以創(chuàng)建無數(shù)個(gè)實(shí)例對(duì)象(instance object),也稱為類的實(shí)例化:

下面來創(chuàng)建一個(gè)表示特定的狗的實(shí)例對(duì)象:

class Dog():
  --snip--
  
my_dog = Dog('willie', 6)  # 類的實(shí)例化(實(shí)例對(duì)象),小寫
print("My dog's name is " + my_dog.name.title() + '.')  # 訪問類的屬性name
print('My dog is ' + str(my_name.age) + ' years old.')  # 訪問類的屬性age
------
My dog's name is willie.
My dog is 6 years old.

訪問類的屬性

要訪問類的屬性,可以使用句點(diǎn)表示法,如要訪問name的值,可以使用(my_dog.name)的方法。

調(diào)用類的方法

與訪問屬性一樣,調(diào)用方法也可以使用句點(diǎn)表示法,如要調(diào)用sit()方法,可以使用(my_dog.sit() )

class Dog():
  --snip--
  
my_dog = Dog('willie', 6)
my_dog.sit()
my_dog.roll_over()
-------------

willie is now sitting
willie rolled over!

創(chuàng)建多個(gè)實(shí)例

根據(jù)類可以創(chuàng)建任意數(shù)量的實(shí)例,條件是將每個(gè)實(shí)例都存儲(chǔ)到不同變量中,或占用列表或字典的不同位置,下面來創(chuàng)建一個(gè)名為your_dog 的實(shí)例:

class Dog():
  --snip--
  
my_dog = Dog('willie', 6)
your_dog = Dog('lucy', 3)
your_dog.sit()
---------------

lucy is now sitting.

1.2、使用類和實(shí)例

類創(chuàng)建后,大部分時(shí)間都是根據(jù)類創(chuàng)建實(shí)例,需要執(zhí)行的一個(gè)重要的任務(wù)是修改實(shí)例的屬性,修改屬性的值可以直接修改或者以特定方式修改:

1.2.1、給屬性指定默認(rèn)值

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

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.modle
    return long_name.title()
  
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
------
2016 Audi A4

接下來添加一個(gè)名為odometer_reading (里程讀取)的屬性,其初始值為0。還添加了一個(gè)read_odometer() 的方法,用于讀取汽車的里程表:

class Car():
  def __init__(self, make, model, year):
    """初始化描述汽車的屬性"""
    self.make = make
    self.model = model
    self.year = year
    self.odometer_reading = 0     # 添加一個(gè)能存儲(chǔ)汽車?yán)锍绦畔⒌膶傩裕鋵傩阅J(rèn)值為0
    
  def get_descriptive_name(self):
    """返回整車的描述信息"""
    long_name = str(self.year) + ' ' + self.make + ' ' + self.modle
    return long_name.title()
  
  def read_odometer(self):         # 增加一個(gè)讀取方法用于讀取打印汽車?yán)锍绦畔?    """打印一條信息指出汽車?yán)锍?""
    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()          # 調(diào)用read_odometer() 方法,調(diào)用self.odometer_reading 屬性的值
------
2016 Audi A4
This car has 0 miles on it.

1.2.2、修改屬性的值

修改屬性的值,有如下三種方法:

  • 直接通過實(shí)例進(jìn)行修改
  • 通過方法進(jìn)行設(shè)置
  • 通過方法進(jìn)行遞增(增加特定值)

直接修改

將里程數(shù)(odometer_reading)修改為23,直接通過實(shí)例調(diào)用屬性,修改其值:

class Car():
  --snip--
  
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23   # 通過實(shí)例調(diào)用屬性,訪問并修改其值
my_new_car.read_odometer()  # 調(diào)用方法打印里程信息
------

2016 Audi A4
This car has 23 miles on it.

通過方法修改屬性的值

如果有替你更新屬性的方法,就無需直接訪問屬性,而是將值傳遞給一個(gè)方法,由它在內(nèi)部進(jìn)行更新。

下面添加一個(gè)名為update_odometer() 的方法,其中有一個(gè)形參,用于接收里程數(shù):

class Car():
  --snip--
  
def update_odometer(self, mileage):  # 定義一個(gè)方法,用于內(nèi)部更新屬性odometer_reading 的值,其中一個(gè)形參用于接收里程數(shù),并將其指定為屬性odometer_reading
  """將里程數(shù)讀數(shù)設(shè)置為指定值"""
  """禁止里程往回?fù)?""
  if mileage >= odometer_reading:  # 修改屬性前,檢查指定的數(shù)是否合理
    self.odometer_reading = mileage
  else:
    print("You can't roll back an odometer!")
  
  
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.update_odometer(32)  # 調(diào)用方法,并傳遞值32給形參mileage
my_new_car.read_odometer()
------------

2016 Audi A4
This car has 32 miles on it.

通過方法對(duì)屬性的值進(jìn)行遞增

有時(shí)需要將屬性值遞增特定的值,而不是設(shè)置為全新的值,比如買了一輛二手車,從購買到登記期間增加了100英里的里程:

class Car():
  --snip--
  def update_odometer(self, mileage):
    --snip--
    
  def increment_odometer(self, miles):  # 新增方法,接受一個(gè)單位為英里的數(shù)字,并將其存儲(chǔ)到屬性self.odometer_reading中
    """將里程表讀數(shù)增加特定的量"""
    self.odometer_reading += miles
    
my_used_car = Car('subaru', 'outback', 2013)
print(my_used_car.get_rescriptive_name())

my_used_car.update_odometer(23500)
my_used_car.read_odometer()

my_used_car.increment_odometer(100)
my_used_car.read_odometer()

------
2013 Subaru Outback
This car has 23500 miles on it.
This car has 23600 miles on it.

練習(xí)

添加一個(gè)屬性number_served,默認(rèn)值為0,創(chuàng)建一個(gè)名為restaurant 的實(shí)例,打印這家餐館有多少人在這家餐館就餐,然后修改這個(gè)值并打印它,添加一個(gè)名為set_number_served() 的方法,它能設(shè)置就餐人數(shù),調(diào)用它傳遞一個(gè)值,再打印這個(gè)值,添加一個(gè)名為increment_number_served() 的方法,它讓你能夠?qū)⒕筒腿藬?shù)遞增,調(diào)用它并傳遞一個(gè)這樣的值:你認(rèn)為這家餐館每天可能接待的就餐人數(shù):

class Restaurant():
    """創(chuàng)建一個(gè)Restaurant的類,里面包含餐廳名字,菜品類型"""
    def __init__(self, restaurant_name, cuisine_type):
        self.restaurant_name = restaurant_name.title()
        self.cuisine_type = cuisine_type
        self.number_served = 0

    def describe(self):
        """顯示餐館的基本信息"""
        msg = self.restaurant_name + ' serves wonderful ' + self.cuisine_type + '.'
        print(msg)

    def open_restaurant(self):
        """顯示餐館正在營業(yè)"""
        msg = self.restaurant_name + ' is open. Come on in!'
        print(msg + '\n')

    def set_number_served(self, number_served):
      """顯示就餐人數(shù)"""
        self.number_served = number_served

    def increment_nums(self, additional_served):
      """人數(shù)遞增"""
        self.number_served += additional_served


restaurant = Restaurant("alice's home", 'pizza')
restaurant.describe()
restaurant.open_restaurant()

restaurant.set_number_served(16)
print('The current number of repast is ' + str(restaurant.number_served))

restaurant.increment_nums(10)
print('The current number of repast is ' + str(restaurant.number_served))


------------------
Alice'S Home serves wonderful pizza.
Alice'S Home is open. Come on in!

The current number of repast is 16
The current number of repast is 26

1.3、繼承

編寫類時(shí),不是都是從空白開始,有時(shí)要編寫的類是另一個(gè)現(xiàn)成的類的特殊版本,可使用繼承。一個(gè)類繼承另一個(gè)類時(shí),它將自動(dòng)獲得另一個(gè)類的所有屬性和方法,被繼承的類稱為基類或父類,繼承的類稱為子類,子類也可以定義自己的屬性和方法。

下面我們來創(chuàng)建一個(gè)名為 ElectricCar()的子類,繼承于父類Car(),用來描述電動(dòng)汽車的相關(guān)信息,它具備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_time = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_time.title()

    def read_odometer(self):
        print('This car has ' + str(self.odometer_reading) + ' miles on it.')

    def update_odometer(self, mileage):
        """將里程表讀數(shù)設(shè)置為指定的數(shù)"""
        self.odometer_reading = mileage

    def increment_odometer(self, miles):
        self.odometer_reading += miles


class ElectricCar(Car):         # 子類,定義子類時(shí),括號(hào)內(nèi)必須指定父類名稱
    """電動(dòng)車的獨(dú)特之處"""

    def __init__(self, make, model, year):  # 方法__init__()接受創(chuàng)建父類實(shí)例所需信息
        """初始化父類的屬性"""
        super().__init__(make, model, year) # super()是一個(gè)特殊函數(shù),可以將父類與子類關(guān)聯(lián)起來,它可以讓python調(diào)用父類的方法__init__(),讓子類實(shí)例包含父類的所有屬性,父類也稱為超類(superclass)


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

2016 Tesla Model S

上面例子,我們首先定一個(gè)名為ElectricCar的子類,它繼承父類Car,創(chuàng)建子類時(shí),父類必須在子類之前,定義子類時(shí)括號(hào)內(nèi)必須指定父類名稱,方法init() 接受Car實(shí)例所需的信息(初始化父類的所有屬性和方法)。

super()函數(shù)是一個(gè)特殊函數(shù),幫助python將父類與子類關(guān)聯(lián)起來,自動(dòng)找到父類的方法,不需要給出父類的名字,這行代碼讓python調(diào)用父類的方法init(),讓子類實(shí)例包含父類的所有屬性。

為子類創(chuàng)建一個(gè)實(shí)例對(duì)象my_tesla,傳入實(shí)參,它將調(diào)用子類的init() 方法,子類的init() 方法將調(diào)用父類的init() 方法。

1.3.1、給子類定義屬性和方法

繼承后,可以添加區(qū)分子類和父類所需的新屬性和方法,需要注意的是,子類可以添加任意數(shù)量的屬性和方法,但只適用子類,如果要適用子類和父類,那么應(yīng)該添加到父類中。

下面為子類ElectricCar 添加一個(gè)電動(dòng)汽車特有的屬性(電瓶),以及一個(gè)描述該屬性的方法,存儲(chǔ)電瓶的容量,并編寫一個(gè)打印電瓶描述的方法:

class Car():
  --snip--
  
class ElectricCar(Car):
  """"""
  def __init__(self, make, model, year):
    """"""
    super().__init__(make, model, year)
    self.battery_size = 70   # 添加新屬性存儲(chǔ)電瓶容量,初始值為70
    
  def describe_battery(self):  # 定一個(gè)方法,用于描述打印這輛車的電瓶容量信息
    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()  # 調(diào)用方法describe_battery()
------------------------

Tesla Model S 2016
This car has a 70-kwh battery.

1.3.2、重寫父類的方法

如果父類的方法不能滿足子類的需求,可以對(duì)其進(jìn)行重寫,為此可以在子類中定一個(gè)方法,與要重寫的父類方法同名,這樣python 就不會(huì)考慮這個(gè)父類的方法,而只關(guān)注這個(gè)子類中定義的相應(yīng)方法。

假設(shè)Car類有一個(gè)名為fill_gas_tank()的方法,它對(duì)電動(dòng)汽車來說沒有意義,因此你可能需要重寫它:

class Car():
  --snip--
  def fill_gas_tank(self):
    print('This car has a gas tank.')
    
class ElectricCar(Car):
  --snip--
  def fill_gas_tank(self):               # 重寫父類方法fill_gas_tank(),因?yàn)楦割惖姆椒ú荒軡M足子類
    """電動(dòng)車沒有油箱"""
    print("This car doesn't need a gas tank!")
 
my_tesla = ElectricCar('tesla', 'model s' 2016)
my_new_car = Car('audi', 'a4', 2016)
my_tesla.fill_gas_tank()                # 父類的方法一旦被重寫,父類的實(shí)例調(diào)用被重寫的方法也會(huì)被忽略
my_new_car.fill_gas_tank()
------------------

This car doesn't need a gas tank!
This car doesn't need a gas tank!

1.3.3、將實(shí)例用作屬性

使用代碼模擬實(shí)物時(shí),你可能會(huì)給類添加越來越多的細(xì)節(jié),屬性和方法以及文件越來越長,這種情況下可能需要將類的一部分作為一個(gè)獨(dú)立的類提取出來,拆分成多個(gè)協(xié)同工作的小類。

給ElectricCar 類添加細(xì)節(jié),可能會(huì)包含很多專門對(duì)汽車電瓶的屬性和方法,可以將這些屬性和方法提取出來,放到另外一個(gè)名為Battery的類中,并將Battery實(shí)例用作ElectricCar類的一個(gè)屬性:

class Car():
  --snip--
  
class Battery():          # 定義一個(gè)新類,用于存儲(chǔ)ElectricCar的屬性和方法
  """一次模擬電動(dòng)汽車電瓶的簡單嘗試"""
  def __init__(self, battery_size=70):  # 設(shè)置電瓶容量初始值
    """初始化電瓶的屬性"""
    self.battery_size = battery_size
    
  def describe_battery(self):
    """打印一條描述電瓶容量的消息"""
    print('This car has a ' + str(self.battery_size) + '-kwh battery.')
    
class ElectricCar(Car):
  """電動(dòng)車的獨(dú)特之處"""
  
  def __init__(self, make, model, year):
    """初始化父類的屬性,再初始化電動(dòng)車的特有屬性"""
    super().__init__(make, model, year)
    self.battery = Battery()  # 這行代碼讓python創(chuàng)建了一個(gè)新的Battery實(shí)例(由于沒有指定參數(shù),默認(rèn)值為70),并將實(shí)例存儲(chǔ)在屬性self.battert中,每當(dāng)__init__()被調(diào)用時(shí),都將執(zhí)行該操作
    
my_tesla = ElectricCar('tesla', 'model s', 2016)

print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery() # 調(diào)用時(shí)采用ElectricCar的實(shí)例加Battery實(shí)例的方式調(diào)用Battery中的方法
-------------------

2016 Tesla Model S
This car has a 70-kwh battery.

把子類拆分成很多小類去協(xié)同處理,看似多了很多步驟,但是可以避免子類混亂不堪,現(xiàn)在我們可以去拓展電動(dòng)汽車的其他信息,比如描述電瓶容量的續(xù)航里程,在Battery中添加一個(gè)名為get_range ()的方法,用于描述續(xù)航里程:

class Car():
  --snip--
  
class Battery():
  --snip--
  def get_range(self):        # 定義一個(gè)方法,用于描述打印電瓶續(xù)航里程信息
    if self.battery_size == 70:
      range = 240
    elif self.battery_size == 85:
      range = 270
    
    msg = 'This car can go approximately ' + str(range)
    msg += ' miles on a full charge.'
    print(msg)
    
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()   # 調(diào)用get_battery() 方法
----------------

2016 Tesla Model S
This car has a 70-kwh battery.
This car can go approximately 240 miles on a full charge.

1.4、導(dǎo)入類

隨著我們給類不斷添加功能,代碼、文件越來越長,為遵循python的總體理念,應(yīng)讓文件盡可能簡潔,為此我們可以將類存儲(chǔ)到模塊中,然后在主程序中導(dǎo)入所需的模塊即可。

1.4.1、導(dǎo)入單個(gè)類

上面我們舉例寫了一個(gè)Car類,現(xiàn)在我們把它放到一個(gè)名為car.py的文件中(模塊),再新建一個(gè)my_car.py 的文件,我們?cè)趍y_car.py 中導(dǎo)入Car 類試試:

# car.py
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):
        """將里程表讀數(shù)設(shè)置為指定的值"""
        """拒絕將里程表回?fù)?""
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print('You can not roll back an odometer!')

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


class Battery():
    """一次模擬電動(dòng)汽車電瓶的簡單嘗試"""

    def __init__(self, battery_size=70):
        """初始化電瓶的屬性"""
        self.battery_size = battery_size

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

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

        msg = 'This car can go approximately ' + str(range_0)
        msg += ' miles on a full charge.'
        print(msg)


class ElectricCar(Car):
    """電動(dòng)車的獨(dú)特之處"""

    def __init__(self, make, model, year):
        """初始化父類的屬性,再初始化子類的屬性"""
        super().__init__(make, model, year)
        self.battery = Battery()
# my_car.py                       
from car import Car                          # 從模塊car.py中導(dǎo)入Car 類

my_new_car = Car('audi', 'a4', 2016)          # Car 類實(shí)例化,傳入?yún)?shù)
print(my_new_car.get_descriptive_name())

my_new_car.odometer_reading = 23
my_new_car.read_odometer()

--------------------
2016 Audi A4
This car has 23 miles on it.

1.4.2、從一個(gè)模塊中導(dǎo)入多個(gè)類

一個(gè)模塊可以存儲(chǔ)多個(gè)類,我們可以一次導(dǎo)入一個(gè)或者多個(gè)類到主程序中,

導(dǎo)入多個(gè)類時(shí),類之間用逗號(hào)分隔即可,導(dǎo)入后即可根據(jù)類創(chuàng)建任意數(shù)量的實(shí)例。

如果我們要在同一個(gè)程序中創(chuàng)建普通汽車和電動(dòng)汽車,就需要將Car 和 ElectricCar 類都導(dǎo)入:

# my_car.py
from car import Car, ElectricCar  # 從模塊car.py中導(dǎo)入Car和ElectricCar 類

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

my_new_car.odometer_reading = 23
my_new_car.read_odometer()

my_tesla = ElectricCar('tesla', 'model s', 2016)
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()

1.4.3、導(dǎo)入整個(gè)模塊

也可以導(dǎo)入整個(gè)模塊,再使用句點(diǎn)表示法訪問所需要的類,這種方法,代碼易讀,也不會(huì)與當(dāng)前文件使用的任何名稱發(fā)生沖突:

# my_car.py
import car

my_new_car = car.Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
------------------
2016 Audi A4

1.4.4、導(dǎo)入模塊中所有類

# 語法
from module_name import *

不推薦使用這種方法導(dǎo)入模塊中所有類,這樣容易導(dǎo)致名稱方面的困惑,引發(fā)難以診斷的錯(cuò)誤,應(yīng)使用導(dǎo)入模塊名,再采用句點(diǎn)表示法的方法訪問。

1.4.5、在一個(gè)模塊中導(dǎo)入另一個(gè)模塊

有時(shí)需要將類分散到多個(gè)模塊中,以免模塊太大,或在同一模塊中存儲(chǔ)不相關(guān)的類,將類存儲(chǔ)到多個(gè)模塊中時(shí),你可能會(huì)發(fā)現(xiàn)一個(gè)模塊中的類依賴與另一個(gè)模塊中的類,這種情況下,可在前一個(gè)模塊中導(dǎo)入必要的類。

下面,我們將Car 類存儲(chǔ)到模塊car.py 中,將Battery和 ElectricCar 類存儲(chǔ)到模塊 electric_car.py 中,在調(diào)用ElectricCar 類時(shí)需要依賴Car 類,因此我們可以在electric_car.py 中導(dǎo)入car.py。

# electric_car.py
"""一組可用于表示電動(dòng)汽車的類"""

from car import Car       # ElectricCar需要訪問其父類,因此我們直接將Car類導(dǎo)入到該模塊中

class Battery():
  --snip--
class ElectricCar():
  --snip--
# my_car.py             # 在my_car模塊中導(dǎo)入car和electric_car 模塊
from car import Car
from electric_car import ElectricCar

1.5、Python標(biāo)準(zhǔn)庫

Python標(biāo)準(zhǔn)庫是一組模塊,安裝的python都包含它,現(xiàn)在對(duì)類有一定的了解,可以使用其他程序員編寫好的模塊,以及標(biāo)準(zhǔn)庫中的任何函數(shù)和類,為此只需一句在程序中包含一條簡單的imp 語句,下面來看模塊collections中的一個(gè)類-----OrdereDict

OrdereDict 實(shí)例行為與字典幾乎一致,區(qū)別在于它記錄了添加鍵-值對(duì)的添加順序,而字典不能。

# favorite_language.py
from collections import OrderedDict

favorite_languages = OrderedDict()

favorite_languages['jen'] = 'Python'
favorite_languages['sarah'] = 'c'
favorite_languages['edward'] = 'ruby'
favorite_languages['phil'] = 'java'

for name, languages in favorite_languages.items():
    print(name.title() + "'s favorite language is " + languages.title() + '.')
----------------------------

Jen's favorite language is Python.
Sarah's favorite language is C.
Edward's favorite language is Ruby.
Phil's favorite language is Java.

1.6、類編碼風(fēng)格

與類有關(guān)的編碼風(fēng)格問題,在編寫復(fù)雜程序更應(yīng)遵循:

  • 類名:駝峰式命名法(如ElectricCar),即首字母大寫,而不是用下劃線
  • 實(shí)例名:小寫格式,單詞間使用下劃線
  • 每個(gè)類都應(yīng)包含一個(gè)文檔字符串,用于描述類的功能,每個(gè)模塊也應(yīng)有。
  • 空行:可用來組織代碼,但不應(yīng)濫用,類中,一個(gè)空行分隔方法,模塊中,兩個(gè)空行分隔類。
  • 需要同時(shí)導(dǎo)入標(biāo)準(zhǔn)庫中的模塊和你編寫的模塊時(shí),先編寫導(dǎo)入標(biāo)準(zhǔn)庫的import 語句,再添加一個(gè)空行,然后在編寫導(dǎo)入你自己編寫的模塊的import 語句,在包含多條import 語句的程序中,這種做法讓人更容易明白程序使用的各個(gè)模塊來自何方。

練習(xí)

模塊random 包含以各種方式生成隨機(jī)數(shù)的函數(shù),其中randint()返回一個(gè)位于指定范圍內(nèi)的整數(shù),創(chuàng)建一個(gè)Die 類,包含一個(gè)名為sides 的屬性,默認(rèn)值為6,編寫一個(gè)名為 roll_die()的方法,它打印位于1和骰子面數(shù)之間的隨機(jī)數(shù),創(chuàng)建一個(gè)6 面、10面、20面的骰子,再分別擲 10 次:

from random import randint        # 導(dǎo)入random 模塊以及randint 函數(shù)

class Die():
  def __init__(self, sides=6):
    self.sides = sides
  
  def roll_die(self):
    return randit(1, self.sides)   # 返回生成1 到self.sides 間的隨機(jī)數(shù),不傳入?yún)?shù)就使用默認(rèn)值 6
  
d_6 = Die()                      # Die 類實(shí)例化,6 面骰子拋擲10次

results = []                                       # 將結(jié)果存儲(chǔ)到 results 列表中
for roll_num in range(10):
  result = d_6.roll_die()
  results.append(result)
print('10 rolls of a 6-sided die:')
print(results)

d_10 = Die(sides=10)             # 10 面骰子

results = []
for roll_num in range(10):
    result = d_10.roll_die()
    results.append(result)
print('10 rolls of a 6-sided die:')
print(results)


d_20 = Die(sides=20)                     # 20 面骰子

results = []
for roll_num in range(10):
    result = d_10.roll_die()
    results.append(result)
print('10 rolls of a 6-sided die:')
print(results)
--------------------

10 rolls of a 6-sided die:
[4, 1, 1, 1, 5, 5, 2, 2, 3, 4]
10 rolls of a 6-sided die:
[5, 2, 2, 3, 9, 4, 2, 7, 10, 8]
10 rolls of a 6-sided die:
[1, 19, 5, 18, 19, 19, 8, 10, 8, 10]
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容