面向对象编程 09

01面向对象编程介绍

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

# print(stu1_dic)
# stu1_dic["choose"](stu1_dic)
# print(stu1_dic["stu1_name"])
面向对象编程介绍

02类与对象

# 什么是类?
#   类就是一个容器(一个内存空间),存放的是对象之间相同的数据与功能
# 为何要有类?
#   为了节省内存空间

"""
学生对象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"


















# print(stu_obj1.name)
# print(stu_obj1.age)
# print(stu_obj1.gender)
#
# print(stu_obj1.school)
# print(stu_obj1.choose)

# stu_obj2
# stu_obj3
类与对象

03__init__方法

# 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、先造一个空对象(空对象的本质就是一个与类的内存空间相关联的、对象的内存空间)
# 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__)
__init__

04类与对象的属性操作

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) 访问
# 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__)

# !!!总结
# 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)
类与对象属性操作

05绑定方法

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)
绑定方法

06三大特性之封装

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

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

3 如何封装

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

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

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

"""
# 应用
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()



# 示例

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()
三大特性之封装

07property装饰器

#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')
property装饰器

08三大特性之继承

"""
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__)
#
#

# 案例1
# 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)

# 如何在子类派生的新方法中重父类的功能
# 方案一:指名道姓地调用某一个类的函数,不依赖于继承
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__)
三大特性之继承

09属性的查找

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

# 2、类名.x
# 当前类=》父类=》父父类。。。

# 示例1:
# 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
# """

# 示例2
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
"""
属性的查找

10多继承

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

# !!! 重要结论:由谁引发的属性查找,就参照谁的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'>]
'''

# obj = A()
# obj.test()

# 菱形继承:一个子类继承的多个父类汇聚到一个非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()
多继承

11supper方法

# 如何在子类派生的新方法中重父类的功能
# 方案一:指名道姓地调用某一个类的函数,不依赖于继承
# 方案二: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()
supper方法
原文地址:https://www.cnblogs.com/2722127842qq-123/p/13586597.html