python基礎學習淺學類

小知識點:
面向對象和麪向過程:::
(1)面向過程(親力親爲): 煮飯,洗菜,洗碗,切菜,炒菜,出鍋 吃飯
(2)面向對象(凡事都是對象來做):女朋友(煮飯,洗菜,洗碗,切菜,炒菜,出鍋) 我們直接 吃飯
點外賣 吃飯

一.類 (抽象)

類是一個獨立存放變量(屬性/方法)的空間。(把一些事物的共有特點封裝起來。)
實例也是一個獨立存放變量的空間。(每個實例都是一個獨立的變量空間,不同實例之間的空間不可見)

類名要大寫,實例名要小寫。

實例名.屬性名 調用某一個實例屬性。
類名.屬性名 調用封裝在類裏面的類的屬性。

類編碼風格:
類名應採用駝峯命名法,即將類名中的每個單詞的首字母都大寫,而不使用下劃線。實例名
和模塊名都採用小寫格式,並在單詞之間加上下劃線。
對於每個類,都應緊跟在類定義後面包含一個文檔字符串。這種文檔字符串簡要地描述類的
功能,並遵循編寫函數的文檔字符串時採用的格式約定。每個模塊也都應包含一個文檔字符串,
對其中的類可用於做什麼進行描述。
可使用空行來組織代碼,但不要濫用。在類中,可使用一個空行來分隔方法;而在模塊中,
可使用兩個空行來分隔類。
需要同時導入標準庫中的模塊和你編寫的模塊時,先編寫導入標準庫模塊的 import 語句,再
添加一個空行,然後編寫導入你自己編寫的模塊的 import 語句。在包含多條 import 語句的程序中,
這種做法讓人更容易明白程序使用的各個模塊都來自何方。

定義:
class 類名:
pass

1.例如:
class Person: #定義類名要首字母大寫。
a = ‘兩隻手,兩條腿’ #封裝在類裏面類中的屬性
#類,是一個獨立存放變量(屬性/方法)的空間。

wumou = Person() #實例名 = 類名() 實例
zhangmou = Person()

wumou.name = “吳某” #實例的特徵 實例屬性 (一個實例的特徵,就是屬性)
wumou.age = 18
zhangmou.age = 20

print(Person.a) #調用類的屬性
print(wumou.age) #調用實例屬性

類與實例之間的關係:::
(1)類:::
是一類事物的抽象,不是真實存在的,描繪了該類事物的共性。
例如:“人”,“動物”
(2)實例:::
某類事物的具體個體,是該類事物的具體表現,它是真實存在的。
例如:“吳某”是具體的某個人,
“張某”也是具體的某個人。

2.私有屬性:
在python中有兩個私有屬性,分別是在屬性前加一個下劃線()和兩個下劃線()
一個下劃線外部可以直接訪問,兩個下劃線外部不能直接訪問。

一個下劃線只是做簡單的標記。
兩個是私有屬性,不能夠直接使用。
python當中的私有屬性沒有絕對的私有。

class Person:
_sex = “男”
__age = 18

wuhan = Person() #實例

print(Person._sex) #調用類屬性
print(Person.__age) #雙下劃線會報錯,不可以直接訪問雙下劃線變量名
print(Person._Person__money) #這樣就可以訪問雙下劃線的屬性

###在python中,_和__的使用更多的是一種規範/約定,沒有真正限制的目的###
###定義類中的私有屬性也可以被子類繼承###

小知識點:::
dir() 可以查看方法,裏面可以放類名。

3.類裏面的方法
方法就是封裝在類裏面的一種特殊函數。

例:
class Person:
def sing(self): #方法,在類裏面寫函數叫做在類裏面定義方法。
print(“我最帥!”) #裏面有一個默認值none。 print(“我最帥!”,none)

wuhan = Person() #定義實例,寫類必備。

wuhan.sing() #調用類裏面的方法。 格式:實例化對象.方法()
Person.sing(self = ‘要傳入的東西’)

實例方法 的調用過程和 self:::
(1)self:通常,將默認會傳入的那個參數命名爲self,用來表示調用這個方法的實例對象本身。
(2)實例方法:方法總是定義在類中,但是卻叫“實例方法”,因爲它表示該類所有實例所共有的行爲。

