零基礎學習python_類和對象(36-40課)


  今天我們開始學習面向對象的知識咯,之前我對面向對象也學的懵懵的,因為感覺知道好像又不是特別清楚,接下來我們一起來學習類和對象吧。零基礎的課程我都是看小甲魚的視頻學的,沒基礎的可以去這個網址下載視頻學習:http://blog.fishc.com/category/python

  好了,我們開始進行學習吧,我們先來思考下,對象是什么?拋開程序代碼,我們想一下如果人是一個對象,那么這個對象有什么呢?

  你是不是會說這個人長得怎么樣,眼睛咋樣,身高多少,對這個人的外貌特征進行描述,那么這個人能干什么呢?是不是能吃飯、走路、說話等。

  那么你想下對於人這個對象來說是不是有特征和行為這兩大特性呢?那么對於程序來說對象也是如此,對象 = 屬性 + 方法

下面就是第一個實例,有屬性和方法,注意:類的名稱第一個字母為大寫,函數為小寫(約定俗成的習慣吧!)

#coding = utf-8
class Person:  #無括號是舊的書寫方式,有括號是新的書寫方式
    '''第一個簡單類實例_人'''
    height = 180    #屬性,是不是很像變量
    weight = 70

#下面是方法 def run(self):    #是不是就是一個個函數呢? print('我跑啊跑啊跑。。。') def sing(self): print('我唱歌唱啊唱啊。。。')

 下面是類的實例化,很簡單的,直接賦值給一個變量,就可以通過變量來調用內的不同方法了

面向對象的特征:

  • 封裝:對外部隱藏對象的工作細節
  • 繼承:子類自動共享父類之間的數據和方法的機制
  • 多態:可以對不同類的對象調用相同的方法,產生不同的結果

 你可能發現上面定義類的時候函數的括號里面都有self這個東東,那這個是啥呢?

舉個例子大家看下:

class Test():
    def __init__(self,name):   #構造函數
        self.name = name   #name傳入后賦值
    
    def run(self):
        print('%s 在跑。。。。'%self.name)  #對name進行調用,記得寫self不然不知道你要調用的name在哪里

調用結果如下:

對於同一個類,那么我在調用的時候怎么區別是誰調的呢?self就是幫你解決這件事情的,self就是指的自己,也就是說是誰實例化的呢?a=Test就等同於Test(a),所以這個是不可缺少的,當前你可以不用self,可以用任意英文代替,不過大家都統一的事情你還是默認這樣寫吧。

類里面也有公有和私有之分,像我們之前看到的變量都是公有的,私有變量的話需要在變量前加入雙下划線“__”,這樣外面就不能調用了,當然實際上也是可以的,舉個例子看看吧。

其實__變量雖然訪問不到,但是也可以通過“_類__變量”進行訪問

 下面給個題目大家做一下,我剛開始沒做出來,感覺有點難,后面看了下答案覺得還好,大家可以想一下:

 

答案如下:

import random as r

legal_x = [0,10]
legal_y = [0,10]

class Turtle:
    def __init__(self):
        #初始體力
        self.power = 100

        #初始位置隨機
        self.x = r.randint(legal_x[0],legal_x[1])
        self.y = r.randint(legal_y[0],legal_y[1])

    def move(self):
        #隨機計算方向並移動到新的位置(x,y)
        new_x = self.x + r.choice([1,2,-1,-2])
        new_y = self.y + r.choice([1,2,-1,-2])

        #檢查移動后是否超出場景x軸邊界
        if new_x < legal_x[0]:
            self.x = legal_x[0] - (new_x - legal_x[0])
        elif new_x > legal_x[1]:
            self.x = legal_x[1] - (new_x - legal_x[1])
        else:
            self.x = new_x

        #檢查移動后是否超出場景y軸邊界
        if new_y < legal_y[0]:
            self.y = legal_y[0] - (new_y - legal_y[0])
        elif new_y > legal_y[1]:
            self.y = legal_y[1] - (new_y - legal_y[1])
        else:
            self.y = new_y

        #體力消耗
        self.power -= 1

        #返回移動后的新位置
        return(self.x, self.y)

    def eat(self):
        self.power += 20
        if self.power > 100:
            self.power = 100

class Fish:
    def __init__(self):
        #初始位置隨機
        self.x = r.randint(legal_x[0],legal_x[1])
        self.y = r.randint(legal_y[0],legal_y[1])

    def move(self):
        #隨機計算方向並移動到新的位置(x,y)
        new_x = self.x + r.choice([1,-1])
        new_y = self.y + r.choice([1,-1])

        #檢查移動后是否超出場景x軸邊界
        if new_x < legal_x[0]:
            self.x = legal_x[0] - (new_x - legal_x[0])
        elif new_x > legal_x[1]:
            self.x = legal_x[1] - (new_x - legal_x[1])
        else:
            self.x = new_x

        #檢查移動后是否超出場景y軸邊界
        if new_y < legal_y[0]:
            self.y = legal_y[0] - (new_y - legal_y[0])
        elif new_y > legal_y[1]:
            self.y = legal_y[1] - (new_y - legal_y[1])
        else:
            self.y = new_y

        #返回移動后的新位置
        return(self.x, self.y)


turtle = Turtle()

fish = []

for i in range(10):
    new_fish = Fish()
    fish.append(new_fish)


while True:
    if not len(fish):
        print("魚兒都吃完了,游戲結束!")
        break
    if not turtle.power:
        print("烏龜體力耗盡,掛掉了!")
        break

    pos = turtle.move()


    for each_fish in fish[:]:
        if each_fish.move() == pos:
            #魚兒被吃掉了
            fish.remove(each_fish)
            turtle.eat()       

