day15-面向对象

一、内置类函数

声明类的时候系统会自动添加的属性(可能会是字段也可能是对象自己)
__name__、__slots__、__class__、__dot__、__dict__、__module__

定制当前对象的打印

class Person:
    """
    说明文档:人类
    num - 人类的数量
    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))

    # 定制当前对象的打印
    # 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 - 人类的数量
    name -人的名字
    

    说明文档:人类
    num - 人类的数量
    name -人的名字
"""
3.__class__

__class__指的是对象属性;
对象.__class__ —— 获取对象对应的类(和type(对象)功能一样)

print(p1.__class__)
print(type(p1))
type1 = p1.__class__  # type1可以当做Person来用
print(type1.__name__)
p2 = type1('小花', '女', 17)
print(p2.name, p2.gender, p2.age)

"""
<class '__main__.Person'>
<class '__main__.Person'>
Person
小花 女 17
"""
4.__dict__(将对象转换成字典)

对象属性;对象.__dict__ —— 将字典中所有的属性以属性和对应的值转换成一个字典中的键值对(一个对象一个字典)
类的字段;类.__dict__ —— 将类转换成一个字典,字典中的元素是类中所有的字段对应的值

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

persons = [p1, p2]  # 因为__repr__的方法
print(persons)

"""
{'name': '小明', 'gender': '男', 'age': 18}
{'__module__': '__main__', '__doc__': '\n    说明文档:人类\n    num - 人类的数量\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__ —— 获取当前类是在那个模块中声明的返回的是模块的名字

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

"""
__main__
builtins
__main__
"""

6.__bases__

__bases__类的字段;类.__bases__ —— 获取当前类的父亲(返回的是一个元组)

print(Person.__bases__)

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

练习将数据转换成对象

import json

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


class Data:
    # 注意:如果设置了__slots__的值,那么当前类的对象就不能使用__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.访问权限:公开、保护、私有

```python
公开 - 公开的属性和方法在类的内部、外部能够使用,也能继承
保护 - 保护的属性和方法在类的内部能够使用,外部不能使用,可以被继承
私有 - 私有的属性和方法只能在类的内部使用,外部不能使用,也不能被继承
2.python中属性和方法的访问权限
python类中所有的属性和方法本质都是公开的;私有化是假的私有化,只是提示程序员这个属性和方法在外部不能使用,也不能被继承

在需要私有化的属性名或者方法名前加'__'(不能以'__'结尾)
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('内部num', self.__num)
        self.func1()

    def func1(self):
        print('函数')
        print('内部age:', self.__age)

    def __func2(self):
        print('私有函数')

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)  # 不建议使用

"""
函数
内部age: 20
小明吃米饭
内部num 61
函数
内部age: 20
函数
内部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

当我们需要在获取属性值之前做点别的事情就需要给这个属性添加getter
当我们需要给属性值赋值之前做点别的事情,就需要给这个属性添加setter

2.给属性添加getter

1)属性命名的时候在前面加一个下划线_
2)在@property装饰器的后面声明一个对象方法
a. 将属性去掉下划线作为方法名
b.方法除了self外不需要其他参数
c.函数的返回值就是获取这个属性的时候得到的值
3)在外部使用属性的时候,通过对象.不带下划线的属性去使用

注意:获取属性值的时候,就会自动调用getter对应的函数

3.给属性添加setter

属性添加setter之前必须先添加getter
1)保证属性名前有一个_
2)在@getter名.setter后面声明函数
a.将属性去掉下划线作为方法名
b.需要一个self以外的参数
c.不需要返回值
3)在外部使用属性的时候,通过'对象.不带下划线的属性'去使用

注意:当给属性赋值的时候,实质是调用setter对应的方法

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)  # 这儿实质就是在调用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
年龄值被修改!!!
"""

练习:写一个矩形类
有属性:长、宽、面积和周长
要求从生活的角度看这个矩形


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
"""

####四、类方法和静态方法

######1.类中的函数
类中的方法分为:对象方法、类方法、静态法