小知識點:::self指的是實例,誰去使用它,那麼它就是誰。
例:
class Person:
def sing(self):
print(“老師在唱歌%s”%self.geci)
print(id(self)) #會發現此處的self的id和下面的laoshi的id是一樣的
laoshi = Person() #在這個實例中,laoshi使用了self,所以self就是laoshi
print(id(laoshi))
#和函數的傳參一樣,只是會先傳一個自身的實例self

laoshi.geci = “溫暖了寂寞”

laoshi.sing()

  1. init 雙下劃線
    初始化方法,作用是在實例化的時候,自動調用。(魔法方法)

“初始化”特殊方法:
在Python中有很多以雙下劃線開頭且以雙下劃線結尾的固定方法,它們會在特定的時機被處罰執行。
__init__就是其中之一,它會在實例化之後自動被調用。以完成實例的初始化。

可以在創建對象時,爲對象實現一些初始化的操作,提供一些默認值,需要爲類定義實例屬性的時候纔會執行__init__方法。

class Person:
def init(self.name):
self.name = name #self.name是實例屬性;name是方法。

 def sing(self):
	 print('吳某最帥')

wumou = Person(“吳某”) # 實例化 自動調用我們的初始化方法,把吳某這個名字給了name
(這句代碼意味着 wumou.name = “吳某”(定義一個實例屬性) wumou.name相當於self.name,"吳某"相當於給了name)

魔法方法:每一個魔法方法都有它特定的功能。

小知識點:
在python中,指向被刪除了,就會被回收。
del刪除指向,一個變量指向沒有了就會被回收。
del調用的就是__init__魔法方法。
例如:列表方法中,del 列表名,再查看這個列表的時候就會報錯,因爲del把指向刪除了。

del 析構,也叫銷燬初始化方法(銷燬上面的那個),是在這個文件運行完然後觸發。(魔法方法)

__del__就是一個析構函數,當使用del刪除對象時,會調用它本身的析構函數。提示開發者,對象被銷燬了,方便調試,進行一些必要的清理工作
淺顯點理解就是:(當實例對象引用數爲0的時候就會調用這個魔術方法)
即當類裏面使用了del魔法方法的時候,如果使用了del刪除,那麼就會調用__del__魔法方法;如果沒有使用del刪除,那麼在程序的最後,會自動回收內存地址,就會調用__del__魔法方法。

入門:
class Person:
pass

hansha = Person()
print(hansha) #輸出爲:hansha這個實例化的對象指向的對象。即爲:<main.Person object at 0x00000175C3AFC1D0>
del hansha
print(hansha) #輸出會報錯,因爲指向被刪除了。即爲:NameError: name ‘hansha’ is not defined

稍微升一點級:
python中一個程序執行完了,內存空間就會被回收,回收掉那麼指向就沒有了。
class Person:
def del(self): #相當於重寫了python的__del__方法。在列表裏使用del刪除時調用的是python默認的__del__方法。
print(‘好好學習’)

hansha = Person()
print(11111)
print(22222)
輸出爲:
11111
22222
好好學習

來個對比的例子仔細看看:
當指向刪除完了之後會調用__del__魔法方法。
class Person:
def del(self):
print(‘好好學習’)

hansha = Person()
print(11111)
del hansha
print(22222)
輸出爲:
11111
好好學習
22222

總結的高級版:
基於變量計數的對象銷燬機制
當沒有一個變量指向某個對象的時候,python會自動銷燬這個對象,以便回收內存空間。
del關鍵字,可以刪除一個變量的指向。
class Person:

def __init__(self,name):    #初始化方法
	self.name = name

def __del__(self): 			#析構方法(銷燬方法)
	print(self.name,"被銷燬了")

wuhan = person(“無名”)
del wuhan #輸出爲:被銷燬了

這裏爲引用了《python編程從入門到實踐》
二,
繼承:

例子:
class Car():
“”“一次模擬汽車的簡單嘗試”""
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_name = str(self.year) + ’ ’ + self.make + ’ ’ + self.model
return long_name.title()
def read_odometer(self):
print(“This car has " + str(self.odometer_reading) + " miles on it.”)
def update_odometer(self, mileage):
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print(“You can’t roll back an odometer!”)
def increment_odometer(self, miles):
self.odometer_reading += miles

