十八、類(lèi)

類(lèi)

面向?qū)ο缶幊淌亲钣行У能浖帉?xiě)方法之一

在面向?qū)ο缶幊讨械咔帉?xiě)表示現(xiàn)實(shí)世界中的事物和情景的類(lèi)削锰,并基于這些類(lèi)來(lái)創(chuàng)建對(duì)象,根據(jù)類(lèi)來(lái)創(chuàng)建對(duì)象被稱(chēng)為實(shí)例化毕莱,這讓你能夠使用類(lèi)的實(shí)例器贩;

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

1.1部服、創(chuàng)建和使用類(lèi)

使用類(lèi)幾乎可以模擬任何東西唆姐,類(lèi)名必須大寫(xiě)瘫想,一個(gè)類(lèi)由方法和屬性組成,類(lèi)中的函數(shù)稱(chēng)為方法,可以通過(guò)實(shí)例訪(fǎng)問(wèn)的變量稱(chēng)為屬性

1.1.1瑞眼、創(chuàng)建類(lèi)

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

# 根據(jù)dog 類(lèi)創(chuàng)建的每個(gè)實(shí)例都將存儲(chǔ)名字黍特、年齡,我們還賦予了每條狗蹲下和打滾的能力
class Dog():     # 類(lèi)名必須大寫(xiě)
  """一只小狗的簡(jiǎn)單嘗試"""
  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è)與類(lèi)關(guān)聯(lián)的方法調(diào)用都自動(dòng)傳遞實(shí)參self傅蹂,它是一個(gè)指向?qū)嵗旧淼囊茫寣?shí)例能訪(fǎng)問(wèn)類(lèi)中的屬性和方法算凿,調(diào)用Dog類(lèi)的init方法時(shí)份蝴,通過(guò)實(shí)參向Dog()傳遞名字和年齡,self自動(dòng)傳遞氓轰,不需要傳遞婚夫,因此只需給name和age提供值。

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

以self 為前綴的變量,可以供類(lèi)中所有方法使用时捌,我們可以通過(guò)類(lèi)的任何實(shí)例來(lái)訪(fǎng)問(wèn)這些變量怒医,它們是類(lèi)的屬性。

1.1.2奢讨、根據(jù)類(lèi)創(chuàng)建實(shí)例

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

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

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

訪(fǎng)問(wèn)類(lèi)的屬性

要訪(fǎng)問(wèn)類(lèi)的屬性,可以使用句點(diǎn)表示法拿诸,如要訪(fǎng)問(wèn)name的值扒袖,可以使用(my_dog.name)的方法。

調(diào)用類(lèi)的方法

