27. 企業(yè)級開發(fā)基礎(chǔ)8:面向?qū)ο髷U展

前面的章節(jié)中潮峦,我們已經(jīng)學(xué)習(xí)過面向?qū)ο蟮幕静僮魅胪怠⒚嫦驅(qū)ο蟮娜筇卣鞯脑敿毑僮?/strong>嘹屯,對于面向?qū)ο笥辛艘粋€初步的了解和認知印荔。
本節(jié)內(nèi)容會針對面向?qū)ο蟮某绦蛟O(shè)計進行一部分的擴展和補充低葫,方便我們在項目開發(fā)過程中的操作能更加的全面和完善。

0. 本節(jié)內(nèi)容

0.1 類型屬性和對象成員屬性
0.2 對象屬性的外部聲明和限制
0.3 多繼承機制下的注意的問題
0.4 類的定制屬性~魔法方法
0.5 特殊的類型:枚舉

1. 類型屬性和對象的成員屬性

在之前的章節(jié)中仍律,我們就類和對象已經(jīng)學(xué)習(xí)過了如下內(nèi)容

  • 類型的定義
  • 類型中屬性的定義
  • 類型中方法的定義
  • 屬性和方法的私有化操作

當類型在處理的過程中嘿悬,我們知道在init()函數(shù)中可以初始化類的成員屬性/變量,在創(chuàng)建對象的過程中染苛,每個對象的成員屬性都是互相獨立且互不影響的鹊漠;對象A是不能直接使用對象B的成員屬性的值的,而是要通過對象B調(diào)用獲取對象B的屬性茶行;
python的類型中躯概,還提供了一種方式,可以直接定義類的屬性畔师,這樣定義的屬性是當前類型創(chuàng)建的所有對象所共享的娶靡,也可以直接通過類名稱調(diào)用,這樣的屬性稱為:類屬性

類屬性:是定義在類型中的公開的屬性看锉,可以讓通過當前類型直接操作姿锭,可以是當前類型創(chuàng)建的所有對象共享的數(shù)據(jù)

# 創(chuàng)建一個Person類型
class Person(object):
    # 定義一個類屬性:在線人數(shù)
    onlineCount = 100
    # 類型初始化的方法
    def __init__(self, name):
        self.__name = name
    # 屬性訪問方法
    def get_name(self):
        return self.__name
    def set_name(self, name):
        self.__name = name
# 創(chuàng)建Person類型的對象
p1 = Person("tom")
p2 = Person("jerry")

# 訪問類屬性
print(Person.onlineCount)    # 執(zhí)行結(jié)果 100
print(p1.onlineCount)          # 執(zhí)行結(jié)果 100
print(p2.onlineCount)          # 執(zhí)行結(jié)果 100

# 通過類名稱修改類屬性
Person.onlineCount = 15
# 再次訪問類屬性
print(Person.onlineCount)    # 執(zhí)行結(jié)果 15
print(p1.onlineCount)          # 執(zhí)行結(jié)果 15
print(p2.onlineCount)          # 執(zhí)行結(jié)果 15

# 切記不能通過對象修改類屬性:下面的做法只是給p1對象添加了一個額外的成員屬性onlineCount
p1.onlineCount = 200
# 再次訪問類屬性
print(Person.onlineCount)    # 執(zhí)行結(jié)果 15
print(p1.onlineCount)          # 執(zhí)行結(jié)果 200
print(p2.onlineCount)          # 執(zhí)行結(jié)果 15

類和對象,注意:
類中可能會出現(xiàn)三種屬性/變量

  • 類屬性:直接定義在類的內(nèi)部伯铣,初始化函數(shù)的外部的屬性呻此,可以直接通過類名稱訪問或者修改,通過當前類創(chuàng)建的對象都可以共享/訪問類的類屬性
  • 成員屬性:定義在初始化函數(shù)__init__(self)中腔寡,每個通過當前類創(chuàng)建的對象都有自己獨立的成員屬性的數(shù)據(jù)焚鲜,并且對象和對象之間的數(shù)據(jù)不會有任何影響
  • 局部變量:在類的方法中的參數(shù)、方法中定義的變量都是局部變量放前,局部變量一旦方法執(zhí)行完畢就會被回收

