面向对象编程

一个例子:
        """定义一个狗的类"""
        country = "中国"
        class Dog:  # 类具有数据属性和函数属性
            """狗的类"""
            name = "dog"
            country = "China"
            l = [1,2,3]
            def __init__(self,name,sex,age):
                print(country)
                self.name = name
                self.sex = sex
                self.age = age
            def run(self):
                print("%s runing" % self.name)
            def call(self):
                print("%s calling" % self.name)

        dog = Dog("PIZZA","g","5")  # 实例只有数据属性,调用函数属性时现在def __init__(self)中找,没有再去上一层(class Dog)找
        dog.call() #PIZZA calling
        print(dog.__dict__) #{'name': 'PIZZA', 'sex': 'g', 'age': '5'}

        print("="*20)
        # 增加类属性
        print(Dog.name)
        Dog.lan = ""
        print(Dog.lan)
        # 删除类属性
        del Dog.lan
        print(Dog.__dict__)
        # 向类中增加一个方法
        def cry(self):
            print("%s is crying" % self.name)
        Dog.cry = cry
        dog.cry()  # PIZZA is crying
        dog.l.append(4)  # 这里改的是类的属性  dog.l = ["a","b"] ,这样改的是实例的属性,这是为实例新加一个属性
        print(dog.l)
0.  静态属性,静态类,静态方法
    静态属性
    @property:封装逻辑,将一个有返回值的函数属性变成一个数据属性,可以直接调用执行而不用加小括号
        @property
        def cal_v(self):
            print("The %s is %s m" % (self.name,self.length * self.width * self.high))
    使用@property
        我们可以在类中定义一个方法,在实例中将它当成属性来用,用@property实现
        例:
            """
            请利用@property 给一个 Screen 对象加上 width 和 height 属性,以及一个
            只读属性 resolution:
            # -*- coding: utf-8 -*-
            class Screen(object):
            ----
            pass
            ----
            # test:
            s = Screen()
            s.width = 1024
            s.height = 768
            print(s.resolution)
            assert s.resolution == 786432, '1024 * 768 = %d ?' % s.resolution
            """
            #!/urs/bin/env python3
            # -*- coding: utf-8 -*-
            class Screen(object):
                @property    # 把getter定义为属性,获取这个属性
                def width(self):
                    """h获取属性"""
                    return self.__width
                @width.setter # 对这个属性进行设置
                def width(self,val):
                    """设置属性"""
                    if not isinstance(val,int):
                        raise ValueError("it's not a digit")
                    elif 0>val or val>100:
                        raise ValueError("Range Error(0-100)")
                    self.__width = val
                @property
                def height(self):
                    return self.__height
                @height.setter
                def height(self,val):
                    if not isinstance(val,int):
                        raise ValueError("It's not a digit")
                    elif 0>val or val>100:
                        raise ValueError("Range Error(0-100)")
                    self.__height = val
                @property
                def resolution(self):
                    """只读属性,因为可以通过上面两个属性计算得到,不需设置"""
                    return self.__height + self.__width

            screen = Screen()
            screen.width = 89
            screen.height = 100
            print(screen.width,screen.height)
            print(screen.resolution)
            """
            D:\python37\python.exe E:/资源/python/DOME.C/LIAOXUEFENG2/property.py
            89 100
            189
            
            Process finished with exit code 0
            """
        @property可以很大程度的简化代码,像上面的例子如果没使用这个
        那么类中的方法就要写成
        def get_width(self):
            return self.__width
        def set_width(self,val):
            ....ship...
            self.__width = val
        向实例中添加width属性就要这样写:
        screen = Screen()
        screen.set_width(60)
        screen.get_width()
        >>>60
        相比较而言使用@property后的代码,变得更加简洁
            class Lazypro:
                def __init__(self,func):
                    self.func = func                      # func就是are
                def __get__(self, instance, owner):
                    print("触发__get__")
                    if instance == None:
                        return self
                    sel = self.func(instance)
                    setattr(instance,self.func.__name__,sel)
                    return sel
            class Hourse:
                def __init__(self,length,width):
                    self.length = length
                    self.width = width
                # @property                               #are = property(are),使被调用的函数直接被执行而不加小括号
                @Lazypro
                def are(self):
                    return self.length * self.width

            h = Hourse(1,2)
            #用实例调用静态方法
            # print(h.are)
            # 用类也可以调用,但类调用时传入的参数是None
            # print(Hourse.are)  # 报错,因为instance为None

            """
            Traceback (most recent call last):
              File "E:/python/DOME.C/s3_28/利用描述符自定制property.py", line 19, in <module>
                print(Hourse.are)
              File "E:/python/DOME.C/s3_28/利用描述符自定制property.py", line 5, in __get__
                return self.func(instance)
              File "E:/python/DOME.C/s3_28/利用描述符自定制property.py", line 13, in are
                return self.length * self.width
            AttributeError: 'NoneType' object has no attribute 'length'
            """
            #那么系统自带的property是怎么做的呢,它返回一个对象<property object at 0x000001D92BE24D68>
            # print(Hourse.are) # 再使用类调用静态属性就不会报错,而是返回一个对象<__main__.Lazypro object at 0x0000023764BA5080>
            # 但是每次调用都要进行一次计算,如果计算重复且计算量很大,就有必要将第一次的计算结果存起来
            print(h.are)    # 只有这次调用会触发__get__,但要注意优先级
            print(h.are)
            print(h.are)
    property补充:静态属性不能被设置和删除,解决方法如下
                    # 写法一
                    # class Good:
                    #     def __init__(self,name,price,many):
                    #         self.name = name
                    #         self.price = price
                    #         self.many = many
                    #     @property
                    #     def pay_money(self):
                    #         return self.price * self.many
                    #     @pay_money.setter
                    #     def pay_money(self,s):
                    #         print("触发setter",s)
                    #     @pay_money.deleter
                    #     def pay_money(self):
                    #         print("触发delter")
                    #
                    # g = Good("name",10,10)
                    # g.pay_money = 10
                    # del g.pay_money
                    #写法二
                    class Good:
                        def __init__(self,name,price,many):
                            self.name = name
                            self.price = price
                            self.many = many
                        def get_pay_money(self):
                            print("触发get")
                            return self.price * self.many
                        def set_pay_money(self,s):
                            print("触发set",s)    # s = 10
                        def del_pay_money(self):
                            print("触发del")
                        pay_money = property(get_pay_money,set_pay_money,del_pay_money)
                    g = Good("name",10,10)
                    print(g.pay_money)
                    g.pay_money = 10    # 传入参数用'='
                    del g.pay_money

    静态类
    @classmethod:当类调用方法时需要传入一个实例,而这样封装就不需要,因为这是专门为类提供的方法
                    它会自动出传入一个类。
                        @classmethod
                        def house_test(cls):  # cls就是自动传入的类,cls.(类属性)这能这样调用
                            pass    
    静态方法
    @staticmethod:类的工具包,不需要传递类或者实例,也不能调用类和实例的属性。类和实例都能调用
        @staticmethod
        def s_test(x,y):
            print(x,y)
