day15-面向?qū)ο?/h2>

一、內(nèi)置類函數(shù)

聲明類的時(shí)候系統(tǒng)會(huì)自動(dòng)添加的屬性(可能會(huì)是字段也可能是對(duì)象自己)
__name__、__slots__、__class__、__dot__、__dict__、__module__

定制當(dāng)前對(duì)象的打印

class Person:
    """
    說明文檔:人類
    num - 人類的數(shù)量
    name - 人的名字
    """"
    num = 61
    
    def __init__(self, name, gender, age):
        self.name = name
        self.gender = gender
        self.age = age

    def eat(self, food):
        print('%s在吃%s' % (self.name, food))

    # 定制當(dāng)前對(duì)象的打印
    # 1)重寫__str__方法
    def __str__(self):
        # return '姓名:{},年齡:{},性別:{}'.format(self.name, self.age, self.gender)
        return '<' + str(self.__dict__)[1:-1] + '>'

    # 2)重寫__reper__方法
    # def __repr__(self)
    def __repr__(self):
        return '<' + str(self.__dict__)[1:-1] + 'id: ' + hex(id(self)) + '>'

p1 = Person('小明', '男', 18)
print(p1)
# <'name': '小明', 'gender': '男', 'age': 18>
1. __name__

__name__指的是類的字段

print(type(Person), person)
print(int)
print(Person.__name__)  # 沒有p1.__name__
print(type(Person.__name__))

"""
<class 'type'> <class '__main__.Person'>
<class 'type'>
Person
<class 'str'>
"""
2.__dot__

'doc'指的是說明文檔

print(Person.__doc__)
# print(int.__doc__)
print(p1.__doc__)

"""
    說明文檔:人類
    num - 人類的數(shù)量
    name -人的名字
    

    說明文檔:人類
    num - 人類的數(shù)量
    name -人的名字
"""
3.__class__

__class__指的是對(duì)象屬性;
對(duì)象.__class__ —— 獲取對(duì)象對(duì)應(yīng)的類(和type(對(duì)象)功能一樣)

print(p1.__class__)
print(type(p1))
type1 = p1.__class__  # type1可以當(dāng)做Person來用
print(type1.__name__)
p2 = type1('小花', '女', 17)
print(p2.name, p2.gender, p2.age)

"""
<class '__main__.Person'>
<class '__main__.Person'>
Person
小花 女 17
"""
4.__dict__(將對(duì)象轉(zhuǎn)換成字典)

對(duì)象屬性;對(duì)象.__dict__ —— 將字典中所有的屬性以屬性和對(duì)應(yīng)的值轉(zhuǎn)換成一個(gè)字典中的鍵值對(duì)(一個(gè)對(duì)象一個(gè)字典)
類的字段;類.__dict__ —— 將類轉(zhuǎn)換成一個(gè)字典,字典中的元素是類中所有的字段對(duì)應(yīng)的值

print(p1.__dict__)
print(Person.__dict__)
print(p1)

persons = [p1, p2]  # 因?yàn)開_repr__的方法
print(persons)

"""
{'name': '小明', 'gender': '男', 'age': 18}
{'__module__': '__main__', '__doc__': '\n    說明文檔:人類\n    num - 人類的數(shù)量\n    name -人的名字\n    ', 'num': 61, '__init__': <function Person.__init__ at 0x000000000279F0D8>, 'eat': <function Person.eat at 0x000000000279F168>, '__str__': <function Person.__str__ at 0x000000000279F1F8>, '__repr__': <function Person.__repr__ at 0x000000000279F288>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>}
<'name': '小明', 'gender': '男', 'age': 18>
[<'name': '小明', 'gender': '男', 'age': 18,id:0x279e848>, <'name': '小花', 'gender': '女', 'age': 17,id:0x279e948>]

"""
5.__module__

__module__是類的字段;類.__module__ —— 獲取當(dāng)前類是在那個(gè)模塊中聲明的返回的是模塊的名字

print(Person.__module__)
print(bool.__module__)
print(p1.__module__)

"""
__main__
builtins
__main__
"""

6.__bases__

__bases__類的字段;類.__bases__ —— 獲取當(dāng)前類的父親(返回的是一個(gè)元組)

print(Person.__bases__)

"""
(<class 'object'>,)
"""

練習(xí)將數(shù)據(jù)轉(zhuǎn)換成對(duì)象

import json

