python,day5,面向对象

python,day5,面向对象,第1张

python,day5,面向对象

目录
    • 面向对象介绍
    • 封装
    • 继承
    • 多态
    • 反射
    • 内置方法
    • 元类

面向对象介绍
'''
面向过程:
    核心是"过程"二字
    过程的核心思想是将程序流程化
    过程是”流水线“,用来分步骤解决问题
面向对象:
    1、核心是”对象“二字
    2、对象的终极奥义就是将程序”整合“
    3、对象就是”容器“,用来盛放数据与功能
        优点:
            1、提升程序的解耦合程度,进而增强程序的可扩展性
        缺点:
            2、可扩展性差

    4、python这门语言到底提供了什么语法来允许我们将数据与功能整合在一起?

    5、类:
        类是对象相似数据与功能的集合体
        所以类体中常见的是变量与函数定义,但是类体其实是可以包含任意其他代码的
        强调!!:类体代码是再类定义阶段就会立即执行,会产生类的名称空间
    6、使用顺序
        # 一、先定义类
                class Student:
                        stu_school = 'oldboy'
                        def __init__(obj, x):   #对象下面的属性
                            obj.stu_name = x

                        def tell_stu_info(stu_obj):
                            print('学生信息:名字:%s,年龄:%s 性别:%s'%(stu_obj['stu_name'],
                            stu_obj['stu_age'],
                            stu_obj['stu_gender']))

                        def set_info(stu_obj,x,y,z):
                            stu_obj['stu_name'] = x
                            stu_obj['stu_age'] = y
                            stu_obj['stu_gender'] = z
                # 功能的定义
                pass
                # 属性访问的语法:
                    # 访问数据属性    print(Student.set_school)
                    # 访问函数属性    print(Student.set_info)


        # 二、再调用类产生对象
                    stu1_obj = Student('hongwei')
                    print(stu1_obj.set_info)
                    print(stu1_obj.__dict__)
                #调用类的过程由称之为实例化,发生了三件事
                    # 1、先产生一个空对象
                    # 2、python会调用类中的__init__方法,然后将空对象已经调用类括号内传入的参数一同传给init
                    # 3、返回初始完的对象

                #总结__init__方法
                        # 1、会在调用类时自动触发执行,用来为对象初始化自己独有的数据
                        # 2、__init__内因该存放是为对象初始化属性的功能,但是是可以存放任意其他代码,想要在
                        # 类调用时就立刻执行的代码都可以放到该方法内
                        # 3、__init__方法必须返回Now

        # 三、绑定方法:
                #谁来调用绑定方法就会将谁当做第一个参数自动传入
                    stu1_obj.tell_stu_info()
'''


案例
#学校信息
class School:
    school_name='ke'
    def __init__(self,nickname,addr):
        self.addr = addr
        self.nickname = nickname
        self.classes = []
    def related_class(self,class_obj):
        self.classes.append(class_obj)
    def tell_class(self):
        print(self.nickname)
        for class_obj in self.classes:
            class_obj.tell_course()

#班级信息
class Class:
    def __init__(self,name):
        self.name=name  #班级名字
        self.coures = None
    def related_course(self,course_obj): #班级课程
        self.coures = course_obj
    def tell_course(self):
        print('班级名:%s '%(self.name))
        # print('课程信息:%s'%(self.coures))
        self.coures.tell_info()

#课程信息
class Course:
    def __init__(self,name,period,price):
        self.name = name
        self.period = period
        self.price = price
    def tell_info(self):
        print('<课程名:%s 周期:%s 价钱:%s >'%(self.name,self.period,self.price))

class Student:
    pass
# 一、班级 *** 作
        # 创建班级
        class_obj1 = Class('脱产14期')
        class_obj2 = Class('脱产15期')
        #创建课程
        class_obj1.related_course('python全栈开发')
        class_obj2.related_course('HCIE云计算')



# 二、校区 *** 作
        # 创建校区
        school_obj1 = School('宏伟魔都校区','瑞昌')
        school_obj2 = School('宏伟帝都校区','北京')
        # 为学校开设班级
        school_obj1.related_class(class_obj1)
        school_obj2.related_class(class_obj2)
        # 查看每个校区开设的班级
        # school_obj2.tell_class()
        # print(school_obj1.nickname)