class ElectricCar(Car):
“”“電動汽車的獨特之處”""
def init(self, make, model, year):
“”“初始化父類的屬性”""
super().init(make, model, year)
#讓一個類繼承另一個類後,可添加區分子類和父類所需的新屬性和方法。
如:self.battery_size = 70

我們還添加了一個名爲 describe_battery() 的方法,它打印有關電瓶的信息

( def describe_battery(self):
“”“打印一條描述電瓶容量的消息”""
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() )

my_tesla = ElectricCar(‘tesla’, ‘model s’, 2016)
print(my_tesla.get_descriptive_name())

首先是 Car 類的代碼。創建子類時,父類必須包含在當前文件中,且位於子類前面。
我們定義了子類 ElectricCar 。定義子類時,必須在括號內指定父類的名稱。方法 init()
接受創建 Car 實例所需的信息。

super() 是一個特殊函數,幫助Python將父類和子類關聯起來。這行代碼讓Python調用
ElectricCar 的父類的方法 init() ,讓 ElectricCar 實例包含父類的所有屬性。父類也稱爲超
類(superclass),名稱super因此而得名。也可以直接Car.init()。
在子類中調用父類的初始化方法格式是:父類名.init(self) 但是super是直角包括所有父類,但是父類名的需要一個個寫。

爲測試繼承是否能夠正確地發揮作用,我們嘗試創建一輛電動汽車,但提供的信息與創建普
通汽車時相同。我們創建 ElectricCar 類的一個實例,並將其存儲在變量 my_tesla 中。這
行代碼調用 ElectricCar 類中定義的方法 init() ,後者讓Python調用父類 Car 中定義的方法
init() 。我們提供了實參 ‘tesla’ 、 ‘model s’ 和 2016 。
除方法 init() 外,電動汽車沒有其他特有的屬性和方法。當前,我們只想確認電動汽車
具備普通汽車的行爲:

2016 Tesla Model S

#####1.
重寫父類的方法:
對於父類的方法,只要它不符合子類模擬的實物的行爲,都可對其進行重寫。爲此,可在子
類中定義一個這樣的方法,即它與要重寫的父類方法同名。這樣,Python將不會考慮這個父類方
法,而只關注你在子類中定義的相應方法。

多繼承中super調用所有父類的被重寫的方法。super本質是用mor算法的順序調用的。

父類也稱爲基類。

######2.
導入類:
Python允許你將類存儲在模塊
中,然後在主程序中導入所需的模塊。

將 Car 類存儲在一個名爲car.py的模塊中,使用該模塊的程序都必須使用更具體的文件名,如my_car.py,其中只包含 Car 類的代碼。
我們包含了一個模塊級文檔字符串(在該模塊的最上面),對該模塊的內容做了簡要的描述。你應爲自己
創建的每個模塊都編寫文檔字符串。

下面來創建另一個文件——my_car.py,在其中導入 Car 類並創建其實例:

from car import Car #從一個只包含一個類的模塊中導入這個類

from car import ElectricCar #從一個包含多個類的模塊中導入一個類

from car import Car, ElectricCar #從一個有多個類的模塊中導入多個類

import car #導入整個模塊 我們使用語法 module_name.class_name 訪問需要的類

from module_name import * #導入模塊中的所有類 (不建議使用,如果要用,推薦使用導入整個模塊)

import 語句讓Python打開模塊 car ,並導入其中的 Car 類。這樣我們就可以使用 Car 類了,
就像它是在這個文件中定義的一樣。

######3.
繼承:
可以處理功能的迭代更新,以及拓展
重用代碼,方便代碼的管理和修改。

類名.bases 可以查看類的父類有哪些,注意要print。

每一個類,如果你不寫繼承,那麼這個類繼承的就是object。
class Father(object): #object默認自動創建了__init__初始化方法
#父類
pass

fa = Father() #實例,自動調用父類的__init__ 初始化方法就叫做繼承。

例子:
class Father: 父類

def eat(self):
	print('大吃一頓')

class Son1(Father): #子類Son1繼承父類Father
pass

hansha = Son1()
hansha.eat() #子類Son1可以使用父類Father中的eat方法。

高級的來咯!!!
多繼承:::
多繼承優先級:從左往右,優先級由高到低。
如果繼承的兩個父類有同樣的方法,那麼會選擇優先級高的方法,即子類會優先使用最先被繼承的方法。
class Father:
def init(self,name,age):
self.name = name

