面向对象

一、概述

1、面向过程编程
    核心是“过程”二字,过程指的是做事的步骤
    基于该思想编写程序就好比在设计一条条的流水线

    优点:复杂的问题流程化、进而简单化
    缺点:扩展性差

2、面向对象编程
    核心是“对象”二字,对象是一个的容器(盛放相关的数据与功能)
    基于该思想编写程序就是造一个个对象/容器

    优点:扩展性强
    缺点:比起面向过程来说,加重了编程的复杂度

大白话:面向对象编程的核心就是造对象/容器盛东西,该容器就是一个内存空间

def choose(self):
    print('<%s:%s:%s>正在选课' %(self["stu1_name"],self["stu1_age"],self["stu1_gender"]))

Student_dic={
"school":"oldboy",
"choose":choose
}

stu1_dic={

    "stu1_name":"egon",
    "stu1_age":18,
    "stu1_gender":"male",

}

stu2_dic={
    "stu1_name":"jack",
    "stu1_age":19,
    "stu1_gender":"female",
}
示例

二、类与对象

# 什么是类?
# 类就是一个容器(一个内存空间),存放的是对象之间相同的数据与功能
# 为何要有类?
# 为了节省内存空间
学生对象1
    数据
        学校="oldboy"
        名字="张三"
        年龄=18
        性别="male"
    功能
        选课功能

学生对象2
    数据
        学校="oldboy"
        名字="李四"
        年龄=19
        性别="female"
    功能
        选课功能

学生对象3
    数据
        学校="oldboy"
        名字="王五"
        年龄=23
        性别="male"
    功能
        选课功能

学生类
    相同数据
        学校="oldboy"
    相同功能
        选课功能
案例
语法规定:先定义类,后调用类产生对象
class Student:
    # 相同数据
    school ="oldboy"

    # 相同功能
    def choose(self):
        print('is choosing course')

    # print("====>")

1.定义类=》把存有所有学生对象相同的数据与功能的内存空间准备好

类体代码会在类定义阶段立即运行,所以会产生一个类的名称空间,将类体代码运行过程中
产生的名字都丢到类的名称空间中,然后类名指向的就是类的名称空间
print(Student.__dict__)
print(Student.school) # Student.__dict__["school"]

2.调用类=》产生对象

# 调用类做的事情
# (1)造一个对象的内存空间,并将给内存空间与类的内存空间绑定
stu_obj1 = Student()
stu_obj2 = Student()
stu_obj3 = Student()

print(stu_obj1)
print(stu_obj2)
print(stu_obj3)

print(stu_obj1.__dict__)
print(stu_obj2.__dict__)
print(stu_obj3.__dict__)
print(stu_obj1.school)

3.为对象初始化自己独有的属性

stu_obj1.name = "张三"  # stu_obj1.__dict__["name"]="张三"
stu_obj1.age = 18  # stu_obj1.__dict__["age"]=18
stu_obj1.gender = "male"  # stu_obj1.__dict__["gender"]="male"
# print(stu_obj1.__dict__)

stu_obj2.name = "李四"
stu_obj2.age = 19
stu_obj2.gender = "female"

stu_obj3.name = "王五"
stu_obj3.age = 23
stu_obj3.gender = "male"

 

三、__int__方法

class Student:
    school ="oldboy"

    def choose(self):
        print('is choosing course')

stu_obj1 = Student()
stu_obj2 = Student()
stu_obj3 = Student()


# 为对象初始化自己独有的属性
stu_obj1.name = "张三"  # stu_obj1.__dict__["name"]="张三"
stu_obj1.age = 18  # stu_obj1.__dict__["age"]=18
stu_obj1.gender = "male"  # stu_obj1.__dict__["gender"]="male"

stu_obj2.name = "李四"
stu_obj2.age = 19
stu_obj2.gender = "female"

stu_obj3.name = "王五"
stu_obj3.age = 23
stu_obj3.gender = "male"

# 优化方案1:
def init(obj,name,age,gender):
    obj.name = name
    obj.age = age
    obj.gender = gender

