從入門到入獄------物件導向(二)

2020-10-25 12:00:45

class Student:
    def __init__(self, name, tel, study_id='001', score=0):
        self.name = name
        self.tel = tel
        self.study_id = study_id
        self.score = score

    # 在列印一個物件的時候,系統會自動用這個物件去呼叫__repr__方法,並且獲取這個方法的返回值
    # 返回值是什麼就列印什麼(返回值必須是字串)
    def __repr__(self):
        return f'<{str(self.__dict__)[1:-1]}>'


#   __dict__將物件轉換成字典
stu1 = Student('小王', 123456, '0001', 1)
stu2 = Student('小林', 22222, '0002', 12)
print(stu1)  # <'name': '小王', 'tel': 123456, 'study_id': '0001', 'score': 1>

# 物件屬性的增刪改查
# 查---獲取物件的屬性值
'''
物件.屬性
getattr(物件,屬性名) 可以做到動態獲取屬性值
'''
print(stu1.name)  # 小王

# value=input('請輸入要獲取的屬性名:')
# print(getattr(stu2,value)) # value="name"  小林  value="tel" 22222
print(getattr(stu2, 'height', 180))  # 180 獲取不存在的屬性如果不給預設值會報錯,

# 增/改
'''
物件.屬性=值  屬性存在的時候就是修改,屬性不存在的時候就是增加
setattr(物件,屬性名,值) 可以做到動態增加/修改屬性值
'''
stu1.name = '我不是小王'
stu1.height = '新新增的屬性:身高170'
print(stu1)  # <'name': '我不是小王', 'tel': 123456, 'study_id': '0001', 'score': 1, 'height': '新新增的屬性:身高170'>
setattr(stu1, 'name', '我還是小王')
print(stu1)  # <'name': '我還是小王', 'tel': 123456, 'study_id': '0001', 'score': 1, 'height': '新新增的屬性:身高170'>

# 刪
'''
del 物件.屬性   刪除屬性
del 物件       刪除物件

delattr(物件,屬性名)
'''
del stu1.height
print(stu1)  # <'name': '我還是小王', 'tel': 123456, 'study_id': '0001', 'score': 1>
delattr(stu1, 'study_id')
print(stu1)  # <'name': '我還是小王', 'tel': 123456, 'score': 1>

物件方法:

定義:直接定義
呼叫:物件.方法名()
特點:有個預設引數self,這個引數在呼叫的時候不用傳參,系統會自動將當前物件傳給self
使用:如果實現函數的功能需要用到物件,那麼這個函數就定義成物件方法

類方法:

定義:在定義函數前加@classmethod
呼叫:類.方法名()
特點:有個預設引數cls,這個引數在呼叫的時候不用傳參,系統會自動將當前類傳給cls
使用:如果實現函數的功能不需要物件需要用到類,那麼這個函數就定義成類方法

靜態方法

定義:在定義函數前加@staticmethod
呼叫:類.方法名()
特點:沒有預設引數
使用:實現函數功能不需要物件也不需要類的前提下就定義靜態方法

class Student:
    # func1是物件方法
    def func1(self):
        print('物件方法')

    # func2是類方法
    @classmethod
    def func2(cls):
        print('cls:', cls)  # cls:<class '__main__.Student'>

    # 當前類能做的,cls都可以做

    # func3是靜態方法
    @staticmethod
    def func3():
        print('靜態方法')


print('Student:', Student)  # Student: <class '__main__.Student'>
class Person:
    """
    人類
    """
    num = 61

    def __init__(self, name='張三', age=18, gender='男'):
        self.name = name
        self.age = age
        self.gender = gender

    def eat(self, food='麵條'):
        print(f'{self.name}在吃{food}')

    @classmethod
    def message(cls):
        print(f'人類目前的數量是:{cls.num}')

    @staticmethod
    def destroy():
        print('人類破壞環境')


p1 = Person()
# 類屬性
'''
類名.__doc__    獲取類的說明檔案
print(Person.__doc__)    # 人類

類名.__module__  獲取指定類所在的模組 如果結果是__main__  說明是當前模組
print(Person.__module__)  # __main__
print(list.__module__)  # builtins

物件.__class__   獲取指定物件對應的型別,和type(物件)功能一樣
print(p1.__class__)  # <class '__main__.Person'>
print(type(p1))  # <class '__main__.Person'>

類名.__name__    獲取類名型別為str
print(Person.__name__) # 'Person'
print(int.__name__) # 'int'

類名.__dict__   獲取類所有的欄位和欄位值,轉化為字典,key是欄位名,value是欄位的值
print(Person.__dict__)
物件.__dict__   獲取物件所有的屬性和屬性值,轉化為字典,key是屬性名,value是屬性的值
print(p1.__dict__)  # {'name': '張三', 'age': 18, 'gender': '男'}

類名.__base__  獲取指定類的父類別
類名.__bases__ 獲取類所有的父類別
object是python中所有類的基礎類別
print(Person.__base__)   # <class 'object'>
print(Person.__bases__)  # (<class 'object'>,)


'''