def eat(self):
	print('大吃一頓')

class Mother:
def init(self,name,age,sex):
self.name = name

def cook(self):
	print('做菜')

class Son(Father,Mother):
pass

hansha = Son(‘寒沙’,18)
hansha.eat()
hansha.cook()

最高級的來啦!!!

class Base:
def play(self):
print(‘這是Base’)

class A(Base):
def play(self):
print(‘這是A’)
super().play() #這裏調用的是B

class B(Base):
def play(self):
print(‘這是B’)
super().play() #這裏調用的是Base

class C(A,B):
#當子類繼承父類之後,如果子類不想使用父類的方法,可以通過重寫來覆蓋父類的方法
def play(self):
print(‘這是C’)
# #重寫父類方法之後,如果又需要使用父類的方法:
# B().play() #第一種方法 實例化,再使用方法
# A.play(self) #第二種方法 類名使用這個方法
super().play() #這裏調用的是A
c = C()
c.play()
print(C.mro) #可以通過調用類的__mro__屬性或者mro方法來查看類的繼承關係
#輸出爲(<class ‘main.C’>, <class ‘main.A’>, <class ‘main.B’>, <class ‘main.Base’>, <class ‘object’>)

#super可以使用父類的方法;在父類中也可以使用super函數;要滿足mro算法規則
#根據mro的順序來決定調用的是誰

#在python3中,類被創建時會自動創建方法解析順序mro

######4.
mro順序 算法 保證程序能夠按序執行。

mro順序的作用:
#保證所有的類在用(構造)他的時候只被用(構造)一次!
保證多繼承的時候,每個類只出現一次。
super().init() 相當於使用了mro。

#######6.
定製屬性訪問 (增,刪,改,查)
就是對類裏的屬性進行增刪改查的操作
(1)增
setattr(實例名,“屬性名”,值) 或者 實例名.屬性 = 值

(2)刪
delattr(實例名,“屬性名”) #只能刪除自己家的屬性

(3)改
setattr(實例名,“屬性名”,“新屬性”) #有這個屬性纔可以修改

(4)查
hasattr(實例名,“屬性名”) #返回布爾值,有就True,沒有就False
或者
getattr(實例名,“屬性名”) #存在就能取到這個值,不存在就報錯

可以用成 實例名.getattr(“屬性名”) 上面的幾個也可以(因爲在python裏面已經定義好了,已經有源碼),但是hasattr不可以,沒有這個方法。
但是用這種方法時,要在類裏面定義這種方法。(重寫方法)
例如:
def getattribute(self,item):
return “屬性不在”
把這個寫在類裏面作爲一個方法。
重寫一個源碼,python會返回你重寫的這個方法的返回值,而不會再執行源碼。

舉例說明:
class Rectangle:
#__init__不能使用return
def init(self,length,width):
self.length = length
self.width = width

def area(self):
    #使用self 那個實例去使用它,它就是誰
    return(self.length*self.width)

a = Rectangle(4,5)
################查
#判斷實例有沒有這個屬性
print(hasattr(a,‘length’)) #輸出aTrue
#實例的這個屬性值是什麼 獲取值,沒有就報錯
print(getattr(a,‘length’)) #輸出4

################改
setattr(a,‘width’,50) #本來應該是5,現在改成了50
#還可以寫成: re .setattr(‘width’, 50)
print(getattr(a,‘width’)) #輸出就是50

################增
#第一種:
#setattr 有則改,無則增
print(hasattr(a,‘name’)) #在這裏實例a裏面沒有屬性name。輸出False
setattr(a,‘name’,‘hansha’) #沒有就增加屬性name
#還可以寫成:a.setattr(‘name’, ‘hansha’)
print(hasattr(a,‘name’)) #上一句增加了name屬性。輸出True
#第二種:
a.age = 18

################刪
print(getattr(a,‘age’)) #因爲上面增加了屬性age。輸出爲True
delattr(a,‘age’) #刪除屬性age
#還可以寫成:a.delattr(‘age’)
print(getattr(a,‘age’)) #上面刪除了屬性age。輸出爲False

(1) + 調用的是__add__

class A:
def init(self,num1,num2):
self.num1 = num1
self.num2 = num2