init(stu_obj1, "张三" ,18,"male")
init(stu_obj2, "李四" ,19,"female")
init(stu_obj3, "王五" ,23,"male")

print(stu_obj1.__dict__)
print(stu_obj2.__dict__)
print(stu_obj3.__dict__)

# 终极解决方案:
class Student:
    school ="oldboy"
    #            空对象,"张三",18,"male"
    def __init__(obj, name, age, gender):
        obj.name = name  # 空对象.name = "张三"
        obj.age = age  # 空对象.age = 18
        obj.gender = gender  # 空对象.gender = "male"
        # return None  # 注意!!!:不能有返回值

    def choose(self):
        print('is choosing course')
范例

1.调用类发生的事情

# 1、先造一个空对象(空对象的本质就是一个与类的内存空间相关联的、对象的内存空间)
# 2、触发类中的__init__函数的运行,会将(空对象"张三" ,18,"male")一起传给__init__函数,完成为对象初始化属性的操作
# 3、将初始化好属性的对象的内存地址赋值给等号左侧的变量名stu_obj1
stu_obj1=Student("张三" ,18,"male")
stu_obj2=Student("李四" ,19,"female")
stu_obj3=Student("王五" ,23,"male")

print(stu_obj1.__dict__)
print(stu_obj2.__dict__)
print(stu_obj3.__dict__)

四、类与对象的属性操作  

class Student:
    school ="oldboy"
    n=0

    def __init__(obj, name, age, gender):
        Student.n+=1
        obj.name = name  # 空对象.name = "张三"
        obj.age = age  # 空对象.age = 18
        obj.gender = gender  # 空对象.gender = "male"

    def choose(self):
        print('is choosing course')


stu_obj1=Student("张三" ,18,"male")
stu_obj2=Student("李四" ,19,"female")
stu_obj3=Student("王五" ,23,"male")

print(Student.n)
print(stu_obj1.n)
print(stu_obj2.n)
print(stu_obj3.n)

 

1.对象属性操作

1.对象的属性操作
(1) 访问
print(stu_obj1.name)
print(stu_obj1.school)

(2) 删除(只能清楚对象自己名称空间内的)
del stu_obj1.name
print(stu_obj1.__dict__)

(3)新增与修改
stu_obj1.x = 111
print(stu_obj1.__dict__)
stu_obj1.x = 222
print(stu_obj1.x)
对象的属性操作

2.类的属性操作

(1) 访问
print(Student.school)
print(Student.choose)
(2) 删除(只能清楚类自己名称空间内的)
del Student.school
print(Student.__dict__)
(3)新增与修改
Student.xxx=111
Student.xxx=222
print(Student.__dict__)
类的属性操作

3.总结

# 1、对象.属性:先从对象自己的内存空间找,没有则去类中查找
# 类.属性:直接去类中查找
stu_obj1.school = "xxx"
print(stu_obj1.school)
print(stu_obj2.school)
print(stu_obj3.school)

# 2、类中定义的属性类可以使用,但其实是为对象准备的
# 类的数据属性是所有对象共享的
print(Student.school,id(Student.school))
Student.school="OLDBOY"
print(stu_obj1.school,id(stu_obj1.school))
print(stu_obj2.school,id(stu_obj2.school))
print(stu_obj3.school,id(stu_obj3.school))

# 类的函数属性
print(Student.choose)
print(stu_obj1.choose)
print(stu_obj2.choose)
print(stu_obj3.choose)
小结

五、绑定方法

class Student:
    school ="oldboy"

    def __init__(self, name, age, gender):
        self.name = name  # 空对象.name = "张三"
        self.age = age  # 空对象.age = 18
        self.gender = gender  # 空对象.gender = "male"

    def choose(self):
        print('%s is choosing course' %self.name)

    def tell_info(self):
        print('<%s:%s:%s>' %(self.name,self.age,self.gender))