# 根據資料不同的型別建立以該型別名命名的檔案
datas = ['abc', -0.1234, '你好', 564]
for data in datas:
    with open(rf'files\{data.__class__.__name__}.txt', 'a', encoding='utf-8') as f:
        f.write(str(data) + '\n')

getter

使用:在獲取物件屬性前,如果要做別的什麼事就可以給這個屬性新增getter
用法:
在需要新增getter的屬性名前加_
在裝飾器@property後面定義一個函數,函數名就是屬性名去掉_
函數沒有引數,但是需要一個返回值,返回值就是獲取屬性值得到的結果
通過物件獲取屬性的時候,屬性不需要帶_

class Circle:
    pi = 3.14

    def __init__(self, r=10):
        self.r = r

    @property
    def area(self):
        return Circle.pi * self.r ** 2


c1 = Circle(100)
print(c1.area)

練習,給Person新增屬性,要求:age中儲存年齡值,但是獲取age屬性的時候
得到的是:兒童(0-4),少年(5-12),青年(13-28),壯年(29-40)中年(41-55),老年(55以上)

class Person:
    def __init__(self, age=0, name='張三', gender='男'):
        self.name = name
        self._age = age
        self.gender = gender

    @property
    def age(self):
        if 0 <= self._age <= 4:
            return '兒童'
        elif 5 <= self._age <= 12:
            return '少年'
        elif 13 <= self._age <= 28:
            return '青年'
        elif 29 <= self._age <= 40:
            return '中年'
        else:
            return '老年'

setter —新增之前必須新增getter

給物件屬性賦值的之前做別的事情,就給這個屬性新增setter
用法
在裝飾器 @函數名.setter 後面定義一個函數,函數名就是屬性名去掉_
函數有且只有一個引數(這個引數指向的是賦值的時候賦的值)

 @age.setter
 def age(self, value):
     print(value)
     if type(value) != int:
         raise ValueError
     if value < 0 or value > 150:
         raise ValueError


p1 = Person()

# p1.age='dwa'  ValueError
# p1.age=151    ValueError

存取許可權

公開的:公開的屬性和方法在類的內部外部都能用,並且可以被繼承
保護的:保護的屬性和方法在類的內部可以使用,外部不能用,但是可以繼承
私有的:私有的屬性和方法在類的內部可以使用,外部不能用,不能被繼承

python中的屬性和方法只有存取許可權:公開的
python 所謂的私有化只是一種說明提示

私有化的方法:
在屬性名和方法名前加__(只能是兩個__開頭,不能再__結尾)

class Person:
    num = 100
    __info = '動物'

    def __init__(self, name='張三', age=18, gender='男'):
        self.name = name
        self.age = age
        self.gender = gender

    def func1(self):
        return Person.__info

    def __func2(self):
        return Person.num


p1 = Person()
print(p1.func1())  # 動物
print(Person.num)  # 100
# print(Person.__info) # AttributeError: type object 'Person' has no attribute '__info'
# print(p1.func2()) # AttributeError: 'Person' object has no attribute 'func2'
# print(Person._Person__info) # 動物 強行檢視

運運算元

python在使用運運算元的時候,本質是在呼叫運運算元對應的方法
每個運運算元對應的方法的方法名是固定的,不同型別的資料在參與相同運算的時候
會呼叫不同類中對應方法

某個型別的資料是否支援某種運算,就看這個資料對應的型別中有沒有實現這個運運算元對應的方法

# __add__
class Person:
    def __init__(self, age=0, name='?', gender='男'):
        self.name = name
        self._age = age
        self.gender = gender
    #self指向+前面的資料,other指向+後面的資料
    def __add__(self, other):
        return self.name + other.name

    def __mul__(self, other):
        return [self.name for _ in range(len(other.name))]

    def __repr__(self):
        return f'<{str(self.__dict__)[1:-1]}>'

    def __gt__(self, other1):
        return self._age>other1._age

p1 = Person(56,'王五','男')
p2 = Person(1, "小花",'女')
print(p1 + p2)  # 張三李四 本質是:pi.__add__(p2)
print(p1 * p2)  # ['張三', '張三'] 本質是:pi.__mul__(p2)

# 練習 根據年齡排序
p3=Person(20,'張三','男')
p4=Person(25,'老王','男')
# 方法一 過載 > 運運算元
ps=[p1,p2,p3,p4]
print(sorted(ps))

# 方法二 實參高階函數
ps.sort(key=lambda item :item._age)
print(ps)