1)对象方法
a.怎么声明:直接声明
b.怎么调用:用对象来调用
c.特点:有指向当前对象的`self`
d.什么时候用:如果实现函数的功能需要用到对象属性,就是引用对象方法

2)类方法
a.怎么声明:声明在@classmethod后面
b.怎么调用:用类来调用,`类.类方法()`
c.特点:有自带的参数`cls`,表示当前类;这个参数在调用的时候不用传参,系统会自动将当前类传给它;
`cls`:谁调用就指向谁(如果是对象指向的是对象对应的类)
d.什么时候用:如果实现函数的功能不需要属性对象属性,但需要类的字段,就使用类方法

3)静态方法
a.怎么声明:声明在@staticmethod的后面
b,怎么调用:通过类来调用,`类.静态方法()`
c.特点:没有默认参数
d.什么时候用:实现函数的功能既不需要类又不需要对象额,就是用静态方法

```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):
        # 对象能做的事情,self都能做
        print(self.name + '在吃' + food)

    @classmethod
    def func1(cls):
        # 类能做的事情,cls都能做
        print(cls)
        t = cls('a', 10, '男')
        print('t:', t)
        print(cls.num)
        print('这是一个类方法!')

    @staticmethod
    def func2():
        print('这是一个静态方法!')

    def func3(self):
        print('这是一个函数!', 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
这是一个类方法!
<class '__main__.Person'>
t: <__main__.Person object at 0x00000000027FD408>
61
这是一个类方法!
这是一个静态方法!
这是一个函数! 西西里
90 61
============================================================
====================1============================
<class '__main__.Student'>
t: <__main__.Student object at 0x00000000027FD408>
10
这是一个类方法!
<class '__main__.Person'>
t: <__main__.Person object at 0x00000000027FD448>
61
这是一个类方法!
====================2============================
这是一个静态方法!
这是一个静态方法!
"""

五、继承

1.什么是继承

继承就是让子类直接拥有父类的属性和方法
子类 —— 继承者
父类 / 超类 —— 被继承着

2.怎么继承

1)语法

class 类名(父类1, 父类2, ...):
    说明文档
    类的类容

2)说明

() —— 固定写法,如果省略相当于(object)
声明类的时候如果没有写父类,默认继承object(object又叫基类)
父类 —— 一个类的分类可以有多个,一般情况下只有一个(支持多继承)

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('人类的数量:%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'
        # 在子类中添加对象属性,需要先通过super去调用父类的__init__来继承父类的对象属性
        super().__init__()

    @staticmethod
    def func1():
        print('学生')

    def func2(self):
        print('我是学生')
        # 在子类中可以通过super方法可以去调用父类的方法
        # 注意:super()只能在对象方法和类方法中使用,静态方法用不了
        super(Student, self).func2()

    # 添加功能
    def study(self):
        print(self.name + '在好好学习!')


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 男
小明在吃米饭
人类的数量:10
{'study_id': '001', 'classes': 'py', 'name': '小明', 'age': 18, 'gender': '男', '_Person__a': 12}
学生
我是学生
我是小明
"""
``

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 1.内置类属性 内置类属性就是魔法属性魔法属性:属性名的前后都有两个下划线魔法方法:方法的前后都有两个下划线类的属...
    oxd001阅读 1,427评论 0 1
  • 一.内置类对象 1.什么是内置类属性 定制当前类的对象的打印 1) 重新str方法, 这个方法的返回值就是对应的打...
    风月辞寒阅读 1,742评论 0 0
  • 内置类属性 1.什么是内置类属性 声明类的时候系统自动添加的属性(可能是字段也可能是对象属性) 私有化 1.访问权...
    Ed97001阅读 1,288评论 0 0
  • 1 数据的访问 1.1 访问和使用权限的分类 在很多的高级面向对象语言中,会将属性和方法分为以下三种公开的 - 在...
    咔佈阅读 1,877评论 0 0
  • 回顾 1.静态方法和类方法、对象方法 对象方法: a.直接声明在类中 b.自带的self参数c.对象来调用d.实现...
    龙神海王阅读 2,555评论 0 0

友情链接更多精彩内容