面向對象程序設計

1、類和對象

  即類別、種類,是面向對象設計最重要的概念,對象是特徵與技能的結合體,就是一系列對象類似特徵和技能的結合體,針對一樣的事物,站在不一樣的角度獲得的類是不一樣的。須要注意的是:python

  • 站的角度不一樣,定義出的類是大相徑庭的;
  • 現實中的類並不徹底等於程序中的類,好比現實中的公司類,在程序中有時須要拆分紅部門類,業務類等;
  • 有時爲了編程需求,程序中也可能會定義現實中不存在的類,好比策略類,現實中並不存在,可是在程序中倒是一個很常見的類。

一、對象和類的前後關係

  在現實世界中必定是先有對象後有類;但在程序中,倒是偏偏相反,必定是先定義類,後調用類來產生對象sql

# 先定義類
class LuffyStudent:
    school = 'luffycity'

    def learn(self):
        print('is learning')

    def eat(self):
        print('is eating')

    def sleep(self):
        print('is sleeping')


# 後產生對象
stu1 = LuffyStudent()  # 不是執行類體,而是實例化
stu2 = LuffyStudent()
stu3 = LuffyStudent()
print(stu1)  # <__main__.LuffyStudent object at 0x10401ae80>

 注意:編程

  • 類中能夠有任意Python代碼,這些代碼的類定義階段便會執行,於是會產生新的名稱空間,用來存放類的變量名和函數名,能夠經過__dict__查看。
  • 類中定義的名字,都是類的屬性,點是訪問屬性的語法。
  • 對於經典類來講咱們能夠經過該字典操做類名稱空間的名字,但新式類有限制。

二、__dict__方法

   __dict__是一個字典,鍵爲屬性名,值爲屬性值。類的__dict__存儲全部實例共享的變量和函數(類屬性,方法等),類的__dict__並不包含其父類的屬性。app

class LuffyStudent:
    school = 'luffycity'

    def learn(self):
        print('is learning')

    def eat(self):
        print('is sleeping')


print(LuffyStudent.__dict__)
print(LuffyStudent.__dict__['school'])
print(LuffyStudent.__dict__['learn'])
"""
{'__module__': '__main__', 'school': 'luffycity', 'learn': <function LuffyStudent.learn at 0x101eb3620>, 'eat': <function LuffyStudent.eat at 0x101f211e0>, '__dict__': <attribute '__dict__' of 'LuffyStudent' objects>, '__weakref__': <attribute '__weakref__' of 'LuffyStudent' objects>, '__doc__': None}
luffycity
<function LuffyStudent.learn at 0x101eb3620>
"""

須要注意__dict__與dir()函數的區別:  

  一、dir()是Python提供的一個API函數,dir()函數會自動尋找一個對象的全部屬性(包括從父類繼承的屬性),包括__dict__中的屬性。ide

  二、__dict__是dir()的子集,一個實例的__dict__屬性僅僅是那個實例的實例屬性的集合,並不包含該實例的全部有效屬性。函數

三、特殊類屬性

__name__:查看類的名字(這裏的類名是字符串類型的)ui

__dict__:查出一個字典,key爲屬性名,value爲屬性值spa

__doc__:顯示註釋設計

dir(類名):查看類,以列表的形式顯示出來code

__module__:類定義所在的模塊

__class__:

isinstance(stu1, LuffyStudent):判斷對象是不是類的實例

四、引用類的屬性

  在使用類時,能夠對類的屬性進行增刪改查操做。

class LuffyStudent:
    school = 'luffycity'

    def learn(self):
        print('is learning')

    def eat(self):
        print('is sleeping')

# 查看
print(LuffyStudent.school)  # luffystudent.__dict__['school']
print(LuffyStudent.learn)  # Luffystudent.__dict_ ('learn')
"""
luffycity
<function LuffyStudent.learn at 0x101cb3620>
"""

#
LuffyStudent.country = 'China'
print(LuffyStudent.__dict__)
print(LuffyStudent.country)
"""
{'__module__': '__main__', 'school': 'luffycity', 'learn': <function LuffyStudent.learn at 0x101eb3620>, 'eat': <function LuffyStudent.eat at 0x1040211e0>, '__dict__': <attribute '__dict__' of 'LuffyStudent' objects>, '__weakref__': <attribute '__weakref__' of 'LuffyStudent' objects>, '__doc__': None, 'country': 'China'}
China
"""

#
del LuffyStudent.country

#
LuffyStudent.school = 'whu'
print(LuffyStudent.school)
"""
whu
"""