def __add__(self,other):      #self  實例對象   ;   other  另外一個實例對象
	sum1 = self.num1 + other.num1
	sum2 = self.num2 + other.num2
	return sum1,sum2

a = A(1,2)
b = A(3,4)
print(a+b) #輸出爲 (4,6)

運算符方法(瞭解即可)
add(self,other) # x+y
sub(self,other) # x-y
mul(self,other) # xy
mod(self,other) # x%y
iadd(self,other) # x+=y
isub(self,other) # x-=y
radd(self,other) # y+x
rsub(self,other) # y-x
imul(self,other) # x
=y
imod(self,other) # x%=y

(2)在交互模式下輸出的交互信息與直接print的信息有些不同,
背後的原理是 ?
str和repr原理:

return返回的必須是字符串。
print打印實例對象的時候(沒有重寫__repr__方法,直接是pass)顯示的是 地址
如果重寫了__repr__方法,那麼打印的就是__repr__方法裏面的東西
如果同時重寫了__repr__和__str__方法,打印實例對象的時候,只會顯示__str__裏面的內容
例一:::
class Person:

def __repr__(self):
	return '這是一個repr方法'

def __str__(self):
	return '這是一個str方法'

p = Person()
print§ 輸出爲: 這是一個str方法

%s 使用的是__str__方法; %r 使用的是__repr__方法
例二:::
class Person:

def __repr__(self):
	return '這是一個repr方法'

def __str__(self):
	return '這是一個str方法'

p = Person()
print(’ %s’%p) 輸出爲:這是一個str方法
print(’ %r’%p) 輸出爲:這是一個repr方法

在python中,str和repr方法在處理對象的時候,分別調用的是對象的__str__和__repr__方法
print打印對象,調用str函數,如果對象沒有定義__str__方法,則調用__repr__方法處理
在交互模式下,直接輸出對象,顯示 repr 的返回值

(3) 魔術方法 def call(self)
正常情況下,實例是不能像函數一樣被調用的,要想實例能夠被調用,就需要定義 call 方法
class Person:

def a(self):
	print('this is a ')

#實例對象加上括號就會自動調用call方法
def __call__(self,*args,**kwargs):
	print('this is call')

p = Person()
p() #輸出爲: this is call

拓展:
類中的一些查詢相關信息的方法(瞭解既可)
1、class 查看類名

格式:  實例.__class__

2、dict 查看全部屬性,返回屬性和屬性值鍵值對形式

格式:實例.__dict__

3、doc 查看對象文檔,即類中(用三個引號引起來的部分)

格式:類名.__dict__

4、bases 查看父類

格式:類名.__base__

5.mro 查看多繼承的情況下,子類調用父類方法時,搜索順序

格式:子類名.__mro__

          	              實例.__class__.__mro__

(4)再來個魔術方法
類每次實例化的時候都會創建一個新的對象,如果要求類只能被實例化一次該怎麼做呢?
__new__方法

舉個例子:::
class Person:

#初始化
def __init__(self):
    print('this is init')

def __new__(cls, *args , **kwargs):
    print('這new方法在init之前就進行了調用')
    #重寫new方法
    #new方法是最先被調用的
    #new 必須返回父類的new方法,程序才能繼續往下運行,如果不返回,即沒有下面這行程序就不會往下運行。
    return super().__new__(cls)

hansha = Person()

四個點理解__new__方法:
1、__new__方法是在類創建實例的時候
自動調用的。
2、實例是通過類裏面的__new__方法是在
類 創建出來的。
3、先調用__new__方法創建實例,再調用 __init__方法初始化實例。
4、__new__方法,後面括號裏的cls代表
的是類本身

在上面的例子中,我們可以看到創建實例的時候,自動調用了__new__,方法和__init__方法,並且
是先調用的__new__(__new__方法會在內存當中開闢一個空間)再調用的__init__方法,打印 cls 的時候顯示的這個Person類

#######
new方法會開闢空間
每次實例化,這個new方法都會開闢一個新的空間
可不可以讓這new方法只開闢一個空間:::單例模式

單例模式:

提前引入一些小知識點:::
第一個:
hasattr() #has attribute
hasattr() 函數用於判斷對象是否包含對應的屬性
hasattr(object(對象),name(“字符串,屬性名”))
返回True(有的時候) False(沒有的時候)