stu_obj1=Student("张三" ,18,"male")
stu_obj2=Student("李四" ,19,"female")
stu_obj3=Student("王五" ,23,"male")
stu_obj1.tell_info()
stu_obj2.tell_info()
stu_obj3.tell_info()
# 类中定义的函数类可以访问,但是类来访问的时候就是一个普通函数,必须按照普通函数的玩法来
print(Student.choose)
Student.choose(stu_obj1)

print(stu_obj1.choose)
print(stu_obj2.choose)
print(stu_obj3.choose)

# 类中定义的函数其实是给对象准备的,对象来用,称之为调用绑定方法
# 绑定方法的特殊之处在于自动传参:会将调用者当作第一个参数自动传入
stu_obj1.choose() # choose(stu_obj1)
stu_obj2.choose() # choose(stu_obj2)
stu_obj3.choose() # choose(stu_obj2)



# 在python3里统一了类与类型的概念
l1=[1,2,3]  # l1=list([1,2,3])
print(type(l1))
print(type(stu_obj1))
l2=[11,22]  # l1=list([1,2,3])

l1.append(333)
print(l1)
l2.append(444)
print(l2)

list.append(l1,333)
print(l1)
list.append(l2,444)
print(l2)

 

六、三大特性之封装

1 什么是封装
封装=》整合

2 为何要封装
为了让程序的整合程度更高,进而提升程序的解耦合程度

3 如何封装

3.1 把装到类或对象里的属性藏起来
(1)藏起来就是:把装进去的属性隐藏起来不让类外部访问到
(2)为何要将属性藏起来???
1、把数据属性藏器里的目的是:严格控制类外部使用者对属性的操作
不想让外部直接操作属性,通过开放接口的方式外部间接操作属性,
我们可以在接口之上附加任意控制逻辑,从而严格控制类外部使用者对属性的操作
2、把功能属性藏起来的目的是:为了隔离复杂度

(3)如何藏起来
在属性前加__开头,就会将该属性隐藏起来

注意:
(1) 这种不是真正意义上的隐藏,仅仅只是一种变形操作
(2) 该变形操作只在类定义阶段检查语法的时候变形一次,在此之后,新增的__开头的属性
都不会发生变形
(3) 该变形操作对外不内

4.应用

class People:
    def __init__(self,name,age,gender):
        self.__name=name
        self.age=age
        self.gender=gender

    def get_name(self):
        print("名字:%s" %self.__name)

    def set_name(self,val):
        if type(val) is not str:
            print("名字必须是str类型")
            return
        self.__name = val

    def del_name(self):
        print('不让删除')

p=People('egon',18,'male')
# p.__name=123123123
# print(p.name)

# p.get_name()
# p.set_name("EGON")
p.del_name()
View Code

5.示例

class Foo:
    __x = 111  # _Foo__x = 111

    def __init__(self, m, n):
        self.__m = m  # self._Foo__m = m
        self.__n = n  # self._Foo__n = n

    def __f1(self):  # _Foo__f1
        print('from f1')

    def f2(self):  # self._Foo__m,self._Foo__n,self._Foo__x
        print(self.__m,self.__n,self.__x)

print(Foo.__x)
print(Foo.__f1)
print(Foo.__dict__)
print(Foo._Foo__x)
print(Foo._Foo__f1)

obj1=Foo(666,777)
print(obj1._Foo__x)
print(obj1._Foo__f1)

print(obj1.__dict__)
print(obj1._Foo__m)
print(obj1._Foo__n)

Foo.__zzz=1111
print(Foo.__dict__)
print(Foo.__zzz)

obj1=Foo(666,777)
obj1.__yyy=222
print(obj1.__dict__)

obj1.f2()
示例

七、property装饰器

1.property基本使用

class People:
    def __init__(self, name, height, weight):
        self.name = name
        self.height = height
        self.weight = weight

    @property
    def bmi(self):
        return self.weight / (self.height ** 2)

p = People('egon', 1.8, 70)
# print(p.bmi())
# p.height=1.90
# print(p.bmi)
基本应用

2.升级应用