五、實例化

  調用類(實例化),獲得程序中的對象。

class LuffyStudent:
    school = 'luffycity'

    def learn(self):
        print('is learning')

    def eat(self):
        print('is eating')

    def sleep(self):
        print('is sleeping')


# 後產生對象
stu1 = LuffyStudent()  # 不是執行類體,而是實例化
stu2 = LuffyStudent()
stu3 = LuffyStudent()
print(stu1)
print(stu2)
print(stu3)
"""
<__main__.LuffyStudent object at 0x10401ae80>
<__main__.LuffyStudent object at 0x10401af28>
<__main__.LuffyStudent object at 0x10401af60>
"""

  實例化完成後,stu一、stu二、stu3都同樣了,這三者除了類似的屬性外還有各類不一樣的屬性,就須要用到__init__方法了。

六、__init__方法:爲對象定製本身獨有的特徵

   __init__方法是在對象產生以後纔會執行,只用來爲對象進行初始化操做,能夠有任意代碼,但必定不能有返回值。

  實例化後會產生對象的名稱空間,對象的名稱空間也能夠用stu1.__dict__查看:{'Name': '百合', 'Sex': '女', 'Age': 12}

class LuffyStudent:
    school = 'luffycity'

    def __init__(self, name, sex, age):  # 實例化時自動調用
        self.Name = name
        self.Sex = sex
        self.Age = age

    def learn(self):
        print('is learning')

    def eat(self):
        print('is sleeping')


# 產生對象
stu1 = LuffyStudent('百合', '', 12)
print(stu1.Name)

"""
加上__init__方法後,實例化的步驟
    一、先產生一個空對象
    二、LuffyStudent.__init__(stu1, '百合', '女', 12)
"""

#
print(stu1.__dict__)
print(stu1.Name)
print(stu1.Sex)
print(stu1.Age)
"""
{'Name': '百合', 'Sex': '女', 'Age': 12}
百合
女
12
"""

#
stu1.Name = '李二丫'
print(stu1.__dict__)
print(stu1.Name)
"""
{'Name': '李二丫', 'Sex': '女', 'Age': 12}
李二丫
"""

# 刪除
del stu1.Name
print(stu1.__dict__)
"""
{'Sex': '女', 'Age': 12}
"""

#
stu1.class_name = 'python開發'
print(stu1.__dict__)
"""
{'Sex': '女', 'Age': 12, 'class_name': 'python開發'}
"""

stu2 = LuffyStudent('李三炮', '', 22)
print(stu2.__dict__)
"""
{'Name': '李三炮', 'Sex': '男', 'Age': 22}
"""

  當類有了__init__方法後,實例化時先調用類產生空對象,再調用__init__()方法。

  上述代碼中也包含有對象的使用,對對象的增刪改查操做。

七、關於self

  self,就是實例自己!你實例化時python解釋器會自動把這個實例自己經過self參數傳進去。

  self是實例化時自動將對象/實例自己傳給__init__的第一個參數,你也能夠給它起個別的名字,可是通常正常人都不會這麼作,由於改了別人就不認識了。

注意:def  __init__(self):   這句話能夠寫也能夠不寫,只要有參數參進來的時候就必須得寫

   def  方法名(self):這裏的self必須得寫

2、屬性查找

  類中有兩種屬性:數據屬性和函數屬性。

class LuffyStudent:
    school = 'luffycity'

    def __init__(self, name, sex, age):  # 實例化時自動調用
        self.Name = name
        self.Sex = sex
        self.Age = age

    def learn(self):
        print('%s is learning' % self.Name)

    def eat(self):
        print('%s is sleeping' % self.Name)


# 產生對象
stu1 = LuffyStudent('百合', '', 12)
stu2 = LuffyStudent('李三炮', '', 38)
stu3 = LuffyStudent('張鐵蛋', '', 48)

# 對象:特徵和技能的結合體
# 類:類是一系列對象類似的特徵與類似技能的結合體

一、類的數據屬性是全部對象共享的

# 類中數據屬性:是全部對象共有的(都是同樣的)
print(LuffyStudent.school, id(LuffyStudent.school))

print(stu1.school, id(stu1.school))
print(stu2.school, id(stu2.school))
"""內存地址同樣
luffycity 4325120112
luffycity 4325120112
luffycity 4325120112
"""

二、類的函數屬性是綁定給對象用的,稱爲綁定到對象的方法。