with open('data.json', 'r', encoding='utf-8') as f:
    content = json.loads(f.read())
    datas = content


class Data:
    # 注意:如果設(shè)置了__slots__的值,那么當(dāng)前類的對(duì)象就不能使用__dict__屬性
    # __slots__ = ('name', 'age', 'dict1')

    def __init__(self, dict1: dict):
        for key in dict1:
            steattr(self, key, dict1[key])

    def __repr__(self):
        return '<' + str(self, __dict__)[1:-1] + '>'

for item in datas:
    data = Data(item)
    print(data.name, '\n', data)

"""
a0 
 <'name': 'a0', 'pwd': '12345', 'add': [], 'alter': [], 'del': [{'name': 'stu0', 'age': 10, 'phone': '12345678901', 'time': 1565170335.1302288}]>
b 
 <'name': 'b', 'pwd': '45678'>
"""

####二、私有化

######1.訪問權(quán)限:公開、保護(hù)、私有

```python
公開 - 公開的屬性和方法在類的內(nèi)部、外部能夠使用,也能繼承
保護(hù) - 保護(hù)的屬性和方法在類的內(nèi)部能夠使用,外部不能使用,可以被繼承
私有 - 私有的屬性和方法只能在類的內(nèi)部使用,外部不能使用,也不能被繼承
2.python中屬性和方法的訪問權(quán)限
python類中所有的屬性和方法本質(zhì)都是公開的;私有化是假的私有化,只是提示程序員這個(gè)屬性和方法在外部不能使用,也不能被繼承

在需要私有化的屬性名或者方法名前加'__'(不能以'__'結(jié)尾)
python私有化的原理:在私有的屬性和方法前加了'_類名'
class Person:
    __num = 61

    def __init__(self, name, age):
        self.name = name
        self.__age = age
        self.func1()

    def eat(self, food='米飯'):
        print('%s吃%s' % (self.name, food))
        print('內(nèi)部num', self.__num)
        self.func1()

    def func1(self):
        print('函數(shù)')
        print('內(nèi)部age:', self.__age)

    def __func2(self):
        print('私有函數(shù)')

p1 = Person('小明', 20)
# print(Person.num, p1.name, p1.age)
# p1.eat()
# print(p1.__num)  # AttributeError: type object 'Person' has no attribute 'num'

# p1.eat('西瓜')

# p1.func2()  # AttributeError: 'Person' object has no attribute 'func2'

p1.eat()
p1.func1()
print(Person.__dict__)
print(p1.__dict__)
# print(p1._Person__age)  # 不建議使用

"""
函數(shù)
內(nèi)部age: 20
小明吃米飯
內(nèi)部num 61
函數(shù)
內(nèi)部age: 20
函數(shù)
內(nèi)部age: 20
{'__module__': '__main__', '_Person__num': 61, '__init__': <function Person.__init__ at 0x0000000002784EE8>, 'eat': <function Person.eat at 0x0000000002784F78>, 'func1': <function Person.func1 at 0x000000000278E048>, '_Person__func2': <function Person.__func2 at 0x000000000278E0D8>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
{'name': '小明', '_Person__age': 20}
"""

三、屬性的getter和setter

1.什么是getter和setter

當(dāng)我們需要在獲取屬性值之前做點(diǎn)別的事情就需要給這個(gè)屬性添加getter
當(dāng)我們需要給屬性值賦值之前做點(diǎn)別的事情,就需要給這個(gè)屬性添加setter

2.給屬性添加getter

1)屬性命名的時(shí)候在前面加一個(gè)下劃線_
2)在@property裝飾器的后面聲明一個(gè)對(duì)象方法
a. 將屬性去掉下劃線作為方法名
b.方法除了self外不需要其他參數(shù)
c.函數(shù)的返回值就是獲取這個(gè)屬性的時(shí)候得到的值
3)在外部使用屬性的時(shí)候,通過對(duì)象.不帶下劃線的屬性去使用

注意:獲取屬性值的時(shí)候,就會(huì)自動(dòng)調(diào)用getter對(duì)應(yīng)的函數(shù)

3.給屬性添加setter

屬性添加setter之前必須先添加getter
1)保證屬性名前有一個(gè)_
2)在@getter名.setter后面聲明函數(shù)
a.將屬性去掉下劃線作為方法名
b.需要一個(gè)self以外的參數(shù)
c.不需要返回值
3)在外部使用屬性的時(shí)候,通過'對(duì)象.不帶下劃線的屬性'去使用

注意:當(dāng)給屬性賦值的時(shí)候,實(shí)質(zhì)是調(diào)用setter對(duì)應(yīng)的方法

class Person:
    count = 0

    def __init__(self, name, age, gender):
        self.name = name
        self._age = age
        self._gender = gender
        self._week = 0

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

    @property
    def age(self):
        Person.count += 1
        print('年齡值被訪問!', Person.count)
        return self._age

    @age.setter
    def age(self, value):
        print('年齡值被修改?。。?)
        if not isinstance(value, int):
            raise ValueError
        if not 0 <= value <= 200:
            raise ValueError
        # print('~~~~~~~')
        # print('value: ', value)
        self._age = value

    @property
    def gender(self):
        # return self._gender
        if self._gender == 1:
            return '女'
        if self._gender == 0:
            return '男'

    @gender.setter
    def gender(self):
        return ValueError


p1 = Person('小米糕', 18, '女')
# p1.age = 1908
# p1.age = 'abc'
# print(p1.name, p1.age, p1.gender, p1.week)
print(p1.week)  # 這兒實(shí)質(zhì)就是在調(diào)用week方法獲取返回值

p2 = Person('小花', 20, '男')
print(p1.age)  # p1.age()
age1 = p1.age
print(p2.age)  # p2.age()

p1.age = 200  # p1.age(200)

"""
星期天
年齡值被訪問! 1
18
年齡值被訪問! 2
年齡值被訪問! 3
20
年齡值被修改?。?!
"""

練習(xí):寫一個(gè)矩形類
有屬性:長、寬、面積和周長
要求從生活的角度看這個(gè)矩形


class WriteError(Exception):
    def __str__(self):
        return '修改只讀屬性'


class Rect:
    def __init__(self, width, length):
        self._width = width
        self._length = length
        self._area = 0
        self._perimeter = 0

    @property
    def length(self):
        return self._length

    @length.setter
    def length(self, value):
        if not isinstance(value, int) and not isinstance(value, float):
            raise ValueError
        if value < 0:
            raise ValueError
        self._length = value

    @property
    def width(self):
        return self._width

    @width.setter
    def width(self, value):
        if not isinstance(value, int) and not isinstance(value, float):
            raise ValueError
        if value < 0:
            raise ValueError
        self._width = value

    @property
    def area(self):
        self._area = self._length * self._width
        return self._area

    @area.setter
    def area(self, value):
        raise WriteError

    @property
    def perimeter(self):
        self._perimeter = 2 * (self._length + self._width)
        return self._perimeter

    @perimeter.setter
    def perimeter(self, value):
        raise WriteError


rect1 = Rect(1, 2)
print(rect1.area)
print(rect1.perimeter)

rect1.length = 3
print(rect1.area)
print(rect1.perimeter)

# rect1.area = 22
# print(rect1.area)

"""
2
6
3
8
"""

####四、類方法和靜態(tài)方法

######1.類中的函數(shù)
類中的方法分為:對(duì)象方法、類方法、靜態(tài)法

1)對(duì)象方法
a.怎么聲明:直接聲明
b.怎么調(diào)用:用對(duì)象來調(diào)用
c.特點(diǎn):有指向當(dāng)前對(duì)象的`self`
d.什么時(shí)候用:如果實(shí)現(xiàn)函數(shù)的功能需要用到對(duì)象屬性,就是引用對(duì)象方法

2)類方法
a.怎么聲明:聲明在@classmethod后面
b.怎么調(diào)用:用類來調(diào)用,`類.類方法()`
c.特點(diǎn):有自帶的參數(shù)`cls`,表示當(dāng)前類;這個(gè)參數(shù)在調(diào)用的時(shí)候不用傳參,系統(tǒng)會(huì)自動(dòng)將當(dāng)前類傳給它;
`cls`:誰調(diào)用就指向誰(如果是對(duì)象指向的是對(duì)象對(duì)應(yīng)的類)
d.什么時(shí)候用:如果實(shí)現(xiàn)函數(shù)的功能不需要屬性對(duì)象屬性,但需要類的字段,就使用類方法

3)靜態(tài)方法
a.怎么聲明:聲明在@staticmethod的后面
b,怎么調(diào)用:通過類來調(diào)用,`類.靜態(tài)方法()`
c.特點(diǎn):沒有默認(rèn)參數(shù)
d.什么時(shí)候用:實(shí)現(xiàn)函數(shù)的功能既不需要類又不需要對(duì)象額,就是用靜態(tài)方法

```python