#三、课程
        #1、创建课程
        course_obj1 = Course('python全栈开发','6mons',2000)
        course_obj2 = Course('HCIE云计算','6mons',2000)
        #2、查看课程的详细信息
        # course_obj1.tell_info()
        # course_obj2.tell_info()
        #3、为班级关联课程对象
        class_obj1.related_course(course_obj1)
        class_obj2.related_course(course_obj2)


#四、验证
        # school_obj2.tell_class()

封装
# 一、封装介绍
     #封装是面向对象三大特性最核心的一个特性
     #封装 = 整合


#二、将封装的属性进行隐藏 *** 作
        #如何隐藏:在属性名前加__前缀,就会实现一个对外隐藏属性效果
            #需要注意的问题:
            #1、在类外部无法直接访问双下划线开头的属性,但知道了类名和属性名就可以拼出属性
            #所以说这种 *** 作并没有严格意义上的限制外部访问,仅仅只是一种语法意义
            #2、这种隐藏对外不对内,应为__开头的属性会在检查类体代码语法时同意变形
            #3、这种变形 *** 作旨在检查类语法的时候发生一次,之后定义的__开头的都不会变形

        #为什么要隐藏?
            #隔离复杂度

class Foo:
    __x=111 #_Foo__x
    def __init__(self,y):
        self.__y = y

# 三、property(类的装饰器)
        # 案例一、
                class People:
                    def __init__(self,name,weight,height):
                        self.name = name
                        self.weight = weight
                        self.height = height
                    #定义函数的原因:
                    # 1、从bmi的公式上看,bmi是应该出发功能计算得到的
                    # 2、bmi是随着身高、体重的变化而动态变化的,不是一个固定的值
                    # 3、
                    @property
                    def bmi(self):
                        return self.weight / (self.height **2 )
        
                obj = People('hw',85,1.86)
                print(obj.bmi)


        # 案例二
            class People:
                def __init__(self,name):
                    self.__name = name
            
                def get_name(self):
                    return self.__name
                def set_name(self,val):
                    if type(val) is not str:
                        print('必须传入str类型')
                        return
                    self.__name = val
                def del_name(self):
                    print('不让删除')
                name = property(get_name,set_name,del_name)
            
            obj = People('kehongwei')
            obj.name = 18
            del obj.name
            print(obj.name)


继承
'''
1、什么是继承
继承是一个类继承另一个类
    python支持多继承
        在python中,新建的类可以继承一个或多个父类
            class a:
                pass
            class b:
                pass
            class c(a): #单继承
                pass
            class d(a,b):  #多继承
                pass

2、为何要用继承?:用来解决类与类之间代码冗余问题

3、多继承?
    优点:子类可以同时遗传多个父类属性
    缺点:
        1、违背人的思维习惯
        2、代码可读性变差
        3、不建议使用多继承,扩展性变差
        如果不可避免的用到多继承,应该使用mixins

4、如何实现继承(怎么使用)
    # 基于继承解决类与类之间的冗余问题(在此基础上加上学生学号)
        class Func:
            school = '宏伟'
            def __init__(self,name,age,sex):
                self.name = name
                self.age = age
                self.sex = sex

        class Student(Func):
            # school='宏伟'
            # def __init__(self,name,age):
            #     self.name = name
            #     self.age = age
            def choose_course(self):
                print('%s 正向选课'%self.name)

        # obj = Student('HW',18,'female')
        # print(obj.__dict__)
        # print(obj.school)
        # obj.choose_course()

        class Teacher(Func):
            school = '宏伟'
            def __init__(self,name,age,sex,salary):
                Func.__init__(self,name,age,sex)
                self.name = name
                self.age = age
                self.sex = sex
                self.salary = salary
            def choose_course(self):
                print('%s 正向选课'%self.name)

        obj2=Teacher('hh',9,'male',4000)
        print(obj2.__dict__)

5、单继承背景下的属性查找
    # 示例1
        class Foo:
            def f1(self):
                print('FOO.F1')
            def f2(self):
                print('FOO.F2')
                self.f1()   #obj.f1()
                Foo.f1(self) #想调用当前类的f1

        class Bar(Foo):
            def f1(self):
                print('Bar.f1')

        obj = Bar()
        obj.f2()


    # 示例2
        class Foo:
            def __f1(self):
                print('FOO.F1')
            def f2(self):
                print('FOO.F2')
                self.__f1()

        class Bar(Foo):
            def f1(self):
                print('Bar.f1')

        obj = Bar()
        obj.f2()

6、多继承背景下的属性查找
    1、先查找父类,父类没有就找父类的父类,总之就是先把父类这个分支找完
    2、通过mro表来查找

7、如果多继承是菱形继承,经典类与新式类的属性查找顺序不一样
    1、新式类与经典类
        父类或者以上由boject就是新式类,否则就是经典类
    2、深度优先与广度优先
        1、经典类:深度优先。会在检索第一条分支的时候直接一条道走到黑
        2、新式类:广度优先,会在检索最后一条分支的时候检索object

8、多继承
    多继承要不要用?
    要用,但是需规避几点问题
    1、继承结构经历不要过于复杂
    2、需要使用mixinx:要在多继承的背景下满足继承什么是什么的关系(单继承)=》mixinx

9、 mixins机制核心:
    # mixins提升多继承的可读性
    #满足人的思维,什么是什么

10、子类中重用父类属性有两种方式:
    #方式一:指名道姓的调用
    #方式二:super()调用父类提供给自己的方法 =》严格以来继承关系
          #调用super()会得到一个特殊对象,该对象会参照发起属性查找的那个类的mro取重用父类属性
'''
多态
1、多态:指的是一类事务有多种形态
    动物的多种形态:牛,马
    文件的多种形态:文本文件,可执行文件

2、多态性:指在不考虑实例类型的情况下使用实例
    举个栗子:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班 *** 作,学生执行的是放学 *** 作,虽然二者消息一样,但是执行的效果不同

3、为什么要用多态性(多态性的好处)
	1.增加了程序的灵活性
		以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
	2.增加了程序额可扩展性
		 通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用  
		 
		 
class Cat(Animal): #属于动物的另外一种形态:猫
...     def talk(self):
...         print('say miao')
... 
def func(animal): #对于使用者来说,自己的代码根本无需改动
...     animal.talk()
... 
cat1=Cat() #实例出一只猫
func(cat1) #甚至连调用方式也无需改变,就能调用猫的talk功能
say miao

'''
这样我们新增了一个形态Cat,由Cat类产生的实例cat1,使用者可以在完全不需要修改自己代码的情况下。使用和人、狗、猪一样的方式调用cat1的talk方法,即func(cat1)
'''


4、鸭子类型
	如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子,程序也是如此
	
#二者都像鸭子,二者看起来都像文件,因而就可以当文件一样去用
class TxtFile:
    def read(self):
        pass

    def write(self):
        pass

class DiskFile:
    def read(self):
        pass
    def write(self):
        pass
反射
# 反射
        #1、什么是反射
            #指的是程序在运行过程中可以动态获取对象的信息
        #2、为什么要用反射?

        #3、实现反射机制的步骤
            #1、通过dir:查看对象可以.出那些属性来
                print(dir(obj))
            #2、通过字符串反射到真正的属性上,得到属性值
                print(obj.__dict__[dir(obj)[-2]])

        #4、四个内置函数的使用:通过字符串来 *** 作属性值
            #1、hasattr()  查看对象下有没有name属性
                print(hasattr(obj,'name'))
            #2、setattr()  给属性赋值 *** 作, obj.name = 'asd'
                print(setattr(obj,'bool','asd'))
            #3、getattr()  获取对象的属性值
                print(getattr(obj,'name'))
            #4、delattr()  删除对象属性
                delattr(obj,'name')
内置方法
#内置方法
        #1、什么是内置方法?
            #定义在类内部,__开头并以__结尾的方法
            #特点:会在某种情况自动触发执行
        #2、为什么需要用内置方法
            #为了定制我们的类和对象
        #3、如何使用内置方法?
            #__str__:在打印对象时会自动触发,然后将返回值(必须是字符串类型)当作本次结果
            #__del__:在清理对象时出发,会先执行该方法
            #__new__:在执行类的时候会第一个执行该方法
            #__call__:将对象做成一个可以加括号调用的对象,加括号时会调用call这个方法,然后将该方法得到的值返回
元类
# 元类
        #1、什么是元类?
            #就是用来实例化产生类的类
            #关系:元类---实例化---》类---实例化---》对象

        #2、查看内置元类:
            #1、type是内置的元类
            #2、class关键字定义的所有类都是由元类type实例化产生的
            print(type()) #查看内置的元类

        #3、class关键字创造类的步骤
            #1、引入类的三个特征 类名,类的基类,执行类体代码拿到类的命名空间

            #2、执行步骤
                #1、拿到类名: class_name = 'obj'
                #2、拿到类的基类: class_bases=(object,)
                #3、拿到执行类体代码拿到类的命名空间 class_dic = {}
                #4、调用元类 a = type(class_name,class_bases,class_dic)

        #4、如何自定义元类来控制类的产生
            #第四步:调用Mymeta发生三件事,调用Mymeta就是type.__call__(该方法也会做以下三个步骤)
                #1、先造一个空对象People,调用类内的__new__方法
                #2、调用mymeta这个类内的__init__方法,完成初始化对象的 *** 作
                #3、返回初始化好的对象
            #强调:只要是调用类,会依次调用类内的 __new__ ,__init__
                class Mymeta(type):
                    # 会将空对象,class_name,class_bases,class_dic这四个参数传入
                    def __init__(self, x, y, z):
                        if not x.capitalize():
                            raise NameError('类名的首字母必须大写!')
                        # print('run')
                        # print(self)
                        # print(x)
                        # print(y)
                        # print(z)
                    def __new__(cls, *args, **kwargs):
                        # 造Mymeta的对象
                        print(cls, args, kwargs)
                        # return super().__new__(cls, *args, **kwargs)
                        return type.__new__(cls, *args, **kwargs)
                class People(metaclass=Mymeta):
                    def __init__(self, name, age):
                        self.name = name
                        self.age = age

        #5、__call__:将对象做成一个可以加括号调用的对象,加括号时会调用call这个方法,然后将该方法得到的值返回
                # type.__call__函数干的三件事
                    #1、先造一个空对象People,调用类内的__new__方法
                    #2、调用mymeta这个类内的__init__方法,完成初始化对象的 *** 作
                    #3、返回初始化好的对象
                #总结
                    #对象()-》类内的__call__
                    #类()-》自定义元类内的__call__
                    #自定义元类() -》内置元类内的__call__
                class Foo:
                    def __init__(self,x,y):
                        self.x = x
                        self.y = y
                    def __call__(self, *args, **kwargs):
                        return 123
                obj = Foo(123123, 123123)
                a = obj()
                print(a)

        #6、自定义元类控制类的调用
                #people = Mymeta() => type.__call__ => 干了三件事
                #1、type.__call__函数内会调用Mymeta内的__new__
                #2、type.__call__函数内会调用Mymeta内的__init__
                #3、type.__call__函数内会返回一个初始化好的对象

                #obj = People('asd',18) ->Mymeta.__call__->干了三件事
                # 1、Mymeta.__call__函数内会调用People内的__new__
                # 2、Mymeta.__call__函数内会调用People内的__init__
                # 3、Mymeta.__call__函数内会返回一个初始化好的对象
                class Mymeta(type):
                    def __call__(self, *args, **kwargs):
                        # 1、type.__call__函数内会调用Mymeta内的__new__
                        people_obj = self.__new__(self)
                        # 2、type.__call__函数内会调用Mymeta内的__init__
                        self.__init__(people_obj,*args, **kwargs)
                        people_obj.__dict__['xxx']=111
                        # 3、type.__call__函数内会返回一个初始化好的对象
                        return people_obj
                class People(metaclass=Mymeta):
                    def __init__(self, name, age):
                        self.name = name
                        self.age = age
                    def __new__(cls, *args, **kwargs):
                        #产生真正的对象
                        return  object.__new__(cls)
                #小试牛刀:
                    # 将People添加个属性,xxx=111
                    obj = People('hw', 18)
                    abc = People('hw', 19)
                    print(obj.__dict__)
                    print(abc.__dict__)


        #7、属性查找
                #正常的属性查找规则:对象 》 类 》 父类
                    #强调:该属性查找不会衍生到元类
                #调类时的属性查找:类》父类》元类

        #8、作业
                #1、在元类中控制把自定义类的数据属性都变成大写
                #2、在元类中控制自定义的类无需__init__方法
                #3、在元类中控制自定义的类产生的对象相关的属性全部为隐藏属性
                #4、基于元类实现单例模式

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/4677687.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-06
下一篇 2022-11-06

发表评论

登录后才能评论

评论列表(0条)

保存