# 類中函數屬性:是綁定給對象的,綁定到不一樣的對象是不一樣的綁定方法,對象調用綁定方法時,會把對象自己當作第一個參數傳入,傳給self
print(LuffyStudent.learn)
LuffyStudent.learn(stu1)
"""
<function LuffyStudent.learn at 0x1040211e0>
百合 is learning
"""

print(stu1.learn)
print(stu2.learn)
print(stu3.learn)
"""綁定方法,每一個人的函數內存地址不一樣
<bound method LuffyStudent.learn of <__main__.LuffyStudent object at 0x10402cc18>>
<bound method LuffyStudent.learn of <__main__.LuffyStudent object at 0x10402cc50>>
<bound method LuffyStudent.learn of <__main__.LuffyStudent object at 0x10402cc88>>
"""

三、屬性查找順序

  優先在對象中查找,對象中沒有再在類中查找,類中沒有會去父類查找,最後都沒有則拋出異常。

# 屬性查找,優先對象中查找,對象中沒有在類中查找
# stu1.x = 'from stu1'
LuffyStudent.x = 'from Luffycity class'

print(stu1.__dict__)
print(stu1.x)
"""
{'Name': '百合', 'Sex': '女', 'Age': 12}
from Luffycity class
"""

3、綁定方法

  在屬性查找那一小節中,定義了類並實例化出了三個對象stu一、stu二、stu3。

class LuffyStudent:
    school = 'luffycity'

    def __init__(self, name, sex, age):  # 實例化時自動調用
        self.Name = name
        self.Sex = sex
        self.Age = age

    def learn(self):
        print('%s is learning' % self.Name)

    def eat(self):
        print('%s is sleeping' % self.Name)


# 產生對象
stu1 = LuffyStudent('百合', '', 12)
stu2 = LuffyStudent('李三炮', '', 38)
stu3 = LuffyStudent('張鐵蛋', '', 48)
定義類並實例化對象

  類中定義的函數(沒有被任何裝飾器裝飾的)是類的函數屬性,類可使用,但必須遵循函數的參數規則,有幾個參數須要傳幾個參數。

LuffyStudent.learn(stu1)
LuffyStudent.learn(stu2)
LuffyStudent.learn(stu3)
"""
百合 is learning
李三炮 is learning
張鐵蛋 is learning
"""

  類中定義的函數(沒有被任何裝飾器裝飾的),其實主要是給對象使用的,並且是綁定到對象的,雖然全部對象指向的都是相同的功能,可是綁定到不一樣的對象就是不一樣的綁定方法

  強調:綁定到對象的方法的特殊之處在於,綁定給誰就由誰來調用,誰來調用,就會將‘誰’自己當作第一個參數傳給方法,即自動傳值(方法__init__也是同樣的道理)

stu1.learn()
stu2.learn()
stu3.learn()
"""
百合 is learning
李三炮 is learning
張鐵蛋 is learning
"""

  注意:綁定到對象的方法的這種自動傳值的特徵,決定了在類中定義的函數都要默認寫一個參數self,self能夠是任意名字,可是約定俗成地寫出self。

4、類即類型

  python中一切皆爲對象,且Python3中類與類型是一個概念,類型就是類。

class student:
    school = 'whu'

# python當中一切皆對象,在python3中統一了類和類型的概念
print(list)
print(dict)∂
print(student)
"""
<class 'list'>
<class 'dict'>
<class '__main__.student'>
"""

   以list類型舉例,類型list就是類list,對類實例化後,對象調用綁定方法append爲對象添加元素。

>>> list
<class 'list'>

#實例化的到3個對象l1,l2,l3
>>> l1=list()
>>> l2=list()
>>> l3=list()

#三個對象都有綁定方法append,是相同的功能,但內存地址不一樣
>>> l1.append
<built-in method append of list object at 0x10b482b48>
>>> l2.append
<built-in method append of list object at 0x10b482b88>
>>> l3.append
<built-in method append of list object at 0x10b482bc8>

#操做綁定方法l1.append(3),就是在往l1添加3,絕對不會將3添加到l2或l3
>>> l1.append(3)
>>> l1
[3]
>>> l2
[]
>>> l3
[]
#調用類list.append(l3,111)等同於l3.append(111)
>>> list.append(l3,111) #l3.append(111)
>>> l3
[111]

5、面向對象小結

一、定義及調用的固定格式

class 類名:
    def __init__(self,參數1,參數2):
        self.對象的屬性1 = 參數1
        self.對象的屬性2 = 參數2

    def 方法名(self):pass

    def 方法名2(self):pass