class People:
    def __init__(self,name):
        self.__name=name

    @property
    def name(self):  # get
        return "名字:%s" %self.__name

    @name.setter
    def name(self,val):  # set
        if type(val) is not str:
            print("名字必须是str类型")
            return
        self.__name = val

    @name.deleter
    def name(self):  # del
        print('不让删除')

p=People('egon')

print(p.name)
p.name=123
del p.name
print(p.name)
升级应用

3.示例

class People:
    def __init__(self,name):
        self.__name=name

    def get_name(self):  # get
        return "名字:%s" %self.__name

    def set_name(self,val):  # set
        if type(val) is not str:
            print("名字必须是str类型")
            return
        self.__name = val

    def del_name(self):  # del
        print('不让删除')

    name = property(get_name,set_name,del_name)

p=People('egon')
示例

八、三大特性之继承

1 什么是继承?
继承是一种新建子类的方式,新建的类称之为子类,被继承的类称之为父类、基类、超类
继承的特点:子类会遗传父类的所有属性

2 为何要继承
类存在的意义是为了解决对象与对象之间的冗余问题
而继承的意义是为了解决类与类之间冗余问题

继承体现的一种耦合思想,于扩展性的增强无益

3 如何继承
语法:python支持单继承与多继承

单继承: 一个子类只能继承一个父类
多继承: 一个子类可以同时继承多个父类

ps:继承表达的是一个is-a的关系
单继承符合is-a的关系,可以让继承结构相对简单一点

而多继承不符合is-a的关系,盲目使用多继承会加大继承结构的复杂度,所以继承的正确打开方式是Mixins机制
class Parent1:
    pass

class Parent2:
    pass

class Sub1(Parent1):
    pass

class Sub2(Parent1,Parent2):
    pass


print(Sub1.__bases__)
print(Sub2.__bases__)
View Code
class Student:
    school = "oldboy"

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

        self.stu_id = stu_id

    def choose(self):
        print('is choosing course')


class Teacher:
    school = "oldboy"

    def __init__(self, name, age, gender,level,salary):
        self.name = name
        self.age = age
        self.gender = gender

        self.level = level
        self.salary = salary

    def set_score(self, stu_obj, num):
        stu_obj.score = num
        print("老师<%s>给学生<%s>打了 %s 分" %(self.name,stu_obj.name,num))

stu_obj1=Student("tom",18,'male',3536)
tea_obj1=Teacher("egon",18,'male',10,3000)

# tea_obj1.set_score(stu_obj1,60)
# print(stu_obj1.score)
案例1
# 如何在子类派生的新方法中重父类的功能
# 方案一:指名道姓地调用某一个类的函数,不依赖于继承
class People:
    school = "oldboy"
    #            空对象,"tom",18,'male'
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender

class Student(People):
    #            空对象,"tom",18,'male',3536
    def __init__(self,name,age,gender,stu_id):
        People.__init__(self,name,age,gender)

        self.stu_id=stu_id

    def choose(self):
        print('is choosing course')

class Teacher(People):
    def __init__(self, name, age, gender,level,salary):
        People.__init__(self,name,age,gender)

        self.level = level
        self.salary = salary

    def set_score(self, stu_obj, num):
        stu_obj.score = num
        print("老师<%s>给学生<%s>打了 %s 分" %(self.name,stu_obj.name,num))

stu_obj1=Student("tom",18,'male',3536)
tea_obj1=Teacher("egon",18,'male',10,3000)

print(stu_obj1.__dict__)
print(tea_obj1.__dict__)
案例2

九、多继承

coding:utf-8
在python中,针对每一个类python解释器都会基于c3算法为其计算出一个MRO列表
ps: 在python中有新式类与经典类之分
新式类:但凡是继承了object类的子类,以及该子类的子子孙孙类都是新式类
经典类:没有继承object类的子类,以及该子类的子子孙孙类都是经典类
注意:在python3中,如果一个子类没有继承任何类,那么python会让其默认继承object类
所以说,只有在python2中才存在经典类

1.由谁引发的属性查找,就参照谁的MRO列表