1.面向对象
"""
            面向对象编程——Object Oriented Programming,简称 OOP,是一种程
    序设计思想。 OOP 把对象作为程序的基本单元,一个对象包含了数据和
    操作数据的函数。
        面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数
    的顺序执行。为了简化程序设计,面向过程把函数继续切分为子函数,
    即把大块函数通过切割成小块函数来降低系统的复杂度。
        而面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象
    都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执
    行就是一系列消息在各个对象之间传递。

"""
    举例:
        class Dog:
            def __init__(self,name):
                self.name = name
2.类和实例:
    面向对象的编程中最重要的就是‘类’和‘实例’
    类是一个对象的模板,实例就是根据模板创建出的对象
    下面创建一个学生成绩的类:
    class Student():
        def __init__(self,name,score):
            self.name = name
            self.score = score
        def show_score(self):
            print('%s的成绩是:%s分' % (self.name,self.score))

    st1 = Student('Bob',98)
    st2 = Student('liny',100)
    st1.show_score()
    st2.show_score()
    输出结果是:
    """
    D:\python37\python.exe E:/资源/python/DOME.C/LIAOXUEFENG2/student_lei.py
    Bob的成绩是:98分
    liny的成绩是:100分

    Process finished with exit code 0
    """
3.访问限制
    上面的学生成绩例子中,创建好的实例参数已经传入,但是之后还可以对参数进行任意修改
    如果想让参数变得不可修改,可以在参数前面加上'__'双下划线
    但是解释器只是把它在类外的调用改成了别的名字,并没有真正的限制访问,python没有这种机制
    例:
        >>> class S():
        def __init__(self,name,score):
            self.__name = name
            self.__score = score
        def show_sc(self):
            print("%s,%s" % (self.__name,self.__score))
            
            >>> st1 = S('bob',98)       #创建一个实例
            >>> st1.show_sc()            #使用实例的方法
            bob,98
            >>> st1.__name = 'lis'      #为实例创建一个数据属性
            >>> st1.__name
            'lis'
            >>> st1.show_sc()
            bob,98
            >>> 
