Day-15 - 類和對象(2018-10-18)

一、昨日內容復習

1.類:擁有相同屬性和相同功能的對象的集合(抽象)
屬性 -> 存儲數據(對象屬性,類的字段)
功能 -> 方法(對象方法,類方法和靜態方法)

class 類名(父類):
類的內容

2.對象: 類的實例(具體)
對象 = 類名()

3.構造方法和init方法
構造方法: 聲明類的時候,系統會自動創建一個函數,這個函數的函數名和類名一樣。這個方法就是構造方法。
構造的作用就是創建對象,并且自動的去調用init方法

init方法:a.系統在創建對象的時候自動調用。
b.可以有除了self以外的其他參數,如果要給這些參數傳參,需要使用構造方法來傳
c.需要給類添加對象屬性

  • 構造方法給init方法傳參的原理:
# 偽代碼
# def Person():
#     obj = malloc(4)
#     obj.__init__()
#     return obj

# 構造方法給init方法傳參的原理
# def dog_init(name, age, sex):
#     print(name, age, sex)
#
# def Dog(*args, **kwargs):
#     dog_init(*args, **kwargs)
#
# Dog('abc', 23, sex='男')

4.對象方法: 直接聲明在類中的函數就是對象方法,有默認參數self,并且要通過對象,調用的時候不用給self傳參
對象.對象方法,系統會將前面的對象傳遞給對象方法中的self

5.對象的屬性
a.聲明在init方法中
b.self.屬性 = 值

要通過對象去使用(增刪改查)

6.類的字段(類的屬性)
聲明在類中,函數的外面的變量;通過類來使用(不管在哪兒用)

7.對象.__dict__

二、類方法和靜態方法

類中方法:對象方法、類方法和靜態方法

1.對象方法:
a.直接聲明在類中
b.自帶參數self
c.通過對象來調用

2.類方法:
a.將函數聲明在@classmethod后面的函數就是類方法
b.自帶參數cls(cls在函數調用的時候不用傳參,系統會自動將調用這個方法的類賦給它)
c.通過類來調用

3.靜態方法:
a.聲明在@staticmethod后面的函數就是靜態方法
b.沒有自帶參數
c.通過類來調用

4.怎么選擇使用哪種方法(重點!!!):
對象方法:如果實現函數的功能需要用到對象的屬性,那么就把這個函數聲明成對象方法
靜態方法和類方法:實現函數的功能不需要用到對象的屬性,就可以使用靜態方法或者類方法
類方法:在不使用對象屬性的前提下,需要使用類
靜態方法:既不需要對象的屬性,也不需要類

class Person:
    num = 61
    # 聲明一個類方法
    @classmethod
    def destory(cls):
        # cls指向的是當前類,調用這個方法的類可以做的事情,cls都能做
        print('cls:', cls, cls.num)
        p2 = cls()

        print('人類破壞環境')

    # 聲明一個靜態方法
    @staticmethod
    def func1():
        print(Person.num)
        p3 = Person()
        print(p3)
        print('人類的靜態方法')


Person.destory()
print(Person)
print(Person.num)
p1 = Person()


class Student(Person):
    pass

Student.func1()
Student.destory()
Person.func1()
Person.destory()
# cls: <class '__main__.Person'> 61
# 人類破壞環境
# <class '__main__.Person'>
# 61
# 61
# <__main__.Person object at 0x00000000024D6588>
# 人類的靜態方法
# cls: <class '__main__.Student'> 61
# 人類破壞環境
# 61
# <__main__.Person object at 0x00000000024D6630>
# 人類的靜態方法
# cls: <class '__main__.Person'> 61
# 人類破壞環境
class Math:
    pi = 3.1415926

    @classmethod
    def circle_area(cls, radius):
        return cls.pi * radius ** 2

    @staticmethod
    def sum(num1, num2):
        return num1 + num2


class Number:
    def __init__(self):
        self.value = 0
        self.type = int
        self.id = None

    @staticmethod
    def max():
        return 100

    @staticmethod
    def min():
        return -100


num = Number()
num.value = 1000
print(Number.max())  # 100

三、私有化

類中的內容默認都是公開的(在類的外面可以使用)

1.私有化
將類的內容在類的外面隱藏
在類中的方法名或者屬性名前加兩個下劃線
私有的方法和屬性,只能在類的內部使用,不能在類的外部使用