對象名 = 類名(1,2)  #對象就是實例,表明一個具體的東西
                  #類名() : 類名+括號就是實例化一個類,至關於調用了__init__方法
                  #括號裏傳參數,參數不須要傳self,其餘與init中的形參一一對應
                  #結果返回一個對象
對象名.對象的屬性1   #查看對象的屬性,直接用 對象名.屬性名 便可
對象名.方法名()     #調用類中的方法,直接用 對象名.方法名() 便可

二、運用面向對象好處

(1)將數據和專門操做該數據的功能整合到一塊兒

  避免定義一大堆全局變量。

class MySQLHandler:
    def __init__(self,host,port,db,charset='utf8'):
        self.host=host
        self.port=port
        self.db=db
        self.charset=charset
        self.conn=connect(self.host,self.port,self.db,self.charset)
    def exc1(self,sql):
        return self.conn.execute(sql)

    def exc2(self,sql):
        return self.conn.call_proc(sql)


obj=MySQLHandler('127.0.0.1',3306,'db1')
obj.exc1('select * from tb1;')
obj.exc2('存儲過程的名字')

(2)可擴展性高

  定義類併產生多個對象

class Chinese:
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex


p1=Chinese('egon',18,'male')
p2=Chinese('alex',38,'female')
p3=Chinese('wpq',48,'female')

  若是新增一個類屬性,會馬上反映給全部對象,而對象卻無需修改。

class Chinese:
    country='China'
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex
    def tell_info(self):
        info='''
        國籍:%s
        姓名:%s
        年齡:%s
        性別:%s
        ''' %(self.country,self.name,self.age,self.sex)
        print(info)


p1=Chinese('egon',18,'male')
p2=Chinese('alex',38,'female')
p3=Chinese('wpq',48,'female')

print(p1.country)
p1.tell_info()

三、面向對象練習題 

練習1:編寫一個學生類,產生一堆學生對象。

要求:有一個計數器(屬性),統計總共實例了多少個對象

class Student:   # 類名頭字母大寫
    school = 'whu'
    count = 0

    def __init__(self, name, age, sex):  # 爲對象定製對象本身獨有的特徵
        self.name = name
        self.age = age
        self.sex = sex
        # self.count += 1  # 每一個對象都是1,沒法實現累加,student類的count一直都是0
        Student.count += 1

    def learn(self):
        print('%s is learning' % self.name)

    def eat(self):
        print('%s is eating very happy!' % self.name)


stu1 = Student('alex', 'male', 38)   # 實例化一次就觸發一次__init__
stu2 = Student('jinxing', 'female', 48)
stu3 = Student('egon', 'male', 18)


print(Student.count)
print(stu1.count)
print(stu2.count)
print(stu3.count)
print(stu1.__dict__)
print(stu3.__dict__)
"""
3
3
3
3
{'name': 'alex', 'age': 'male', 'sex': 38}
{'name': 'egon', 'age': 'male', 'sex': 18}
"""
學生類具有計算器

練習2:模仿王者榮耀定義兩個英雄類, (10分鐘)

要求:一、英雄須要有暱稱、攻擊力、生命值等屬性;

   二、實例化出兩個英雄對象;

   三、英雄之間能夠互毆,被毆打的一方掉血,血量小於0則斷定爲死亡。

class Garen:
    camp = 'Demacia'

    def __init__(self, nickname, life_value, aggresivity):
        self.nickname = nickname
        self.life_value = life_value
        self.aggresivity = aggresivity

    def attack(self, enemy):
        enemy.life_value -= self.aggresivity


class Riven:
    camp = 'Noxus'

    def __init__(self, nickname, life_value, aggresivity):
        self.nickname = nickname
        self.life_value = life_value
        self.aggresivity = aggresivity

    def attack(self, enemy):
        enemy.life_value -= self.aggresivity


g1 = Garen('草叢倫', 100, 30)

r1 = Riven('可愛的瑞雯', 80, 50)

print(r1.life_value)
g1.attack(r1)  # 攻擊了一刀
r1.attack(g1)
print(r1.life_value)
print(g1.life_value)
英雄角色類互相交互

四、判斷是函數仍是方法?

函數:函數是封裝了一些獨立的功能,能夠直接調用,python內置了許多函數,同時能夠自建函數來使用。

方法:方法和函數相似,一樣封裝了獨立的功能,可是方法是須要經過對象來調用的,表示針對這個對象要作的操做,使用時採用點方法。

相關文章
相關標籤/搜索