class Person:
#範式:固定的公式;固定的寫法
def new(cls,*args,**kwargs):
#hasattr 判斷類裏面有沒有這個方法
#如果類沒有instance這個屬性
if not hasattr(cls,‘instance’): #cls就是Person這個類本身
#沒有instance這個屬性就會執行下面這句
#創建instance這個屬性,等於父類的new方法
#new返回父類的new方法,和返回instance都可以
cls.instance = super().new(cls) #上面說如果類沒有instance這個屬性就執行這句,把父類的new方法添加爲類本身的屬性
#在下一句在return這個類本身的這個instance屬性,這樣在第二次實例化的時候,return
#的仍然是第一次實例化的cls.instance,就沒有返回父類的new方法,也就沒有創建新的內存
#空間,而是仍然指向第一次創建的內存空間
return cls.instance #如果把返回的改爲 super().new(cls),直接返回父類的new方法,這就不是單例模式,因爲每次實例化都會返回父類
#的new方法,即創建一個新的內存空間。
def init(self,name):
self.name = name

a = Person(‘寒沙’)
b = Person(‘敢敢’)
print(id(a))
print(id(b))

會發現兩次的id都一樣了,即兩次指向同一片內存空間,相當於a被b覆蓋了。
意味着這兩個其實引用的是同一個實例,是一個實例的不同名字

(3)描述符
描述符協議:python描述符是一個“綁定行爲”的對象屬性,在描述符協議中,
它可以通過方法重寫屬性的訪問。這些方法有__get__(), set(), 和__delete__()。
如果這些方法中的任何一個被定義在一個對象中,這個對象就是一個描述符

舉例說明:
#描述符:描述符就是類裏面的屬性base
#控制實例對象a訪問 這個屬性 (base) 可以做一些額外的操作
#描述符 定義了__get__ set delete 當中的一種
class Base:
def get(self,instance,owner):
print(‘恭喜玩家獲得荒古寶典’)
def set(self, instance,value):
print(‘強化%s’%value)
def delete(self,instance):
print(‘武器已經損壞’)

class A:
base = Base()

#實例化
a = A()

a.base # get 會直接輸出__get__方法裏面的內容

a.base = 50 # set 會直接輸出__set__方法裏面的內容

del a.base # delete 會直接輸出__delete__方法裏面的內容

(4)裝飾器:
原因:python是一個動態語言,因爲一切都是對象。是一個腳本語言。

#########################第一個:
首先咱再看遍閉包是啥:
#閉包
def fun1():
print(‘fun1’)
def fun2():
print(‘fun2’)
return fun2

#fun1()() ===> fun2()
a = fun1()
a() #會執行兩個函數

然後,咱稍微高級點,看看閉包參數。這種方法比較麻煩,所以下面就引入了裝飾器,和這個的功能一模一樣,不過
簡單了許多:
#閉包裏面有參數 回調函數
def aa(fun): #fun = f1
print(’------------aa’)
def bb():
fun() #fun() = f1()
print(’----------bb’)
return bb

def f1():
print(‘this is f1’)

def f2():
print(‘this is f2’)

cc = aa(f1)
cc() #輸出爲 ------------aa
this is f1
----------bb

最後,就來看看第一種裝飾器:

#裝飾器 在不改變原有函數的基礎上面增加額外的功能
#裝飾器
def aa(fun): #fun = f1
print(’------------aa’)
def bb():
fun() #fun() = f1()
print(’----------bb’)
return bb

#裝飾器 被裝飾的函數名字(f1)會被當做參數傳遞給裝飾函數(aa)
#代碼就是: aa(f1)
#裝飾函數(aa)執行完它自己內部的代碼之後,會把它的結果返回給
#被裝飾的函數(f1)
#代碼就是: f1 = aa(f1)
#然後下面又是f1() 就相當於 aa(f1)()

@aa # 就相當於 f1 = aa(f1) 要使用嵌套函數裏面的內容 aa(f1)(),就是最後調用的時候f1加個括號
# 而注意函數外部的只要用到裝飾器就會執行,而嵌套的內層函數需要調用纔會執行,所以
# 用處就是把重要的東西寫到嵌套的內層函數,在調用的時候纔會執行
def f1():
print(‘this is f1’)

def f2():
print(‘this is f2’)