class Person:
    num = 61

    def __init__(self, name: str, age: int, gender: str):
        self.name = name
        self.age = age
        self.gender = gender

    def eat(self, food: str):
        # 對(duì)象能做的事情,self都能做
        print(self.name + '在吃' + food)

    @classmethod
    def func1(cls):
        # 類能做的事情,cls都能做
        print(cls)
        t = cls('a', 10, '男')
        print('t:', t)
        print(cls.num)
        print('這是一個(gè)類方法!')

    @staticmethod
    def func2():
        print('這是一個(gè)靜態(tài)方法!')

    def func3(self):
        print('這是一個(gè)函數(shù)!', self.name)

    def func4(self):
        print(self.age, Person.num)


print(Person)
Person.func1()
p1 = Person('西西里', 90, '女')
p1.func1()
Person.func2()
p1.func3()
p1.func4()


print('=' * 60)


class Student(Person):
    num = 10


print('====================1============================')
Student.func1()
Person.func1()
print('====================2============================')
Student.func2()
Person.func2()

"""

<class '__main__.Person'>
<class '__main__.Person'>
t: <__main__.Person object at 0x00000000027FD388>
61
這是一個(gè)類方法!
<class '__main__.Person'>
t: <__main__.Person object at 0x00000000027FD408>
61
這是一個(gè)類方法!
這是一個(gè)靜態(tài)方法!
這是一個(gè)函數(shù)! 西西里
90 61
============================================================
====================1============================
<class '__main__.Student'>
t: <__main__.Student object at 0x00000000027FD408>
10
這是一個(gè)類方法!
<class '__main__.Person'>
t: <__main__.Person object at 0x00000000027FD448>
61
這是一個(gè)類方法!
====================2============================
這是一個(gè)靜態(tài)方法!
這是一個(gè)靜態(tài)方法!
"""