2.私有的原理
python中沒有真正的私有化(沒有從訪問權限上去限制內容的訪問)
私有的原理就是在私有的屬性名或者方法名前加前綴'_類名',來阻止外部直接通過帶兩個下劃線的名字去使用私有屬性和方法

class Person:
    # 私有字段
    __num = 61

    def __init__(self, name, age):
        self.name = name
        # 私有的對象屬性
        self.__age = age

    def show_age(self):
        print(self.__age)
        self.__func1()

    # 私有的對象方法
    def __func1(self):
        print('私有對象方法')


p1 = Person('小明', 23)
print(p1.name)
# print(p1.age)  # AttributeError: 'Person' object has no attribute 'age'
# print(p1.__age)  # AttributeError: 'Person' object has no attribute 'age'
p1.show_age()
# 23
# 私有對象方法
# p1.__func1()  # AttributeError: 'Person' object has no attribute 'age'
print(p1.__dict__)  # {'name': '小明', '_Person__age': 23}
print(p1._Person__age)  # 23

四、getter和setter

1.什么時候需要添加對象屬性的getter和setter
如果希望在通過對象.屬性獲取屬性的值之前,再干點兒別的事情,就可以給這個屬性添加getter
如果希望在通過對象.屬性給屬性賦值之前,再干點兒別的事情,就可以給這個屬性添加setter

2.怎么添加setter和getter
getter:
a.在屬性名前加_
b.添加屬性對應的getter

@property
def 屬性名去掉_(self):
    函數體 --> 會對屬性的值進行處理后返回相應的結果(必須要有返回值)

c.使用屬性的值的時候,不通過帶下劃線的屬性名去使用,而是通過沒有下劃線的屬性去使用

注意:對象.不帶下劃線的屬性 --> 調用getter對應的函數
自己備注的:(property是去掉調用函數時的括號,并且將函數返回值作為函數名的值)

setter:
如果要添加setter,必須要先添加getter
a.添加setter

@getter名.setter
def 屬性名去掉_(self,參數):
    做別的事情
    self.屬性名 = 處理后的值
class Number:
    def __init__(self):
        self._value = 0
        # 通過0-6保存星期幾
        self._week = 0
        self.type = int
        self.id = None

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, x):
        if not -100<=x<=100:
            raise ValueError
        self._value = x



    # _week的getter
    @property
    def week(self):
        if self._week == 0:
            return '星期天'
        elif self._week == 1:
            return '星期一'
        elif self._week == 2:
            return '星期二'
        elif self._week == 3:
            return '星期三'
        elif self._week == 4:
            return '星期四'
        elif self._week == 5:
            return '星期五'
        elif self._week == 6:
            return '星期六'


    """
    isinstance(值, 類)  --> 判斷指定的值是否是指定類型(返回值是bool)
    """
    @week.setter
    def week(self, value):
        if not isinstance(value, int):
            raise ValueError
        if not 0<=value<=6:
            raise ValueError

        self._week = value


    @staticmethod
    def max():
        return 100

    @staticmethod
    def min():
        return -100



num = Number()
print(num.week)  # 星期天  # num.week實質是在通過num對象調用getter對應的對象方法week
print(num._week)  # 0
# num.week = '1'  # ValueError
num.week = 1  # num.week = 值 實質是通過num對象去調用setter對應的week方法
# num.week = 10  # ValueError
# num.value = 1000  # ValueError

練習:

class Person:
    def __init__(self):
        self.name
        self.age

賦值時要求age的值只能在0-150之間,超過范圍報錯;獲取age的值的時候,返回年齡值,并且返回這個年齡對應的階段和值

class Person:
    def __init__(self):
        self.name = ''
        self._age = 18

    @property
    def age(self):
        if 0<=self._age<=3:
            return '年齡:' + str(self._age) + ', 階段:嬰兒'
        elif 4<=self._age<=12:
            return '年齡:' + str(self._age) + ', 階段:兒童'
        elif 13<=self._age<=17:
            return '年齡:' + str(self._age) + ', 階段:少年'
        elif 18<=self._age<=29:
            return '年齡:' + str(self._age) + ', 階段:青年'
        elif 30<=self._age<=59:
            return '年齡:' + str(self._age) + ', 階段:中年'
        elif 60<=self._age<=150:
            return '年齡:' + str(self._age) + ', 階段:老年'

    @age.setter
    def age(self, value):
        if not 0<=value<=150:
            raise ValueError
        self._age = value


age1 = random.randint(0,150)
p1 = Person()
p1.age = age1
print(p1.age)
# p2 = Person()
# p2.age = 151  # ValueError
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容