1. 封裝(實際封裝python中的封裝只是一個約定)
第一層面的封裝:類就好像一個袋子,這就是一種封裝
第一階段:
# 如果我們要定義學生jack如何定義?
name = 'jack'
age = 17
sex = '男'
這三個變量可以用來形容jack這個人(當然你也可以使用字典,列表去描述).但是我們用三個變量去形容這個人,有什么弊端?
弊端:太零散,如果學生太多,需要有很多變量去描述
為了解決這個問題,因此才有了類。
第二階段:
class Student(object):
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
one = Student('jack',17,'男') # 這里的one就相當於一個學生jack,所有的屬性都封裝到了one變量中。這里的Student類,相當於一個模板。只要給定它name,age,sex,它就能創建出一個學生對象。
two = Student('aaa',16,'男')
three = Student('bbb',15,'女')
four = Student('ccc',14,'男')
five = Student('ddd',13,'女')
print(f'姓名:{one.name} 年齡:{one.age} 性別:{one.sex}')
姓名:jack 年齡:17 性別:男
到這里,不知道你是否已經體會到使用類封裝的便利沒!
第二層面的封裝:類中定義私有的,只有類內部使用,外部無法訪問(比如_(杠) __(杠杠) )
第一階段:
class Student(object):
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
one = Student('plf',18,'男')
one.name = 'who'
one.age = -28
one.sex = '人妖'
print(f'姓名:{one.name} 年齡:{one.age} 性別:{one.sex}')
姓名:who 年齡:-28 性別:人妖
問題:我們在外部能隨意訪問到對象one的屬性,並且隨意修改,這樣數據是不安全的,因為我們需要將屬性隱藏起來。那我們應該如何去做了?
第二階段:
class Student(object):
def __init__(self,name,age,sex):
self.__name = name
self.__age = age
self.__sex = sex
one = Student('plf',18,'男')
print(one._Student__name)
print(one._Student__age)
print(one._Student__sex)
one._Student__age = 20
print(one._Student__age)
rint(one.__name) # 報錯,無該屬性
print(one.name) # 報錯,無該屬性
plf
18
男
20
此時發現,我們雖然不能使用one.name或者one.__name訪問到該屬性。但是我們可使用one._Student__age訪問到對象的age屬性並且能修改。說明python在設置私有屬性的時候,只是把屬性的名字換成了其他的名字。
總結:
類中以_或者__的屬性,都是私有屬性,禁止外部調用。雖然我們可以通過特殊的手段獲取到,並且賦值,但是最好不要這么做(約定俗成)
問題:現在我將name,age,sex設置為私有屬性,但是我又想讓他們通過我指定的接口去訪問或者修改我的屬性,應該如何實現了?
第三階段:
Student(object):
def __init__(self,name,age,sex):
self.__name = name
self.__age = age
self.__sex = sex
def get_name(self):
return self.__name
def set_name(self,name):
if len(name) > 1 :
self.__name = name
else:
print("name的長度必須要大於1個長度")
def get_age(self):
return self.__age
def set_age(self, age):
if age > 0 and age < 150:
self.__age = age
else:
print("輸入的年齡必須要大於0,小於150歲")
one = Student('plf',18,'男')
one.set_name('a') # 通過自己設置接口,可以有效規避臟數據
print(one.get_name()) # 通過接口獲取數據
one.set_age(-9) # 通過自己設置接口,可以有效規避臟數據
print(one.get_age()) # 通過接口獲取數據
name的長度必須要大於1個長度
plf
輸入的年齡必須要大於0,小於150歲
18
這樣我們就自定義了自己屬性的接口,它的好處在於:規避臟數據
問題:使用接口設置獲取數據 和 使用點方法(one.name = 18 或者print(one.name))設置數據相比, 點方法使用更方便,我們有什么方法達到 既能使用點方法,同時又能讓點方法直接調用到我們的接口了? 其他python已經幫我們實現了,讓我們一起看一下吧!
第四階段:
class Student(object):
def __init__(self,name,age,sex):
self.__name = name
self.__age = age
self.__sex = sex
@property
def name(self):
return self.__name
@name.setter
def name(self,name):
if len(name) > 1 :
self.__name = name
else:
print("name的長度必須要大於1個長度")
@property
def age(self):
return self.__age
@age.setter
def age(self, age):
if age > 0 and age < 150:
self.__age = age
else:
print("輸入的年齡必須要大於0,小於150歲")
one = Student('plf',18,'男')
one.name = '張三'
print(one.name)
one.age = 170
print(one.age)
張三
輸入的年齡必須要大於0,小於150歲
18
總結:
- 使用 @property 裝飾器時,接口名不必與屬性名相同.
- 凡是賦值語句,就會觸發set方法。獲取屬性值,會觸發get方法