4.类的三大:继承、多态和封装
    继承:
        在编写类的时候我们会在第一行这样写:
            class Student(object):
        括号中的object就是Student类继承的类,继承与被继承是子类与父类的关系
        子类拥有父类全部的属性和方法,父类也叫超类,子类要想继承父类的属性,
        需要调用父类的__init__方法
        supper().__init__(name,score)
        多态是子类继承于父类的方法可以在子类中修改,而调用该方法时调用子类中修改后的方法
        下面创建一个学生成绩的类:
        class Student():
            def __init__(self,name,score):
                self.name = name
                self.score = score
            def show(self):
                print("name:%s  score:%s)" % (self.name,self.score))
        我们再创建一个男学生类,继承学生类:
        class Men_st(Student):
            def __init__(self,name,score):
                super().__init__(name,score)
            def men_show(self):
                """输出这个学生的性别"""
                print('%s is a boy' % self.name)
        st1 = Men_st('Bob',29)
        st1.show()
        st1.men_show()
        """
        输出为:
        name:Bob  score:29
        Bob is a boy
        """
        下面我们对学生类中的show()函数在男学生类中做修改:    
        class Men_st(Student):
            def __init__(self, name, score):
                super().__init__(name, score)
            def show(self):
                print("score:%s  name:%s" % (self.score,self.name))
            def men_show(self):
                """输出这个学生的性别"""
                print('%s is a boy' % self.name)
            st1 = Men_st('Bob',29)
            st1.show()
            st1.men_show()
            """
            输出为:
            score:29  name:Bob  
            Bob is a boy
            """        
        当子类和父类中都有同一个方法时,子类中的方法会覆盖父类中的方法
        每次调用该方法时都是调用子类中的
        接口类、抽象类
        接口是一组功能的入口,要调用某一组功能,需要通过接口来进行调用,
        而不需要关注这组功能是如何实现的,要的只是结果。在类里,接口是提取了一群类共同的函数,
        可以把接口当做一个函数的集合。
        抽象类定义的方法,继承它的子类必须全部实现,接口类使用抽象实现归一思想
                import abc
                class Animal(metaclass=abc.ABCMeta):       # 定义基类(抽象类),抽象类不能产生实例
                    @abc.abstractmethod                    # 抽象这个方法
                    def read(self):                        # 定义接口
                        pass
                    @abc.abstractmethod
                    def write(self):                       # 定义接口
                        pass
                class Med(Animal):
                    def read(self):
                        print("Med_read")
                    def write(self):
                        print("Med_write")
                        
                class Disk(Animal):
                    def read(self):
                        print("disk_read")

                med = Med()
                disk = Disk()    # 因为这个类中缺少write方法,所以运行会报错
                报错:
                Traceback (most recent call last):
                  File "E:/python/DOME.C/s3_25/接口继承.py", line 19, in <module>
                    disk = Disk()
                TypeError: Can't instantiate abstract class Disk with abstract methods write
        继承顺序:发生继承是会创建mro列表,里面就保存着继承顺序  f.__mro__
            在新式类(python3都是新式类,继承object,但不必写出来)上采用广度优先,
            在经典类(python2默认经典类,不继承object)上采用深度优先
    多态:
        多态只是继承的一种体现方式,对于源于同一子类的不同实例,要使用该子类父类的相同方法,
        这一动作表现为多态
    封装:            