五、繼承

1.什么是繼承

繼承就是讓子類直接擁有父類的屬性和方法
子類 —— 繼承者
父類 / 超類 —— 被繼承著

2.怎么繼承

1)語法

class 類名(父類1, 父類2, ...):
    說明文檔
    類的類容

2)說明

() —— 固定寫法,如果省略相當(dāng)于(object)
聲明類的時(shí)候如果沒有寫父類,默認(rèn)繼承object(object又叫基類)
父類 —— 一個(gè)類的分類可以有多個(gè),一般情況下只有一個(gè)(支持多繼承)

class Person:
    num = 61

    def __init__(self):
        print('Person中的init')
        self.name = '小明'
        self.age = 18
        self.gender = '男'
        self.__a = 12

    def eat(self, food='米飯'):
        print('{}在吃{}'.format(self.name, food))

    @classmethod
    def show(cls):
        print('人類的數(shù)量:%d' % cls.num)

    @staticmethod
    def func1():
        print('人類')

    def func2(self):
        print('我是' + self.name)


class Student(Person):
    num = 10  # 重寫

    def __init__(self):
        print('Student中的init')
        self.study_id = '001'
        self.classes = 'py'
        # 在子類中添加對(duì)象屬性,需要先通過super去調(diào)用父類的__init__來繼承父類的對(duì)象屬性
        super().__init__()

    @staticmethod
    def func1():
        print('學(xué)生')

    def func2(self):
        print('我是學(xué)生')
        # 在子類中可以通過super方法可以去調(diào)用父類的方法
        # 注意:super()只能在對(duì)象方法和類方法中使用,靜態(tài)方法用不了
        super(Student, self).func2()

    # 添加功能
    def study(self):
        print(self.name + '在好好學(xué)習(xí)!')


stu1 = Student()
print(stu1.num)
print(stu1.name, stu1.age, stu1.gender)
stu1.eat()
Student.show()

print(stu1.__dict__)
stu1.func1()
stu1.func2()

# import sys
# print(sys.stdout.flush())

"""
Student中的init
Person中的init
10
小明 18 男
小明在吃米飯
人類的數(shù)量:10
{'study_id': '001', 'classes': 'py', 'name': '小明', 'age': 18, 'gender': '男', '_Person__a': 12}
學(xué)生
我是學(xué)生
我是小明
"""
``

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容