2. 對象屬性的外部聲明和限制

上面的代碼中忿磅,我們使用p1.onlineCount=15發(fā)現(xiàn)沒有修改類屬性,而是給p1增加了一個成員屬性凭语,這是怎么回事呢葱她?

觀察下面的代碼:

# 創(chuàng)建了一個空類型
class Person:
    pass

# 創(chuàng)建Person的對象
p = Person()
# 給對象p追加成員屬性
p.name = "tom"
p.age = 19
p.gender = "男"
# 打印屬性數(shù)據(jù)
print(p.name, p.age, p.gender)
# 執(zhí)行結(jié)果:tom 19 男

在上述代碼中,我們定義了一個空類型Person似扔,在創(chuàng)建了Person的對象之后吨些,可以在對象的引用變量上搓谆,給對象添加額外的成員屬性【切記,這里添加的額外的成員屬性僅限于當前的這個對象锤灿,其他對象上不會出現(xiàn)】

這樣的操作方式挽拔,可以在一定程度上讓代碼的操作更加靈活,但是同時也降低了代碼的可讀性但校,試想一下~我們辛辛苦苦抽象定義好了類型Person螃诅,Person中已經(jīng)出現(xiàn)了我們所有人知道的屬性,結(jié)果在操作的過程中状囱,朝陽群眾A創(chuàng)建的Person對象多出來了2個其他人不知道的屬性术裸,朝陽群眾B創(chuàng)建的Person對象又多出來了其他人不知道的3個屬性,這是一件非惩ぜ希恐怖的事情袭艺,會讓整個類型和對象的操作變得非常的混亂。

# 原始的Person類型叨粘,只有一個name屬性
class Person:
    def __init__(self, name):
        self.__name = name
    def get_name(self):
        return self.__name
    def set_name(self, name):
        self.__name = name

# 朝陽群眾A創(chuàng)建的對象
p = Person("老A")
p.age = 20
p.sex = "男"
# 朝陽群眾B創(chuàng)建的對象
p = Person ("老B")
p.gender = "女"
p.address = "朝陽"
p.phone = "13838383838"

觀察上述代碼猾编,兩個人創(chuàng)建的對象,一團混亂升敲,光是一個性別兩個開發(fā)人員定義的擴展出來的成員變量都不一致答倡,后續(xù)其他人在操作的時候都不知道應(yīng)該調(diào)用什么屬性來處理了。

python為了處理這樣的問題驴党,提供了一個特殊的類屬性__slots__ 瘪撇,該屬性的值是一個元組,元組中定義了類中可以出現(xiàn)的所有成員屬性的名稱

# 創(chuàng)建一個Person類型
class Person:
    # 通過__slots__屬性定義可以擴展的成員屬性名稱
    __slots__ = ("__name", "address", "age", "gender", "email")
    # 初始化方法
    def __init__(self, name):
        self.__name = name
    # 屬性的set/get方法
    def get_name(self):
        return self.__name
    def set_name(self, name):
        self.__name = name
# 創(chuàng)建對象
p = Person("tom")
# 擴展屬性
p.address = "朝陽"
p.age = 20
p.sex = "男"
# 執(zhí)行結(jié)果
~ AttributeError: 'Person' object has no attribute 'sex'

通過上述代碼就可以看到港庄,python提供了一個__slots__類屬性倔既,屬性的值是一個元組,元組中規(guī)范了可能出現(xiàn)在類的成員屬性列表鹏氧。

類在創(chuàng)建好對象之后渤涌,可以在對象上直接掛在屬性,這在一定程度上對于程序處理的靈活度有所提升把还,但是同樣的歼捏,過于靈活的代碼都會極大的降低代碼的可讀性,所以python提供了__slots__這樣的類屬性進行規(guī)范笨篷,規(guī)范類屬性中只能出現(xiàn)的成員屬性的列表,防止惡意的擴展瓣履。

3. 多繼承機制下的注意的問題

多繼承機制率翅,在操作的過程中,同樣也是提高了代碼的處理靈活性袖迎,很大程度的擴展了代碼的功能