5.获取对象信息
    想要获取一个对象的类型可以使用type()
    >>> type(int)
    <class 'type'>
    >>> type('1234')
    <class 'str'>
    >>> type(1234)
    <class 'int'>
    >>> type([1,2,3])
    <class 'list'>
    >>> 
    想要判断是否是继承或者包含关系可以使用isinstance()
    TypeError: isinstance() arg 2 must be a type or tuple of types
    某一变量是否属于某一类型
    >>> isinstance(1,int)
    True
    某一实例是否属于某一类(子类/父类)
    print(isinstance(st1,Student))
    结果为:True
    想要知道一个对象的所有属性和方法使用dir()
    >>> dir(abs)
    ['__call__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', 
    '__format__', '__ge__', '__getattribute__', '__gt__', 
    '__hash__', '__init__', '__init_subclass__', '__le__', 
    '__lt__', '__module__', '__name__', '__ne__', '__new__', 
    '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', 
    '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__',
    '__text_signature__']
    想要知道一个属性或者方法是否在对象内使用hasattr()
    >>> class Student():
    def __init__(self,name,score):
        self.name = name
        self.score = score
    def show(self):
        print('%s %s' % (self.name,self.score))

        
    >>> st = Student('Bob',100)
    >>> st.show()
    Bob 100
    >>> st.name
    'Bob'
    >>> st.score
    100
    >>> hasattr(st,'name')
    True
    >>> hasattr(st,show) # 属性和方法都需要加小括号,否则会报错NameError
    Traceback (most recent call last):
      File "<pyshell#13>", line 1, in <module>
        hasattr(st,show)
    NameError: name 'show' is not defined
    >>> hasattr(st,'show')
    True
    如果想获取对象中的变量和方法可以使用getattr()
    >>> st_name = getattr(st,'name')
    >>> st_name
    'Bob'
    >>> st_score = getattr(st,'score')
    >>> st_score
    100
    >>> st_show = getattr(st,'show')
    >>> st_show
    <bound method Student.show of <__main__.Student object at 0x0000014FA19ACFD0>>
    >>> st_show()
    Bob 100
    如果想设置一个属性可以使用estattr()
    >>> setattr(st,'grade',6)
    >>> st.grade  # 添加一个属性
    6
    >>> setattr(st,'score',89)
    >>> st.score   # 对原有属性进行修改
    89
6.类属性和实例属性
    实例属性是通过实例变量或者self变量绑定的属性
    类属性是在定义实例属性之前定义的,并且是公开的,但如果实例属性
    和类属性同名,实例属性会屏蔽掉类属性,比方说我们先定义了一个类属性
    通过实例也可以调用它,但接着我们又定义了一个和它同名的实例属性
    再通过实例调用这个属性就只会调用实例属性,但通过类属性还是可以调用它
    例:
        >>> class Std():
    name = 'shcool'
    def  __init__(self,score):
        self.score = score
        
    >>> st = Std(100)
    >>> st.name
    'shcool'
    >>> setattr(st,'name','Bob')
    >>> st.name
    'Bob'
    >>> del st.name # 删除实例属性
    >>> st.name
    'shcool'  # 删除实例属性后,再次调用name属性,调用的就是类属性
7.组合
    将没有共同点的两个类关联起来
8.反射/自省
    主要指程序可以访问、检测和修改它本身状态或行为的
    一种能力(自省)
    举例:
        class BlackMe:
            def __init__(self,name,addr):
                self.name = name
                self.addr = addr
            def sell_house(self):
                print("%s 正在卖房子" % self.name)

        obj1 = BlackMe("置业",'碧桂园')
        # python提供的四个反射方法

        # 1 hasattr, 检测属性是否存在,返回True/False
        print(hasattr(obj1,"name"))  #True
        print(hasattr(obj1,"save"))  #False

        # 2 getattr, 获取该属性,存在返回属性值,不存在报错,或者指定返回值
        print(getattr(obj1,"name"))  #置业
        # print(getattr(obj1,"save"))  #报错,AttributeError: 'BlackMe' object has no attribute 'save'
        print(getattr(obj1,"save","属性不存在"))  #属性不存在

        # 3 setattr ,为对象添加或者修改一个属性
        # print(obj1.__dict__)         # {'name': '置业', 'addr': '碧桂园'}
        setattr(obj1,"sb","123")
        # print(obj1.__dict__)         # {'name': '置业', 'addr': '碧桂园', 'sb': '123'}

        # 4 delattr
        print(obj1.__dict__)         # {'name': '置业', 'addr': '碧桂园', 'sb': '123'}
        delattr(obj1,"sb")
        print(obj1.__dict__)         # {'name': '置业', 'addr': '碧桂园'} 
9.动态导入模块
        # 动态导入模块,将模块中的函数赋值给一个变量两种方法
        # 1 __import__
        m = __import__("m1.t")
        print(m)   # <module 'm1' (namespace)> 不管调用的是第多少层的模块,返回的总是最顶级模块
        m.t.test1()   # test1
        m.t.test2()   #test2

        # 2 import importlib
        import importlib
        m = importlib.import_module("m1.t") # 返回的就是调用的模块
        print(m)    #<module 'm1.t' from 'E:\\python\\DOME.C\\s3_26\\m1\\t.py'>
        m.test1() #test1
        m.test2() #test2
10.__getattr__   __setattr__  __delattr__ 针对实例的内置方法 使用'.'操作属性时会触发
        同样的还有__getitem__ __setitem__ __delitem__   使用'[]'操作属性时会触发
        举例:
            # class BlackMe:
            #     def __init__(self,name,addr):
            #         self.name = name
            #         self.addr = addr
            #     # def __getattr__(self, item):
            #     #     print("__getattr__正在执行")
            #     def __setattr__(self, key, value):
            #         print("__setattr__正在执行")
            #
            # s = BlackMe("dv","akduvg")
            # #  1 __getattr__
            # # print(s.iwbvi)  # __getattr__正在执行 ,调用不存在的属性时会触发
            # s.save = "sb"
            # print(s.save)   # AttributeError: 'BlackMe' object has no attribute 'save'

            # class BlackMe:
            #     def __init__(self,name,addr):
            #         self.name = name
            #         self.addr = addr
            #     # def __getattr__(self, item):
            #     #     print("__getattr__正在执行")
            #     def __setattr__(self, key, value):
            #         print("__setattr__正在执行")
            #         self.__dict__[key] = value
            #
            # s = BlackMe("dv","akduvg")
            # #  1 __getattr__
            # # print(s.iwbvi)  # __getattr__正在执行 ,调用不存在的属性时会触发
            # s.save = "sb"
            # print(s.save)   # sb

            # class BlackMe:
            #     s = 1
            #     def __init__(self,name,addr):
            #         self.name = name
            #         self.addr = addr
            #     # def __getattr__(self, item):
            #     #     print("__getattr__正在执行")
            #     def __delattr__(self, item):
            #         print("__delattr__正在执行")
            #
            # print(BlackMe.__dict__)
            # del BlackMe.s
            # print(BlackMe.__dict__)

            class BlackMe:
                def __init__(self,name,addr):
                    self.name = name
                    self.addr = addr
                # def __getattr__(self, item):
                #     print("__getattr__正在执行")
                def __getattr__(self, item):
                    print("__getattr__正在执行")

            s = BlackMe("ssfb","veb")
            print(s.name)   #ssfb
            print(s.sssss)   #__getattr__正在执行    属性不存在时才会触发
11.__str__   __repr__:修改实例的返回值

        举例:
            class Foo:
                def __init__(self,name,age):
                    self.name = name
                    self.age = age
                def __str__(self):
                    return "%s 的年龄是 %s" % (self.name,self.age)
            f = Foo("alxe",10)
            print(f)  #alxe 的年龄是 10,__str__可以指定实例的返回

            class Foo:
                def __init__(self,name,age):
                    self.name = name
                    self.age = age
                def __str__(self):
                    return "%s 的年龄是 %s" % (self.name,self.age)
                def __repr__(self):
                    return "%s 的 %s" % (self.name, self.age)
            f = Foo("alxe",10)
            print(f)  #alxe 的年龄是 10,__repr__可以指定实例的返回,会先寻找__str__,没有时会找到__repr__执行
12.__format__
        举例:
            # s = "{0}-{1}-{2}".format("2019","8","6")
            # print(s)   #2019-8-6
            date_dic = {
                "ymd":'{0.year}{0.mon}{0.day}',
                "mdy":'{0.mon}:{0.day}:{0.year}',
                "y-m-d":'{0.year}-{0.mon}-{0.day}'
            }
            class Foo:
                def __init__(self,year,mon,day):
                    self.year = year
                    self.mon = mon
                    self.day = day
                def __format__(self, format_spec):
                    print(format_spec)
                    return date_dic[format_spec].format(self)

            s =Foo(2019,8,6)
            print(format(s,"y-m-d"))

            print('=========','{0.year}{0.mon}{0.day}'.format(s))            
posted @ 2020-06-13 17:45  pywhy  阅读(119)  评论(0编辑  收藏  举报