day16、类和对象的应用 2019-01-14

一、复习

1.类的声明

class 类名:
类的雷类容

2.类的属性

属性就是声明在类中的变量

a.对象属性:值会因为对象的不同而不同
    声明在 init 方法中,
    self.属性 = 值
    对象.属性
b.类的字段:值不会因为对象的不同而不同
    直接声明在类中
    变量名 = 值
    对象.属性

3.方法

a.对象方法:直接声明在类中,自带 self 参数,调用的时候不用传参,谁调用就指向谁
    对象.方法()
    实现函数的功能需要对象属性时
    (1) init 方法:系统创建对象的时候,系统会自动调用, 需要通过构造方法来给
b.类方法:声明前加 @classmethod,自带 cls 参数,调用的时候,不用传参,谁调用就指向谁
    类.方法()
    实现函数的功能需要类的字段时
c.静态方法:声明前加 @stadicmethod 没有自带参数
    类.方法()
    实现函数的功能既不需要需要对象属性,也不需要类的字段时

二、私有化:

1.属性和方法

保护的:在外部不可以使用,可以继承
公开的:在外部可以使用,可以继承

2.python 的的私有化

在 python 中,属性或者方法名前加 (--),就可以加将属性或者方法变成私有的(注意)
私有的属性和方法只能在类的内部使用,不能在类的外面使用。

3.python 私有化的原理

在名字前是 __ 的属性和方法前再加 '_类名' 去保存属性和方法

class Person:
    num = 61
    __num2 = 62

    def __init__(self, name='张三', age=0):
        self.name = name
        self.age = age
        self.__sex = '男'

    def eat(self, food):
        print(self.__sex)
        print(self.name, food)
        self.__run()

    def __run(self):
        print('%s在跑步' % self.name)

    @classmethod
    def show_num(cls):
        print('人类的数量:%d, %d' % (cls.num, cls.__num2))

    @staticmethod
    def func1():
        print('人类要保护大自然!')


def main():
    p1 = Person()

    print(Person.num)
    # print(Person.__num2)

    print(p1.name)
    # print(p1.__sex)
    print(p1._Person__sex)

    p1.eat('面条')
    # p1.run()

    Person.show_num()
    Person.func1()

    print(p1.__dict__)


if __name__ == '__main__':
    main()

三、getter & setter

1.应用 getter 的场景:

getter : 获取属性的值之前想要做一些别的事情,就给这个属性添加 getter
setter : 给对象属性赋值之前想要做一些别的事情,就给这个属性添加 setter

2.getter :

第一步:申明属性时,在属性前加 ''
第二步:声明函数 @property (函数没有除了 self 以外的参数,但是要有返回值.返回值就是获取)
def 去掉 '
' 的属性名(self):
做点别的事情
返回属性的值
第三步:
在类的外部,通过对象.去掉_的属性去获取相关

3.setter :

想要添加 setter 必须要先添加 getter
第一步: 声明属性的时候在属性名前面加 _
第二步:声明函数(函数除了 self 以外还需要一个参数,没有返回值.之类的参数代表给属性赋的值)
@属性名去掉.setter
def 去掉
的属性名(self, 参数):
做点别的事情
给属性赋值
第三步:在类的外部通过 对象.去掉_ 的属性去给相关属性赋值
例如:

class Person:
    def __init__(self, name=''):
        self.name = name
        self._age = 0
        self._week = 1          # 属性名前面有 _ ,使用属性的时候不要直接使用

    # 添加 setter
    @property
    def age(self):
        return self._age

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

    # 给 week 添加 getter
    @property
    def week(self):
        print('---------------------------------')
        if self._week < 7:
            return '星期 %d ' % self._week
        else:
            print('星期天')

    @week.setter
    def week(self, value):
        self._week = value


def main():
    p1 = Person('阿黄')
    p1.age = 23
    p1.age = 2
    print(p1.week)
    p1.week = 5


if __name__ == '__main__':
    main()

运行效果:

---------------------------------
星期 1 

四 、继承

1.什么是继承

一个类继承一个类,其中会产生继承者和被继承者,这里的继承者加子类,被继承者叫父类/超类;
继承就是让子类直接拥有父类的方法和属性;

2.怎么继承

class 类名(父类列表)
类的内容
说明:

a.python 中所有的类都是直接或间接继承自基类 object
    class 类名 -->  class类名(object)
b.python 中的继承支持多继承,父类列表中可以拥有多个类,多各类之间用逗号隔开

3.继承能继承那些东西

所有的属性和方法都能继承,私有的属性都可以继承
注意:slots的值不会被继承,如果在类中给 slots 赋值后,当前类的对象不能使用 dict;但是这个类的子类对象可以使用__dict
只是 dict 中没有从父类继承下来的属性
如果父类没有给slots赋值,直接给子类的slots,会无效
例如:

class Person(object):
    num1 = 123

    def __init__(self, name='', age=0, sex='男'):
        self.name = name
        self.age = age
        self.sex = sex

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

    @classmethod
    def show_num(cls):
        print('人类的数量为 : %s' % cls.num1)


class Student(Person):
    pass


def main():
    Student.num1 = 5000000
    print(Student.num1)

    stu = Student('阿黄')

    stu.eat('火锅')

    Student.show_num()


if __name__ == '__main__':
    main()

运行效果:

5000000
 阿黄 在吃 火锅
人类的数量为 : 5000000

五、添加属性和方法

1.添加方法

直接在子类中声明新的方法
子类可以使用父类的属性和方法,但是父类不能使用子类添加的属性和方法

2.方法的重写

在子类中重新实现父类已经拥有的方法 -----完全重写
在重写这个函数时,需要保留父类的功能在子类中添加新的功能
-----部分重写(在子类中通过'super().'的方式调用父类方法后添加新的代码)

3.类中函数的调用过程

a.

回到函数声明的位置,先看当前类中是否有方法,如果有就直接调用当前类中的方法;,没有就去看父类中有没有这个方法,
如果父类中也没有,就看父类的父类,以此类推,,,直到找到 object 类,如果 object 类里面也是没有,程序就报错

b.添加类的字段
c.添加对象属性

对象属性其实是由 init 方法继承下来的
例如:

class Person(object):
    num1 = 123

    def __init__(self, name, sex='男'):
        self.name = name
        self.age = 3
        self.sex = sex

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

    @classmethod
    def show_num(cls):
        print('人类的数量为 : %s' % cls.num1)


class StudentPlus(Person):
    def __init__(self, sno, name=None):
        self.name = name
        self.sno = sno
        self.sex = '男'
        self.age = 3
        self.score = 90


class Student(Person):
    def student(self):
        print('%s 在睡觉' % self.name)

    @classmethod
    def show_num(cls):
        print('学生的数量为: %d ' % cls.num1)


def main():
    p1 = Person('阿黄')
    stu1 = Student('大白')
    stu1.student()
    Person.show_num()
    Student.show_num()


if __name__ == '__main__':
    main()

运行效果:

大白 在睡觉
人类的数量为 : 123
学生的数量为: 123 

六、多继承

一个类同时继承多个类
多继承:
class 类名(父类1, 父类2, 父类3......)
类的内容
多个父类中的所有方法和字段都可以继承,只是对象属性只能继承第一个父类的
例如:

class Animal:
    def __init__(self, name, age=0, color='黑色'):
        self.name = name
        self.age = age
        self.color = color

    def func1(self):
        print('对象 方法')


class Fly:
    def __init__(self):
        self.height = 100000


class Bride(Animal, Fly):
    pass


def main():
    p1 = Bride('阿黄')
    print(p1.__dict__)
    # print(p1.height)                # 报错。   AttributeError: 'Bride' object has no attribute 'height'


if __name__ == '__main__':
    main()

运行效果:

{'name': '阿黄', 'age': 0, 'color': '黑色'}

七、运算符的重载

1.什么是运算符重载

通过实现类中相应的魔法方法,来让自己的对象支持相应的运算符
注意:python 中所有的数据类型都是类,所有的数据都是对象
例如:

class Student:
    def __init__(self, name='', age=0, score=0):
        self.name = name
        self.age = age
        self.score = score

    # 返回值就是运算结果
    def __add__(self, other):
        # 支持学生加学生
        return self.age + other.age

    # 大于和小于符号只需要重载一个后可以了
    def __gt__(self, other):
        return self.score > other.score


def main():
    stu1 = Student('阿黄', 3, 50)
    stu2 = Student('阿黄', 5, 50)
    print(stu1 + stu2)              # 相当于: print(stu1.__add__(stu2))


if __name__ == '__main__':
    main()

运行效果:

8

八、内存管理机制

1.数据的存储(分为栈区间和堆区间)

栈区间:从底层来看,系统自动开辟、,释放的;一般存变量,函数的调用过程是在栈区间。
堆区间:从底层来看,由程序员自己开辟的空间;一般存数据(python 中所有的数据都是对象)。
从 python 的角度来看,程序员已经不需要写代码来开辟空间和释放空间了。
变量赋值过程:现在堆区间开辟空间把数据存起来,然后将数据对应的地址存到栈区间的变量中。
注意:数字、字符串在赋值的时候,不会直接开辟空间,会先检测之前有没有存储过这个数据,
如果有就用之前的数据地址。

2.内存释放(垃圾回收机制)原理:

python 中的每一个对象在创建的时候,都有一个属性,叫'引用计数',表示当前对象的应用个数。
判断一个对象是否销毁,就看'引用计数'是否为 0 ,为 0 就销毁,否则不销毁。

from sys import getrefcount (获取对象的引用计数)
例如:

from sys import getrefcount


def main():
    list1 = [1, 2]
    print(getrefcount(list1))  # 2

    # 使用不同的变量存对象地址会增加引用计数
    list2 = list1
    print(getrefcount(list1))  # 3

    [1, list1]
    print(getrefcount(list1))  # 3

    # def func1(obj):
    #     print(getrefcount(list1))
    #
    # func1(list1)

    print(getrefcount(list1))

    list1 = []
    print(getrefcount(list2))  # 2

    del list2
    # print(getrefcount(list2))   # UnboundLocalError

    # def getrefcount(obj):
    #     obj = list1
    #     获取obj的引用计数

    bullets = [{'x': 10, 'y': 20}, {'x': 30, 'y': 10}, {'x': 100, 'y': 200}]
    del bullets[2]

    bullets.pop(0)


if __name__ == '__main__':
    main()

运行效果:

2
3
3
3
2

你可能感兴趣的:(day16、类和对象的应用 2019-01-14)