在使用多繼承機制進行程序設(shè)計開發(fā)的過程中一定要注意一個問題:當前類繼承了一個或者多個父類冕臭,當前類就同時繼承了父類中的公開的屬性和函數(shù)腺晾,如果不同的父類中出現(xiàn)相同的屬性/函數(shù),就需要明確執(zhí)行的過程

# 定義一個類型Son
class Son(object):
    def fealty(self):
        print("孝順父母")
# 常見一個類型Student
class Student(object):
    def fealty(self):
        print("尊師重道")

# 創(chuàng)建一個Person類型辜贵,繼承自Son和Student
class Person(Son, Student):
    pass

# 創(chuàng)建對象悯蝉,執(zhí)行方法
p = Person()
p.fealty()
# 問題:這里的fealty()函數(shù),會不會報錯托慨?如果不報錯鼻由,怎么執(zhí)行?
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
# 我們可以看到厚棵,在繼承的兩個父類中都出現(xiàn)了fealty()函數(shù)
# 這里執(zhí)行時蕉世,按照類型定義時繼承的順序進行查找
#  查找到對應(yīng)的函數(shù)立刻執(zhí)行并且不再向后查詢
# 上述案例中,繼承順序是(Son, Student)
# 首先在Son類型中查詢是否有fealty()方法婆硬,查詢到立刻執(zhí)行狠轻。
# 執(zhí)行結(jié)果:孝順父母
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

上述案例中,我們看到一旦出現(xiàn)多重繼承彬犯,就會出現(xiàn)這樣繼承的多個父類中出現(xiàn)了多個相同名稱的變量或者方法的情況向楼,使用的這些變量和方法的時候一定要注意一個原則,先繼承誰就使用誰的變量或者方法谐区!

4. 類的定制屬性~魔法方法

上面的代碼中湖蜕,我們已經(jīng)看到了,類似__slots__這樣的變量在前后加了雙下劃線的卢佣,在python中會有特殊的含義重荠,這里會繼續(xù)介紹一些常見的在面向?qū)ο箝_發(fā)過程中出現(xiàn)的一些這樣的魔法方法

4.1. 對象格式化打印輸出【__str__()】

常規(guī)情況下,對象直接輸出虚茶,會輸出對象的描述信息戈鲁,晦澀難懂

# 定義類型
class Person(object):
    def __init__(self, name):
        self.__name = name
# 創(chuàng)建對象
p = Person("jerry")
# 輸出對象
print(p) 
# 執(zhí)行結(jié)果:<__main__.Person object at 0x0000028727259550>

對當前類型進行如下改造

# 定義類型
class Person(object):
    def __init__(self, name):
        self.__name = name
    def __str__(self):
        return "i am a person, my name is " + self.__name
# 創(chuàng)建對象
p = Person("jerry")
# 輸出對象
print(p) 
# 執(zhí)行結(jié)果:i am a person, my name is jerry
p
# 執(zhí)行結(jié)果:<__main__.Person object at 0x0000028727259550>

我們突然發(fā)現(xiàn),直接打印對象嘹叫,輸出的結(jié)果竟然是我們在__str__()方法中定義的字符串婆殿。其實我們在使用使用對象的時候,就會默認調(diào)用對象的__str__()方法獲取對象的字符串描述信息罩扇,這個__str__()方法是從object對象繼承而來的婆芦,我們這里只是對它進行了方法重寫。

另外喂饥,在命令行操作過程中消约,如果不用print()方法打印而是直接輸入對象,會發(fā)現(xiàn)執(zhí)行的結(jié)果又是讓人晦澀難懂的東西了员帮,在命令行直接使用對象調(diào)用的不是對象的__str__()方法或粮,而是__repr__()方法,只需要簡單的修改即可

# 定義類型
class Person(object):
    def __init__(self, name):
        self.__name = name
    def __str__(self):
        return "i am a person, my name is " + self.__name
    # 將方法__str__賦值給__repr__
    __repr__ = __str__
# 創(chuàng)建對象
p = Person("jerry")
# 輸出對象
print(p) 
# 執(zhí)行結(jié)果:i am a person, my name is jerry
p
# 執(zhí)行結(jié)果:i am a person, my name is jerry
4.2. 玩轉(zhuǎn)自己~對象的應(yīng)用直接調(diào)用【__call__()】

當我們創(chuàng)建好對象之后捞高,可以將對象的引用變量當成方法執(zhí)行會出現(xiàn)什么樣的情況呢

# 定義類型
class Person(object):
    def __init__(self, name):
        self.__name = name
# 創(chuàng)建對象
p = Person("jerry")
# 直接執(zhí)行
p()
# 執(zhí)行結(jié)果:TypeError: 'Person' object is not callable

肯定是不能這么干的~氯材,所以出現(xiàn)錯誤:Person對象不是一個可執(zhí)行的東東

但是可以進行如下的改造

# 定義類型
class Person(object):
    def __init__(self, name):
        self.__name = name
    def __call__(self):
        print("一種快捷執(zhí)行對象中某些初始化操作的特殊方法__call__")
# 創(chuàng)建對象
p = Person("jerry")
# 直接執(zhí)行
p()
# 執(zhí)行結(jié)果:一種快捷執(zhí)行對象中某些初始化操作的特殊方法__call__

此時又發(fā)現(xiàn)渣锦,這樣直接將引用變量當成方法執(zhí)行又變的可行了。
__call__()方法氢哮,主要用于對象快捷執(zhí)行而存在的一個魔術(shù)方法袋毙,方便進行對象中某些重要數(shù)據(jù)的初始化整理工作等。

在python中冗尤,還有一系列的魔法方法听盖,可以讓一個類具有各種特殊的處理功能,如__iter__()方法生闲,讓一個類創(chuàng)建的對象可以像列表那樣進行數(shù)據(jù)的迭代媳溺;__getitem__()函數(shù)可以在迭代的基礎(chǔ)上進行索引取值等操作,

5. 特殊的類型:枚舉

某些情況下碍讯,在我們項目開發(fā)過程中悬蔽,會針對一些不會改變的數(shù)據(jù)進行標記,常見的做法就是通過定義常量的情況進行處理捉兴,如:在一個員工管理系統(tǒng)中蝎困,針對一年十二個月發(fā)放工資,這里的十二個月需要進行標記每個月的天數(shù)倍啥、績效這些都不一定一致禾乘,可以按照下面的方式進行處理:

# 通過列表中定義一堆的變量來表示12個月份
month = ["JAN", "FAB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"]
# 但是列表表示的方式,列表中的數(shù)據(jù)并不是非常的安全虽缕,有可能在操作的過程中被修改

# 通過元組中定義一堆的變量來表示12個月份
month = ("JAN", "FAB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC")
# 這樣就比第一種方案簡單多了始藕,也方便后續(xù)的各種操作

# 通過類型中定義一堆的變量來表示12個月份
class Month(object): 
    "JAN" = 1
     "FAB" = 2
    "MAR" = 3
    "APR" = 4 
    "MAY" = 5 
    "JUN" = 6 
    "JUL" = 7 
    "AUG" = 8 
    "SEP" = 9 
    "OCT" = 10 
    "NOV" = 11
    "DEC" = 12
# 這樣更加正式一些,不過寫起來確實挺麻煩氮趋,后續(xù)的操作也不怎么友好
5.1. 使用枚舉

上述代碼中伍派,我們通過三種方式進行了枚舉的定義和處理,但是每一種方式都多多少少存在一些遺憾剩胁,python中提供了一種特殊的類型:枚舉诉植,來處理這樣定義常量的問題:

枚舉的語法結(jié)構(gòu):是不是和上面我們使用元組的方式特別相像呢?昵观!

from enum import Enum
# Month = Enum("枚舉名稱", (元組中的枚舉值))
M = Enum("Month",  ("JAN", "FAB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"))
# 使用枚舉
print(M.JAN)   #執(zhí)行結(jié)果:Month.JAN
print(M.JAN.value) # 執(zhí)行結(jié)果:1

通過將我們原始的條件判斷晾腔,加上枚舉操作,可以簡化代碼的同時提高代碼的可讀性
參考如下代碼啊犬,明顯第二種代碼的可讀性更高灼擂,更加方便我們的項目維護操作

if month == 1:
    print("1月份發(fā)放工資")
-------------------------------------------
if month = Month.JAN:
     print("1月份發(fā)放工資")
5.2. 自定義枚舉

Python提供的枚舉已經(jīng)完全足夠適用于我們項目中使用的各種場景了
如果枚舉的細節(jié)處理程度還是不滿足您的項目,可以通過python提供的方式進行自定義枚舉的定義

# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
#  自定義枚舉語法結(jié)構(gòu)
# from enum import Enum, unique
#
# @unique
# class EnumName(Enum):
#     枚舉元素
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
# 創(chuàng)建一個自定義枚舉觉至,用于定義一周中星期的每一天缤至,方便做日志記錄
from enum import Enum, unique

@unique
class Weekday(Enum):
    MON = 1
    TUE = 2
    WED = 3
    THU = 4
    FRI = 5
    SAT = 6
    SUN = 7
# 使用枚舉,和常規(guī)的使用方式一致
if today == Weekday.SAT:
    print("提醒:今天是發(fā)送周報的日子,不要忘記哦")

枚舉领斥,是為了方便在項目中定義有字面意義的常量,提高代碼的可讀性而出現(xiàn)的一種特殊的類型沃暗,底層封裝的其實就是給枚舉的名稱賦值了整數(shù)數(shù)據(jù)月洛,所以我們可以在程序中使用整數(shù)常量作為條件處理判斷的地方,使用枚舉能提高代碼的可讀性和維護性孽锥。


大牧莫邪.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嚼黔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子惜辑,更是在濱河造成了極大的恐慌唬涧,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盛撑,死亡現(xiàn)場離奇詭異碎节,居然都是意外死亡,警方通過查閱死者的電腦和手機抵卫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門狮荔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人介粘,你說我怎么就攤上這事殖氏。” “怎么了姻采?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵雅采,是天一觀的道長。 經(jīng)常有香客問我慨亲,道長婚瓜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任巡雨,我火速辦了婚禮闰渔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘铐望。我一直安慰自己冈涧,他們只是感情好,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布正蛙。 她就那樣靜靜地躺著督弓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪乒验。 梳的紋絲不亂的頭發(fā)上愚隧,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天,我揣著相機與錄音锻全,去河邊找鬼狂塘。 笑死录煤,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的荞胡。 我是一名探鬼主播妈踊,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼泪漂!你這毒婦竟也來了廊营?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤萝勤,失蹤者是張志新(化名)和其女友劉穎露筒,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體敌卓,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡慎式,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了假哎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瞬捕。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖舵抹,靈堂內(nèi)的尸體忽然破棺而出肪虎,到底是詐尸還是另有隱情,我是刑警寧澤惧蛹,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布扇救,位于F島的核電站,受9級特大地震影響香嗓,放射性物質(zhì)發(fā)生泄漏迅腔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一靠娱、第九天 我趴在偏房一處隱蔽的房頂上張望沧烈。 院中可真熱鬧,春花似錦像云、人聲如沸锌雀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽腋逆。三九已至,卻和暖如春侈贷,著一層夾襖步出監(jiān)牢的瞬間惩歉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留撑蚌,地道東北人上遥。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像锨并,于是被迫代替她去往敵國和親露该。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

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

  • 國家電網(wǎng)公司企業(yè)標準(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 10,970評論 6 13
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young閱讀 3,805評論 1 10
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法第煮,類相關(guān)的語法,內(nèi)部類的語法抑党,繼承相關(guān)的語法包警,異常的語法,線程的語...
    子非魚_t_閱讀 31,631評論 18 399
  • 通覽全部UI,先統(tǒng)一對基礎(chǔ)控件進行自定義,不要一出來UI就悶頭開干,這樣可能寫出來多個功能重復(fù)的自定義控件. 文件...
    蕭旭閱讀 210評論 0 0
  • 許多人都相信一個謊言壹瘟,那就是:婚姻是愛情的墳?zāi)埂5珔s不知道另一個真理:婚姻是愛情的天堂鳄逾。 當我寫下這句話的時候稻轨,一...
    仇小方閱讀 431評論 4 7