與訪(fǎng)問(wèn)屬性一樣佳镜,調(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ù)類(lèi)可以創(chuàng)建任意數(shù)量的實(shí)例蟀伸,條件是將每個(gè)實(shí)例都存儲(chǔ)到不同變量中,或占用列表或字典的不同位置缅刽,下面來(lái)創(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啊掏、使用類(lèi)和實(shí)例

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

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

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

class Car():
  def __init__(self, make, model, year):
    """初始化描述汽車(chē)的屬性"""
    self.make = make
    self.model = model
    self.year = year
    
  def get_descriptive_name(self):
    """返回整車(chē)的描述信息"""
    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

接下來(lái)添加一個(gè)名為odometer_reading (里程讀日险)的屬性,其初始值為0徐鹤。還添加了一個(gè)read_odometer() 的方法垃环,用于讀取汽車(chē)的里程表:

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

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

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

直接修改

將里程數(shù)(odometer_reading)修改為23劲赠,直接通過(guò)實(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   # 通過(guò)實(shí)例調(diào)用屬性只磷,訪(fǎng)問(wèn)并修改其值
my_new_car.read_odometer()  # 調(diào)用方法打印里程信息
------

2016 Audi A4
This car has 23 miles on it.

通過(guò)方法修改屬性的值

如果有替你更新屬性的方法,就無(wú)需直接訪(fǎng)問(wèn)屬性泌绣,而是將值傳遞給一個(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.

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

有時(shí)需要將屬性值遞增特定的值甥角,而不是設(shè)置為全新的值,比如買(mǎi)了一輛二手車(chē)识樱,從購(gòu)買(mǎi)到登記期間增加了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的類(lèi)奠支,里面包含餐廳名字,菜品類(lèi)型"""
    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íng)業(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涌献、繼承

編寫(xiě)類(lèi)時(shí)胚宦,不是都是從空白開(kāi)始,有時(shí)要編寫(xiě)的類(lèi)是另一個(gè)現(xiàn)成的類(lèi)的特殊版本燕垃,可使用繼承枢劝。一個(gè)類(lèi)繼承另一個(gè)類(lèi)時(shí),它將自動(dòng)獲得另一個(gè)類(lèi)的所有屬性和方法卜壕,被繼承的類(lèi)稱(chēng)為基類(lèi)或父類(lèi)您旁,繼承的類(lèi)稱(chēng)為子類(lèi),子類(lèi)也可以定義自己的屬性和方法轴捎。

下面我們來(lái)創(chuàng)建一個(gè)名為 ElectricCar()的子類(lèi)鹤盒,繼承于父類(lèi)Car()蚕脏,用來(lái)描述電動(dòng)汽車(chē)的相關(guān)信息,它具備Car類(lèi)的所有功能:

class Car():                        # 父類(lèi)
    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):         # 子類(lèi)侦锯,定義子類(lèi)時(shí)驼鞭,括號(hào)內(nèi)必須指定父類(lèi)名稱(chēng)
    """電動(dòng)車(chē)的獨(dú)特之處"""

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


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

2016 Tesla Model S

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

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

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

1.3.1访诱、給子類(lèi)定義屬性和方法

繼承后垫挨,可以添加區(qū)分子類(lèi)和父類(lèi)所需的新屬性和方法,需要注意的是触菜,子類(lèi)可以添加任意數(shù)量的屬性和方法九榔,但只適用子類(lèi),如果要適用子類(lèi)和父類(lèi)涡相,那么應(yīng)該添加到父類(lèi)中哲泊。

下面為子類(lèi)ElectricCar 添加一個(gè)電動(dòng)汽車(chē)特有的屬性(電瓶),以及一個(gè)描述該屬性的方法催蝗,存儲(chǔ)電瓶的容量切威,并編寫(xiě)一個(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è)方法丙号,用于描述打印這輛車(chē)的電瓶容量信息
    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先朦、重寫(xiě)父類(lèi)的方法

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

假設(shè)Car類(lèi)有一個(gè)名為fill_gas_tank()的方法涮拗,它對(duì)電動(dòng)汽車(chē)來(lái)說(shuō)沒(méi)有意義,因此你可能需要重寫(xiě)它:

class Car():
  --snip--
  def fill_gas_tank(self):
    print('This car has a gas tank.')
    
class ElectricCar(Car):
  --snip--
  def fill_gas_tank(self):               # 重寫(xiě)父類(lèi)方法fill_gas_tank(),因?yàn)楦割?lèi)的方法不能滿(mǎn)足子類(lèi)
    """電動(dòng)車(chē)沒(méi)有油箱"""
    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()                # 父類(lèi)的方法一旦被重寫(xiě)迂苛,父類(lèi)的實(shí)例調(diào)用被重寫(xiě)的方法也會(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ì)給類(lèi)添加越來(lái)越多的細(xì)節(jié)三幻,屬性和方法以及文件越來(lái)越長(zhǎng)就漾,這種情況下可能需要將類(lèi)的一部分作為一個(gè)獨(dú)立的類(lèi)提取出來(lái),拆分成多個(gè)協(xié)同工作的小類(lèi)念搬。

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

class Car():
  --snip--
  
class Battery():          # 定義一個(gè)新類(lèi),用于存儲(chǔ)ElectricCar的屬性和方法
  """一次模擬電動(dòng)汽車(chē)電瓶的簡(jiǎn)單嘗試"""
  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)車(chē)的獨(dú)特之處"""
  
  def __init__(self, make, model, year):
    """初始化父類(lèi)的屬性爷恳,再初始化電動(dòng)車(chē)的特有屬性"""
    super().__init__(make, model, year)
    self.battery = Battery()  # 這行代碼讓python創(chuàng)建了一個(gè)新的Battery實(shí)例(由于沒(méi)有指定參數(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.

把子類(lèi)拆分成很多小類(lèi)去協(xié)同處理,看似多了很多步驟栈虚,但是可以避免子類(lèi)混亂不堪袖外,現(xiàn)在我們可以去拓展電動(dòng)汽車(chē)的其他信息,比如描述電瓶容量的續(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)入類(lèi)

隨著我們給類(lèi)不斷添加功能鬓照,代碼、文件越來(lái)越長(zhǎng)相艇,為遵循python的總體理念颖杏,應(yīng)讓文件盡可能簡(jiǎn)潔,為此我們可以將類(lèi)存儲(chǔ)到模塊中坛芽,然后在主程序中導(dǎo)入所需的模塊即可留储。

1.4.1翼抠、導(dǎo)入單個(gè)類(lèi)

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

# car.py
class Car():
    def __init__(self, make, model, year):
        """初始化汽車(chē)屬性"""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0

    def get_descriptive_name(self):
        """返回整車(chē)的描述性名稱(chēng)"""
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()

    def read_odometer(self):
        """打印一條信息,指出汽車(chē)的里程"""
        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)汽車(chē)電瓶的簡(jiǎn)單嘗試"""

    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)車(chē)的獨(dú)特之處"""

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

my_new_car = Car('audi', 'a4', 2016)          # Car 類(lèi)實(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è)類(lèi)

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

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

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

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

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)表示法訪(fǎng)問(wèn)所需要的類(lèi),這種方法蒲犬,代碼易讀朱监,也不會(huì)與當(dāng)前文件使用的任何名稱(chē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)入模塊中所有類(lèi)

# 語(yǔ)法
from module_name import *

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

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

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

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

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

from car import Car       # ElectricCar需要訪(fǎng)問(wèn)其父類(lèi)牛隅,因此我們直接將Car類(lèi)導(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)庫(kù)

Python標(biāo)準(zhǔn)庫(kù)是一組模塊,安裝的python都包含它媒佣,現(xiàn)在對(duì)類(lèi)有一定的了解匕累,可以使用其他程序員編寫(xiě)好的模塊,以及標(biāo)準(zhǔn)庫(kù)中的任何函數(shù)和類(lèi)默伍,為此只需一句在程序中包含一條簡(jiǎn)單的imp 語(yǔ)句欢嘿,下面來(lái)看模塊collections中的一個(gè)類(lèi)-----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、類(lèi)編碼風(fēng)格

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

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

練習(xí)

模塊random 包含以各種方式生成隨機(jī)數(shù)的函數(shù)屏鳍,其中randint()返回一個(gè)位于指定范圍內(nèi)的整數(shù),創(chuàng)建一個(gè)Die 類(lèi)局服,包含一個(gè)名為sides 的屬性钓瞭,默認(rèn)值為6,編寫(xiě)一個(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 類(lèi)實(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)系作者
  • 序言:七十年代末系吩,一起剝皮案震驚了整個(gè)濱河市来庭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌穿挨,老刑警劉巖月弛,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異科盛,居然都是意外死亡帽衙,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)贞绵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)厉萝,“玉大人,你說(shuō)我怎么就攤上這事榨崩∏吹妫” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵母蛛,是天一觀的道長(zhǎng)翩剪。 經(jīng)常有香客問(wèn)我,道長(zhǎng)彩郊,這世上最難降的妖魔是什么前弯? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮秫逝,結(jié)果婚禮上恕出,老公的妹妹穿的比我還像新娘。我一直安慰自己违帆,他們只是感情好浙巫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著前方,像睡著了一般狈醉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惠险,一...
    開(kāi)封第一講書(shū)人閱讀 51,182評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音抒线,去河邊找鬼班巩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的抱慌。 我是一名探鬼主播逊桦,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼抑进!你這毒婦竟也來(lái)了强经?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤寺渗,失蹤者是張志新(化名)和其女友劉穎匿情,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體信殊,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡炬称,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了涡拘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片玲躯。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖鳄乏,靈堂內(nèi)的尸體忽然破棺而出跷车,到底是詐尸還是另有隱情,我是刑警寧澤橱野,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布姓赤,位于F島的核電站,受9級(jí)特大地震影響仲吏,放射性物質(zhì)發(fā)生泄漏不铆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一裹唆、第九天 我趴在偏房一處隱蔽的房頂上張望誓斥。 院中可真熱鬧,春花似錦许帐、人聲如沸劳坑。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)距芬。三九已至,卻和暖如春循帐,著一層夾襖步出監(jiān)牢的瞬間框仔,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工拄养, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留离斩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像跛梗,于是被迫代替她去往敵國(guó)和親寻馏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

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