寫完這個例子相信你對類其實了解一些了,接着我們來學習下類的繼承,聽名字好像又是什么高大上的東西,不怕其實是個很簡單的東東。

舉個簡單的例子,假設你寫了一個黃種人的類,但是又要寫黑人、白人的類呢?全部重新寫方法嗎?直接看代碼,來:

class Yello_person():

    def __init__(self):
        self.skin = 'yellow'
        #self.name = 'liu'

    def eat(self):
        self.food = 'rice'
        print("%s種人在吃%s"%(self.skin,self.food))

class Black_person(Yello_person):  #繼承Yello_person類的所有
def __init__(self):       #重寫__init__這個構造函數,因此
  self.skin
= 'black'

大家看這就是繼承,可以繼承父類、基類、超類,繼承之后可以擁有父類的所有屬性和方法,如果重寫了就會讀取自己寫的屬性和方法,那么有個問題來了,如果我又想繼承部分屬性又想自己定義部分屬性呢?

那么接着看剛剛那么例子,用super()繼承即可:

class Yello_person():

    def __init__(self):
        self.skin = 'yellow'
        self.name = 'liu'

    def eat(self):
        self.food = 'rice'
        print("叫%s的%s種人在吃%s"%(self.name,self.skin,self.food))

class Black_person(Yello_person):

    def __init__(self):
        super().__init__()      #繼承父類的__init__()下的屬性
        self.skin = 'black'

或者用下面這種方法,父類.__init__(self):

class Yello_person():

    def __init__(self):
        self.skin = 'yellow'
        self.name = 'liu'

    def eat(self):
        self.food = 'rice'
        print("叫%s的%s種人在吃%s"%(self.name,self.skin,self.food))

class Black_person(Yello_person):

    def __init__(self):
        Yello_person.__init__(self)          #繼承父類的__init__屬性
        self.skin = 'black'

這兩個結果都是一樣的,都可以繼承,建議寫super(),因為修改的話只要修改一個地方的類就好了,第二種方法要修改很多處。

接下來說下多重繼承,其實就是class Person(class1,class2,class3),逗號隔開即可,看個實例:

class Yello_person():

    def __init__(self):
        self.skin = 'yellow'

    def eat(self):
        self.food = 'rice'
        print("%s種人在吃%s"%(self.skin,self.food))

class Black_person():

    def __init__(self):
        self.skin = 'black'


class White_person(Black_person,Yello_person):
    pass

注意,如果繼承時Yello_person寫在前面則會打印這個,所以多重繼承時,如果出現重復的,默認是選擇第一個類的屬性或方法。

接着看下下面的題目:

1、定義一個點(Point)類和直線(Line)類,使用getLen方法獲得直線的長度。

代碼如下:

import math
class Point():

    def __init__(self,x,y):
        self.x = x
        self.y = y


    def getX(self):
        return self.x

    def getY(self):
        return self.y

class Line():
    
    def __init__(self,p1,p2):
        self.x = p1.getX() - p2.getX()
        self.y = p1.getY() - p2.getY()
        self.len = math.sqrt(self.x*self.x + self.y*self.y)               #獲取兩點之間的數學公式


    def getLen(self):
        return self.len
    

   之前說了類的繼承和多重繼承,那么如果說我們要定義一個房子,里面有人和家具,那么顯然用繼承是不合理的,因為這個類就是四不像了,那么這個時候該怎么辦呢?——組合,沒錯就是類的組合,舉個例子大家看下就好了;

class Person:

    def __init__(self,num):
        self.num = num

class Jiaju:

    def __init__(self,num):
        self.num = num


class room:

    def __init__(self,pnum,jnum):
        self.pnum = Person(pnum)             #實例化人這個類然后賦值給一個變量
        self.jnum = Jiaju(jnum)        #實例化家具這個類然后賦值給一個變量
def retrunnum(self): print("房子里面總共有%d人和%d家具!"%(self.pnum.num, self.jnum.num))

運行結果可以看下:

組合就是將類的實例化放在新的類中,這樣就完成了組合 

類、類對象和實例對象

    

 

這個圖是三個的關系圖,簡單說一下,剛開始看我覺得類定義和類對象分不清,實際上當類定義執行完后就變成了類對象,實例對象就是對類對象的實例化而已。

注意:類中的方法名與屬性名重名時,類將被屬性覆蓋,來看個實例:

>>> class Person:
    def name(self):
        print('king')

        
>>> p1 = Person()
>>> p1.name()
king
>>> p1.name = 1
>>> p1.name()
Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    p1.name()
TypeError: 'int' object is not callable

綁定:python嚴格要求方法需要有實例才能被調用,這種限制其實就是python所謂的綁定概念。

  1、issubclass(class, classinfo)

    a、一個類被認為是其自身的子類

    b、classinfo可以是類對象組成的元組,只要class是其中任何一個子類,則返回True

  2、isinstance(object,classinfo)

    a、如果第一個參數不是對象,則永遠返回False

    b、如果第二個參數不是類或者由類對象組成的元組,會拋出一個TypeError異常。

  3、hasattr(object,name):測試一個對象是否有指定的屬性

  4、getattr(object, name[, default]):返回對象指定的屬性值

  5、setattr(object,name,value):設置指定屬性的值

  6、delattr(object,name):刪除對象中指定的屬性,如果屬性不存在拋出異常。

還有一個屬性函數,property

下表列出了可以在自己的類中覆蓋的一些通用方法 

給個題目大家看下:

請在類中定義一個變量,用於跟蹤該類有多少個實例被創建(實例化一個對象時,變量+1,銷毀一個對象時,變量自動-1)

代碼如下;

class A:
    
    count = 0

    def __init__(self):
        A.count += 1

    def __del__(self):
        A.count -= 1

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM