類和對象(實例)
- 先將對象分類
- 歸納出共同特征,構(gòu)建基類
- 構(gòu)建子類,描述其不同狀態(tài)(變量)和行為
- 創(chuàng)建類的實例,表示某個對象
- 對象通過行為觸發(fā)或與其他對象交互,來實現(xiàn)具體功能
如此一來,既節(jié)約了內(nèi)存空間,又少寫了代碼。(抽象是為了偷懶,偷懶是計算機前進的動力之一) - 存活的實例對象都有 “唯一“ 的ID值,可使用內(nèi)置函數(shù)id()查看。(id函數(shù)用來獲得對象的內(nèi)存地址,并且,該ID值只能保證在某個時間段內(nèi)該存活對象唯一,所以,該ID不適合作為全局身份標識)
- type()函數(shù)用來返回實例所屬類型,不會考慮繼承關(guān)系
- isinstance()函數(shù)判斷實例是否屬于特定類型,會考慮繼承關(guān)系
面向?qū)ο蟮娜筇匦裕?/h1>
- 封裝
- 繼承
- 多態(tài)
經(jīng)典類和新式類
- 當類是經(jīng)典類時,多繼承情況下,會按照深度優(yōu)先方式查找
- 當類是新式類時,多繼承情況下,會按照廣度優(yōu)先方式查找
- 如果該類或其父類繼承了object類,那么該類便是新式類,否則便是經(jīng)典類(新式類是推薦寫法,包含更多的功能)
類和對象在內(nèi)存中的保存方式
- 類及類中的屬性和方法,在內(nèi)存中只保存一份
- 每個對象都需要在內(nèi)存中保存一份(只保存對象的屬性,及指向類的類對象指針)。因此,在對象執(zhí)行方法時,會先通過類對象指針找到類中對應(yīng)的方法,將對象當作參數(shù)傳給方法的第一個參數(shù)self
類的成員
- 類的成員可以分為三大類:字段,方法和屬性
- 字段
- 普通字段(所有成員中,只有普通字段的內(nèi)容是保存在對象中的,其他成員均保存在類中,在內(nèi)存中只創(chuàng)建一份)
- 靜態(tài)字段
class Province:
# 靜態(tài)字段
country = '中國'
def __init__(self, name):
# 普通字段
self.name = name
# 直接訪問普通字段
obj = Province('河北省')
print obj.name
# 直接訪問靜態(tài)字段
Province.country
- 方法
- 普通方法
- 類方法
- 靜態(tài)方法
class Foo:
def __init__(self, name):
self.name = name
def ord_func(self):
""" 定義普通方法,至少有一個self參數(shù) """
# print self.name
print '普通方法'
@classmethod
def class_func(cls):
""" 定義類方法,至少有一個cls參數(shù) """
print '類方法'
@staticmethod
def static_func():
""" 定義靜態(tài)方法 ,無默認參數(shù)"""
print '靜態(tài)方法'
# 調(diào)用普通方法(自動將調(diào)用該方法的對象賦值給self)
f = Foo()
f.ord_func()
# 調(diào)用類方法(自動將調(diào)用該方法的類復(fù)制給cls)
Foo.class_func() # 推薦
f.class_func()
# 調(diào)用靜態(tài)方法(由類調(diào)用)
Foo.static_func() # 推薦
f.static_func
- 屬性
- 普通屬性(屬性存在意義是:訪問屬性時可以制造出和訪問字段完全相同的假象)(屬性由方法變種而來,如果Python中沒有屬性,方法完全可以代替其功能)
# ############### 定義 ###############
class Pager:
def __init__(self, current_page):
# 用戶當前請求的頁碼(第一頁、第二頁...)
self.current_page = current_page
# 每頁默認顯示10條數(shù)據(jù)
self.per_items = 10
@property
def start(self):
val = (self.current_page - 1) * self.per_items
return val
@property
def end(self):
val = self.current_page * self.per_items
return val
# ############### 調(diào)用 ###############
p = Pager(1)
p.start # 就是起始值,即:m
p.end # 就是結(jié)束值,即:n
# 定義時,在普通方法的基礎(chǔ)上添加 @property 裝飾器;
# 定義時,屬性僅有一個self參數(shù)
# 調(diào)用時,無需括號,自動執(zhí)行屬性,并獲取屬性的返回值
# 方法:foo_obj.func()
# 屬性:foo_obj.prop
- 定義屬性的兩種方式
- 裝飾器定義(新式類有三種屬性定義裝飾器,經(jīng)典類只有@property一種)
# ############### 定義 ###############
class Goods(object):
@property
def price(self):
print '@property'
@price.setter
def price(self, value):
print '@price.setter'
@price.deleter
def price(self):
print '@price.deleter'
# ############### 調(diào)用 ###############
obj = Goods()
obj.price # 自動執(zhí)行 @property 修飾的 price 方法,并獲取方法的返回值
obj.price = 123 # 自動執(zhí)行 @price.setter 修飾的 price 方法,并將 123 賦值給方法的參數(shù)
del obj.price # 自動執(zhí)行 @price.deleter 修飾的 price 方法
- 普通字段(所有成員中,只有普通字段的內(nèi)容是保存在對象中的,其他成員均保存在類中,在內(nèi)存中只創(chuàng)建一份)
- 靜態(tài)字段
class Province:
# 靜態(tài)字段
country = '中國'
def __init__(self, name):
# 普通字段
self.name = name
# 直接訪問普通字段
obj = Province('河北省')
print obj.name
# 直接訪問靜態(tài)字段
Province.country
- 普通方法
- 類方法
- 靜態(tài)方法
class Foo:
def __init__(self, name):
self.name = name
def ord_func(self):
""" 定義普通方法,至少有一個self參數(shù) """
# print self.name
print '普通方法'
@classmethod
def class_func(cls):
""" 定義類方法,至少有一個cls參數(shù) """
print '類方法'
@staticmethod
def static_func():
""" 定義靜態(tài)方法 ,無默認參數(shù)"""
print '靜態(tài)方法'
# 調(diào)用普通方法(自動將調(diào)用該方法的對象賦值給self)
f = Foo()
f.ord_func()
# 調(diào)用類方法(自動將調(diào)用該方法的類復(fù)制給cls)
Foo.class_func() # 推薦
f.class_func()
# 調(diào)用靜態(tài)方法(由類調(diào)用)
Foo.static_func() # 推薦
f.static_func
- 普通屬性(屬性存在意義是:訪問屬性時可以制造出和訪問字段完全相同的假象)(屬性由方法變種而來,如果Python中沒有屬性,方法完全可以代替其功能)
# ############### 定義 ###############
class Pager:
def __init__(self, current_page):
# 用戶當前請求的頁碼(第一頁、第二頁...)
self.current_page = current_page
# 每頁默認顯示10條數(shù)據(jù)
self.per_items = 10
@property
def start(self):
val = (self.current_page - 1) * self.per_items
return val
@property
def end(self):
val = self.current_page * self.per_items
return val
# ############### 調(diào)用 ###############
p = Pager(1)
p.start # 就是起始值,即:m
p.end # 就是結(jié)束值,即:n
# 定義時,在普通方法的基礎(chǔ)上添加 @property 裝飾器;
# 定義時,屬性僅有一個self參數(shù)
# 調(diào)用時,無需括號,自動執(zhí)行屬性,并獲取屬性的返回值
# 方法:foo_obj.func()
# 屬性:foo_obj.prop
# ############### 定義 ###############
class Goods(object):
@property
def price(self):
print '@property'
@price.setter
def price(self, value):
print '@price.setter'
@price.deleter
def price(self):
print '@price.deleter'
# ############### 調(diào)用 ###############
obj = Goods()
obj.price # 自動執(zhí)行 @property 修飾的 price 方法,并獲取方法的返回值
obj.price = 123 # 自動執(zhí)行 @price.setter 修飾的 price 方法,并將 123 賦值給方法的參數(shù)
del obj.price # 自動執(zhí)行 @price.deleter 修飾的 price 方法
由于新式類中具有三種訪問方式,我們可以根據(jù)他們幾個屬性的訪問特點,分別將三個方法定義為對同一個屬性:獲取、修改、刪除
class Goods(object):
def __init__(self):
# 原價
self.original_price = 100
# 折扣
self.discount = 0.8
@property
def price(self):
# 實際價格 = 原價 * 折扣
new_price = self.original_price * self.discount
return new_price
@price.setter
def price(self, value):
self.original_price = value
@price.deltter
def price(self, value):
del self.original_price # del刪除的是變量,解除變量和數(shù)據(jù)的引用,而不是刪除數(shù)據(jù)
obj = Goods()
obj.price # 獲取商品價格
obj.price = 200 # 修改商品原價
del obj.price # 刪除商品原價
- 靜態(tài)字段定義(當使用靜態(tài)字段的方式創(chuàng)建屬性時,經(jīng)典類和新式類無區(qū)別)
class Foo:
def get_bar(self):
return 'wupeiqi'
BAR = property(get_bar)
obj = Foo()
reuslt = obj.BAR # 自動調(diào)用get_bar方法,并獲取方法的返回值
print reuslt
property的構(gòu)造方法中有個四個參數(shù)
第一個參數(shù)是方法名,調(diào)用 對象.屬性 時自動觸發(fā)執(zhí)行方法
第二個參數(shù)是方法名,調(diào)用 對象.屬性 = XXX 時自動觸發(fā)執(zhí)行方法
第三個參數(shù)是方法名,調(diào)用 del 對象.屬性 時自動觸發(fā)執(zhí)行方法
第四個參數(shù)是字符串,調(diào)用 對象.屬性.doc ,此參數(shù)是該屬性的描述信息
class Foo:
def get_bar(self):
return 'wupeiqi'
# *必須兩個參數(shù)
def set_bar(self, value):
return 'set value' + value
def del_bar(self):
return 'wupeiqi'
BAR = property(get_bar, set_bar, del_bar, 'description...')
obj = Foo()
obj.BAR # 自動調(diào)用第一個參數(shù)中定義的方法:get_bar
obj.BAR = "alex" # 自動調(diào)用第二個參數(shù)中定義的方法:set_bar方法,并將“alex”當作參數(shù)傳入
del Foo.BAR # 自動調(diào)用第三個參數(shù)中定義的方法:del_bar方法
obj.BAE.__doc__ # 自動獲取第四個參數(shù)中設(shè)置的值:description...
由于靜態(tài)字段方式創(chuàng)建屬性具有三種訪問方式,我們可以根據(jù)他們幾個屬性的訪問特點,分別將三個方法定義為對同一個屬性:獲取、修改、刪除
class Goods(object):
def __init__(self):
# 原價
self.original_price = 100
# 折扣
self.discount = 0.8
def get_price(self):
# 實際價格 = 原價 * 折扣
new_price = self.original_price * self.discount
return new_price
def set_price(self, value):
self.original_price = value
def del_price(self, value):
del self.original_price
PRICE = property(get_price, set_price, del_price, '價格屬性描述...')
obj = Goods()
obj.PRICE # 獲取商品價格
obj.PRICE = 200 # 修改商品原價
del obj.PRICE # 刪除商品原價
類成員的修飾符
- 公有成員,在任何地方都能訪問
- 私有成員,只有在類的內(nèi)部才能訪問
私有成員和公有成員的定義不同:私有成員命名時,前兩個字符是下劃線。(特殊成員除外,例如:init、call、dict等)
class C:
def __init__(self):
self.name = '公有字段'
self.__foo = "私有字段"
class C:
name = "公有靜態(tài)字段"
__name = "私有靜態(tài)字段"
def __init__(self):
...
類的特殊成員
# __doc__ 類的描述信息
class Foo:
""" 描述類信息寫在這里 """
def func(self):
pass
print Foo.__doc__
#輸出:類的描述信息
# __module__ 表示當前操作的對象在哪個模塊
# __class__ 表示當前操作的對象的類是什么
# __init__ 構(gòu)造方法,創(chuàng)建對象時自動執(zhí)行
# __del__ 析構(gòu)方法,對象在內(nèi)存中釋放時自動觸發(fā)執(zhí)行
# __call__ call方法通過對象后加括號執(zhí)行
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print '__call__'
obj = Foo() # 執(zhí)行 __init__
obj() # 執(zhí)行 __call__
Foo()() # 執(zhí)行 __call__
# __dict__ 顯示類或?qū)ο笏鶕碛械某蓡T
class Province:
country = 'China'
def __init__(self, name, count):
self.name = name
self.count = count
def func(self, *args, **kwargs):
print 'func'
# 獲取類的成員,即:靜態(tài)字段、方法
print Province.__dict__
# 輸出:{'country': 'China', '__module__': '__main__', 'func': , '__init__': , '__doc__': None}
obj1 = Province('HeBei',10000)
print obj1.__dict__
# 獲取 對象obj1 的成員
# 輸出:{'count': 10000, 'name': 'HeBei'}
obj2 = Province('HeNan', 3888)
print obj2.__dict__
# 獲取 對象obj2 的成員
# 輸出:{'count': 3888, 'name': 'HeNan'}
# __str__ 打印對象默認輸出該方法的返回值
Python中一切皆是對象
- 類本身也是對象,并且類是由type類創(chuàng)建的
- 類的創(chuàng)建也可以通過type類的構(gòu)造函數(shù)創(chuàng)建
def func(self):
print 'hello xiaozhupeiqi'
Foo = type('Foo',(object,), {'func': func})
#type第一個參數(shù):類名
#type第二個參數(shù):當前類的基類
#type第三個參數(shù):類的成員