f1() #輸出和上面一個一模一樣

############################第二個:
#類裏面的內置裝飾器
引入:

class Base:

def fun(self):
    print('好好學習,天天向上')

b = Base()
b.fun() # 調用類裏面的方法,就會執行類裏面的方法fun,打印 好好學習,天天向上

########
第一個是把類裏面的方法變爲屬性:
class Base:
name = ‘寒沙’

@property         #將方法變爲屬性  更加簡潔
def fun(self):
    return('好好學習,天天向上')

b = Base()
print(b.name) #屬性的使用不需要加括號;方法的使用纔要加括號
print(b.fun) #現在類裏面的方法fun就變成了類的屬性
#輸出爲:
寒沙
好好學習,天天向上

########
第二個是把類裏面的方法變爲靜態方法,讓其可以像使用函數一樣去使用,而不需要再實例化才能使用:
class Base:

@staticmethod       #靜態方法  方法能夠像函數一樣的去使用, 比如在類裏面,你要寫一些閉包什麼的就可以在這裏面寫,相當於擴展了一些功能。
def fun2():              # 注意:這裏已經不需要self   和class類斷開聯繫
    print('過年好,新年好')

#再來個不加裝飾器的
def func(self):
    print('這是普通方法')

Base.fun2() # fun2已經變爲靜態方法,可以像使用函數一樣的使用
#輸出爲: 過年好,新年好

Base是類名;Base() 就是實例化
Base().func() # 而沒有使用裝飾器的方法就需要先實例化,才能去使用
#輸出爲:這是普通方法

########
第三個是類方法

class Base:

def func(self):
    print('這是普通方法')

@classmethod
def fun3(cls):        #沒有self   和實例無關,這是類方法  ;   有self的是實例方法,需要先實例化才能使用
    print('cls類方法')
    cls().func()      #cls 代表類本身,即Base這個類

#類方法的使用,也不用實例化 直接類名點方法
Base.fun3()

###########################第三個:
#類裝飾器 必須使用__call__方法
class Base:

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

def __call__(self,*args,**kwargs):
    print('this is call')

@Base # func = Base(func) 被裝飾函數(func)當做參數傳遞給裝飾函數(Base)
def func():
print(‘this is func’)

func() # 此處的括號就相當於 func() = Base(func)()
# __call__方法只要實例化就會被調用
#輸出爲: this is call

看看高級點的:
class Base:

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

def __call__(self,*args,**kwargs):
    self.fun()         #就會打印    this is func
    print('this is call')

def __str__(self):
    return 'this is str'

@Base # func = Base(func) 相當於實例化 被裝飾函數(func)當做參數傳遞給裝飾函數(Base)
def func():
print(‘this is func’)

func() # 此處的括號就相當於 func() = Base(func)()
# __call__方法只要實例化就會被調用
print(func) # 打印類的實例,就會調用類裏面的__str__方法

#輸出爲:
this is func
this is call
this is str

拓展一下唄:::
來個裝飾器的習題:
測試type和isinstance兩個函數,那個速度更加的快
#程序運行速度比較快 只查看上面兩個
函數 運行一次的時間顯示不出來效果
可以查看循環一萬次的時間

#time.time() 計算目前的時間 時間戳(格林威治時間, 1970.1.1到現在的總秒數)
import time

def funa(fun):
def funb():
a = time.time()
fun()
b = time.time()
print(‘函數運行了%s’%(b-a))
return funb

@funa
def f1():
for i in range(100000):
type(1)
f1()
@funa
def f2():
for i in range(100000):
isinstance(1,int)
f2()

(3)多態
:提高了方法的靈活程度

class Student(object):
def print_uid(self):
print(“我是UID”)

class VIPStudent(Student):
print(“我是VIP學院”)

class PutongStudent(Student):
print(“我是普通學員”)

class BaianStudent(Student):
print(“我是賣課程的,爲你們服務的”)

class Jiezhang(object):
def jiezhang(self,student:Student):
student.print_uid()

zhouzhanghong = Student() #實例化

baiyintao = VIPStudent()

cuihaolin = PutongStudent()

baian = BaianStudent()

check = Jiezhang()

check.jiezhang(zhouzhanghong)
check.jiezhang(baiyintao)
check.jiezhang(cuihaolin)
check.jiezhang(baian)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章