一,嵌套函數
要點:內部函數只能在函數內被使用,在函數外不可以被使用
使用情況:(1)封裝,數據隱藏。(2)避免重複代碼(3)閉包情況使用
嵌套函數示例如下:
#嵌套函數
def outer():
print('ourer running')
def inner01():
print('inner running')
inner01()
outer()
def printname(ischinese,name,familyname):
def inner(a,b):
print('{0}{1}'.format(a,b))
if ischinese==0:
inner(name,familyname)
else:
inner(familyname,name)
printname(True,'hy','l')
printname(False,'hy','l')
#可分成兩個函數,ischinese,isenglishname來寫,但那樣有重複。
結果如下:
ourer running
inner running
l hy
hy l
二,nonlocal關鍵字
nonlocal用來聲明外部的局部變量
global 用來聲明全局變量
這兩個都可以在內部函數正常調用,但是想要修改必須定義
代碼如下:
a=10
def outer():
b=20
global a
a=20
print(a)
def inner():
nonlocal b
b=30
print(b)
inner()
outer()
結果如下:
20
30
三,LEGB規則
python中查找變量名的時候,先在local(函數內部查找),然後在Enclosed(嵌套函數外部查找),然後在global(模塊)查找,最後在Built in(python爲自己保留的特殊名稱中查找)
代碼如下:
print(type(str))
#str='global'
def outer():
#str='outer'
def inner():
#str='inner'
print(str)
inner()
outer()
結果爲:
<class 'type'>
<class 'str'>
四,面向對象與對象
python即可以面向對象,又可以面向過程
所謂面向對象編程就是:將數據和操作數據的相關方法封裝在對象內
python中一切皆對象,對象其實就是堆內存內的一個內存塊
五,類
類可分爲方法(函數)與屬性(變量)
對象可分爲:方法(由創建它的類規定好的),屬性(變量)
創建一個類的代碼如下:
class Student: #類名一般首字母大寫,多個單詞采用駝峯原則
def __init__(self,name,score):#self必須位於第一個 實例屬性
self.name=name
self.score=score
def say_score(self):
print('{0}的成績爲{1}'.format(self.name,self.score))
s1=Student('lhy',90)#self默認傳,爲對象的地址。爲創建的Student('lhy',90)對象的地址,通過類名調用構造函數
s1.say_score()
s1.age=18
print(s1.age)
print(dir(s1))
print(s1.__dict__)
print(isinstance(s1,Student))
print(isinstance(s1,int))
print(isinstance(Student,type))
結果如下:
lhy的成績爲90
18
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name', 'say_score', 'score']
{'name': 'lhy', 'score': 90, 'age': 18}
True
False
True
解釋代碼:首先,self其實等於創建實例s1或s2的地址,只是self通概表示所有的對象地址。
class Student 這句代碼創建了一個類對象,這裏後面具體說明。
def init 這句代碼定義的是構造函數。
def say_score 定義的是實例方法,但其實具體代碼保存在類對象中,實例對象中只是指向這個函數的地址,所以實例方法其實爲所有實例共享。
當執行s1=Student(‘lhy’,60)時,其實就是在創建一個實例對象,它先調用
(1)new()方法創建一個對象,不過我們一般無需定義
(2)init()方法將lhy,60,傳進去完成初始化,給實例屬性賦值(self.name=name)這裏發生了,在self內的地址中的name等於形參name,也就是實例對象中的name=形參name,在這裏s1=self
當執行s1.say_score()時調用了實例方法。其實會被翻譯爲Student.say_score(s1)
s1.age是添加了一個實例屬性。如果再定義一個s2,則s2中不存在這個實例對象
dir()獲得對象的所有屬性與方法
s1.__dict__對象的屬性字典
isinstance(s1,Student)判斷s1是否屬於Student類
Student屬於type大類
五,構造函數要點
(1)名稱固定
(2)第一個參數爲self
(3)通過類名(參數列表)調用,調用後將創建好的對象返回
(4)構造函數通常用於初始化實例對象的實例屬性
六,實例屬性
從屬於實例對象的屬性,也稱實例變量
(1)一般在構造函數中定義:
self.name=name
(2)在本類的其他實例方法中,通過self進行訪問
如self.name
七,實例方法
從屬於實例對象的方法
注意:類方法爲所有對象共享,兩個不同的實例對象只要屬於同一類,那麼實例方法的代碼用的是同一個,都在該類中,而對象的空間中只有該方法的地址。
調用實例方法時,不需要也不能給self傳參數
八,函數與方法的區別
(1)方法調用時要通過對象來調用
(2)方法需要self
九,類對象
屬於type大類
代碼如下:
class Student: #類名一般首字母大寫,多個單詞采用駝峯原則
def __init__(self,name,score):#self必須位於第一個 實例屬性
self.name=name
self.score=score
def say_score(self):
print('{0}的成績爲{1}'.format(self.name,self.score))
s=Student
s2=s('lhy',60)
s2.say_score()
Student.say_score(s2)
十,類屬性
從屬於類對象,也稱類變量
代碼如下:
class Student:
count=0
company='yzu'#類屬性
def __init__(self,name,score):
self.name=name
self.score=score #實例屬性
Student.count+=1
def sayscore(self):
print('{0}的分數是{1}'.format(self.name,self.score))
s1=Student('lhy',60)#實例對象,自動調用__init__函數
s1.sayscore()
s2=Student('z3',30)
Student.sayscore(s2)
print("一共{0}個人在{1}公司".format(Student.count,Student.company))
結果如下:
lhy的分數是60
z3的分數是30
一共2個人在yzu公司
本例中,student.count與student.company就是類屬性
十一,類方法與靜態方法
類方法:從屬於類對象的方法,用來操作類屬性
通過@classmethod來定義
格式爲:@classmethod
def 類方法名(cls,【形參列表】):
函數體
要點:(1)@classmethod必須在第一行
(2)第一個cls必須有,指向類函數本身
(3)類名.類方法名(參數列表) ,不需要也不能給cls傳值
(4)類方法中訪問實例屬性或方法會報錯
(5)子類繼承父類方法時,傳入cls的是子對象而非父對象。
靜態方法:python中允許定義與類對象無關的方法
格式如下:@staticmethod
def 靜態方法名(【參數列表】)
函數體
在其中也可以 引用類屬性
代碼如下:
class Student:
company='yzu'
@staticmethod
def add(a,b):
print('{0}+{1}={2}'.format(a,b,a+b))
print(Student.company)
@classmethod
def printc(cls):
print('公司是',cls.company)#要加Student,也可以加cls
Student.printc()
Student.add(1,2)
結果如下:
公司是 yzu
1+2=3
yzu
從某種含義上來說,cls=Student,但是在調用時,不可以用cls代替Student
十二,析構函數和垃圾回收機制
__del__方法被稱爲析構函數,用來實現對象被銷燬時所需操作
垃圾回收機制:當對象的引用計數爲0時,垃圾回收器調用__del__方法
可以用del刪除對象來確保調用__del__方法
代碼如下:
class none:
def __del__(self):
print('被銷燬的對象是{0}'.format(self))
q1=none()
q2=none()
del q2#其實就是調用__del__函數,所以先刪除q2
print(q1)
結果爲
被銷燬的對象是<__main__.none object at 0x000001E0300FD848>
<__main__.none object at 0x000001E0300FD7C8>
被銷燬的對象是<__main__.none object at 0x000001E0300FD7C8>
十三,__call__方法與可調用對象
用__call__方法定義的對象叫做可調用對象,即該對象可以像函數一樣被調用
代碼如下:
class Salary:
def __call__(self, salary):
yearsalary=salary*12
daysalary=salary/30
hoursalary=daysalary/8
return dict(hoursalary=hoursalary,daysalary=daysalary,mouthsalary=salary,yearsalary=yearsalary)
def p(self):
print('執行了')
s=Salary()
print(s(30000))
結果爲:
{'hoursalary': 125.0, 'daysalary': 1000.0, 'mouthsalary': 30000, 'yearsalary': 360000}
注意前面說的__call__方法與__del__方法是與構造函數一個等級的,他們作用的類創建出來的對象。
在__call__方法中,要注意這一句s=Salary()不能傳參數,參數要在後面傳。