class E:
    def test(self):
        print('from E')


class F:
    def test(self):
        print('from F')


class B(E):
    def test(self):
        print('from B')


class C(F):
    def test(self):
        print('from C')


class D:
    def test(self):
        print('from D')


class A(B, C, D):
    # def test(self):
    #     print('from A')
    pass


print(A.mro())


'''
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class 'object'>]
'''
View Code

2.菱形继承:一个子类继承的多个父类汇聚到一个非object类

新式类与经典类关于属性的查找不一样
(1)新式类:广度优先
(2)经典类:深度优先
class G: # 在python2中,未继承object的类及其子类,都是经典类
    # def test(self):
    #     print('from G')
    pass

class E(G):
    # def test(self):
    #     print('from E')
    pass

class F(G):
    def test(self):
        print('from F')

class B(E):
    # def test(self):
    #     print('from B')
    pass

class C(F):
    def test(self):
        print('from C')

class D(G):
    def test(self):
        print('from D')

# print(D.mro())
class A(B,C,D):
    # def test(self):
    #     print('from A')
    pass

obj = A()
# print(A.mro())
obj.test()
View Code

十、属性的查找

在单继承背景下的属性查找:
1、obj.x
对象=》对象的类=》父类=》父父类。。。

2、类名.x
当前类=》父类=》父父类。。。
class Foo:
    def f1(self):
        print("Foo.f1")

    def f2(self):
        print('Foo.f2')
        self.f1()  # obj.f1()

class Sub(Foo):
    def f1(self):
        print("Sub.f1")

obj=Sub()
obj.f2()
"""
Foo.f2
Sub.f1
示例1
class Foo:
    def __f1(self):  # _Foo__f1
        print("Foo.f1")

    def f2(self):
        print('Foo.f2')
        self.__f1()  # self._Foo__f1

class Sub(Foo):
    def __f1(self):  # _Sub__f1
        print("Sub.f1")

obj=Sub()
obj.f2()
"""
Foo.f2
Sub.f1
"""
示例2

十一、supper方法

如何在子类派生的新方法中重父类的功能
方案一:指名道姓地调用某一个类的函数,不依赖于继承
方案二:super()会返回一个特殊的对象,super().x该对象会参照当前类的mro列表去父类里找,严格依赖继承
class People:
    school = "oldboy"
    #            空对象,"tom",18,'male'
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender

    def tell_info(self):
        print("名字:%s" %self.name)
        print("年龄:%s" %self.age)
        print("性别:%s" %self.gender)

class Student(People):
    #            空对象,"tom",18,'male',3536
    def __init__(self,name,age,gender,stu_id):
        # People.__init__(self,name,age,gender)
        # super(Student,self).__init__(name,age,gender)  # 在python2中
        super().__init__(name,age,gender)  # 在python2中

        self.stu_id=stu_id

    def choose(self):
        print('is choosing course')

    def tell_info(self):
        print("学号:%s" %self.stu_id)
        super().tell_info()

class Teacher(People):
    def __init__(self, name, age, gender,level,salary):
        # People.__init__(self,name,age,gender)
        super().__init__(name,age,gender)  # 在python2中

        self.level = level
        self.salary = salary

    def set_score(self, stu_obj, num):
        stu_obj.score = num
        print("老师<%s>给学生<%s>打了 %s 分" %(self.name,stu_obj.name,num))

stu_obj1=Student("tom",18,'male',3536)
tea_obj1=Teacher("egon",18,'male',10,3000)

# print(stu_obj1.__dict__)
# print(tea_obj1.__dict__)

# stu_obj1.tell_info()
# tea_obj1.tell_info()


class A:
    def test(self):
        super().test() # 参照属性发起者的mro,去父类里找属性

class B:
    def test(self):
        print('from B')

class C(A,B):
    pass

# obj=C()
# obj.test()
# print(C.mro())

obj=A()
print(A.mro())
obj.test()
View Code

 

 

 
posted @ 2020-08-31 21:39  sean_wang  阅读(169)  评论(0编辑  收藏  举报