zoukankan      html  css  js  c++  java
  • PYTHON_DAY_07

    目录

    一. 类与对象

    二. 继承

    三. 多态与多态性

    四. 封装

    五. 绑定方法与非绑定方法

    六. staticmethod 与 classmethod 的区别

    七. 内置方法

    八. 反射


    一. 类与对象

     类(Class)定义了一件事物的抽象特点。通常来说,类定义了事物的属性和它可以做到的(它的行为)。举例来说,“狗”这个类会包含狗的一切基础特征,即所有“狗”都共有的特征或行为,例如它的孕育、毛皮颜色和吠叫的能力。类可以为程序提供模版和结构。一个类的方法和属性被称为“成员”。 在代码中,我们声明了一个类,这个类具有一些狗的基本特征。

      

    类 狗
    开始
    公有成员:
        吠叫():
    私有成员:
        毛皮颜色:
        孕育:结束
    

      

    对象

      对象(Object)是类的实例。例如,“狗”这个类列举狗的特点,从而使这个类定义了世界上所有的狗。而莱丝这个对象则是一条具体的狗,它的属性也是具体的。狗有皮毛颜色,而莱丝的皮毛颜色是棕白色的。因此,莱丝就是狗这个类的一个实例。一个具体对象属性的值被称作它的“状态”。(系统给对象分配内存空间,而不会给类分配内存空间。这很好理解,类是抽象的系统不可能给抽象的东西分配空间,而对象则是具体的。)

    定义莱丝是狗
    莱丝.毛皮颜色:棕白色
    莱丝.吠叫()
    

      

      我们无法让狗这个类去吠叫,但是我们可以让对象“莱丝”去吠叫,正如狗可以吠叫,但没有具体的狗就无法吠叫。类和对象就好比是“实型”和“1.23”,“实型”是一种数据的类型,而“1.23”是一个真正的“实数”(即对象)。所有的“实数”都具有“实型”所描述的特征,如“实数的大小”,系统则分配内存给“实数”存储具体的数值。

    消息传递

      一个对象通过接受消息、处理消息、传出消息或使用其他类的方法来实现一定功能,这叫做消息传递机制(Message Passing)。

      如:莱丝可以通过吠叫引起人的注意,从而导致一系列的事发生。

     

    二. 继承

    继承

      继承性(Inheritance)是指,在某种情况下,一个类会有“子类”。子类比原本的类(称为父类)要更加具体化。例如,“狗”这个类可能会有它的子类“牧羊犬”和“吉娃娃犬”。在这种情况下,“莱丝”可能就是牧羊犬的一个实例。子类会继承父类的属性和行为,并且也可包含它们自己的。我们假设“狗”这个类有一个方法(行为)叫做“吠叫()”和一个属性叫做“毛皮颜色”。它的子类(前例中的牧羊犬和吉娃娃犬)会继承这些成员。这意味着程序员只需要将相同的代码写一次。

    在伪代码中我们可以这样写:

    类牧羊犬:继承狗
     
    定义莱丝是牧羊犬
    莱丝.吠叫()            /* 注意这里调用的是狗这个类的吠叫方法。    
    

      

      回到前面的例子,“牧羊犬”这个类可以继承“毛皮颜色”这个属性,并指定其为棕白色。而“吉娃娃犬”则可以继承“吠叫()”这个方法,并指定它的音调高于平常。子类也可以加入新的成员,例如,“吉娃娃犬”这个类可以加入一个方法叫做“颤抖()”。设若用“牧羊犬”这个类定义了一个实例“莱丝”,那么莱丝就不会颤抖,因为这个方法是属于吉娃娃犬的,而非牧羊犬。事实上,我们可以把继承理解为“是”或“属于”。莱丝“是”牧羊犬,牧羊犬“属于”狗类。因此,莱丝既得到了牧羊犬的属性,又继承了狗的属性。 我们来看伪代码:
    类吉娃娃犬:继承狗
    开始
    公有成员:
        颤抖()
    结束
     
    类牧羊犬:继承狗
    定义莱丝是牧羊犬
    莱丝.颤抖()    /* 错误:颤抖是吉娃娃犬的成员方法。 */
    

      

    当一个类从多个父类继承时,我们称之为“多重继承”。如一只狗既是吉娃娃犬又是牧羊犬(虽然事实上并不合逻辑)。多重继承并不总是被支持的,因为它很难理解,又很难被好好使用。
     

    三. 多态与多态性

      A. 多态

      多态是指由继承而产生的相关的,不同的类,其对象对同一消息做出不同的响应。

      例如1:

        狗和鸡都有“叫()”这一方法,但是调用狗的“叫()”,狗会吠叫;

        调用鸡的“叫()”,鸡则会啼叫。

        虽然同样是做出叫这一行为,但狗和鸡具体做出的表现方式将大不相同。

      例如2:

        1. 序列类型有多种形态:字符串,列表,元组。

        2. 动物有多种形态:人,狗,猪

        3. 文件有多种形态:文本文件,可执行文件

    #!/usr/bin/python
    # -*- coding:utf-8 -*-
    
    #多态是同一种事物的多种形态
    class Animal:
        def talk(self):
            print('正在叫')
    
    
    class People(Animal):
        def talk(self):
            print('say hello')
    
    class Pig(Animal):
        def talk(self):
            print('哼哼哼')
    
    class Dog(Animal):
        def talk(self):
            print('汪汪汪')
    
    
    class Cat(Animal):
        def talk(self):
            print('喵喵喵')
    
    peo1=People()
    pig1=Pig()
    dog1=Dog()
    cat1=Cat()
    
    
    peo1.talk()
    dog1.talk()
    pig1.talk()
    

      B. 多态性

      多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同功能的函数。

      多态性:向不同的对象发送同一条消息(!!!obj.func():是调用了obj的方法func,又称为向obj发送了一条消息func),不同的对象在接收时会产生不同的行为(即方法)。

      也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。

      比如:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操作,学生执行的是放学操作,虽然二者消息一样,但是执行的效果不同。

    #多态性
    def func(obj):  # obj-可以任意命名
        obj.talk()
    
    func(peo1)
    func(pig1)
    func(dog1)
    func(cat1)
    

      

    1 say hello
    2 哼哼哼
    3 汪汪汪
    4 喵喵喵
    运行结果

       多态性的好处:

      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)
    '''
    

      

    四. 封装

    封装性

      具备封装性(Encapsulation)的面向对象程序设计隐藏了某一方法的具体执行步骤,取而代之的是通过消息传递机制传送消息给它。因此,举例来说,“狗”这个类有“吠叫()”的方法,这一方法定义了狗具体该通过什么方法吠叫。但是,莱丝的朋友并不知道它到底是如何吠叫的。

      封装是通过限制只有特定类的对象可以访问这一特定类的成员,而它们通常利用接口实现消息的传入传出。举个例子,接口能确保幼犬这一特征只能被赋予狗这一类。通常来说,成员会依它们的访问权限被分为3种:公有成员、私有成员以及保护成员

    封装分为俩个层面

      第一个层面的封装(什么都不用做):创建类和对象会分别创建二者的名称空间,我们只能用类名.或者obj.的方式去访问里面的名字,这本身就是一种封装

      注意:对于这一层面的封装就是访问隐藏属性的接口(类名. 和 实例名.

    class Foo:
        x=1
        def test(self):
            print('from test')
    
    print(Foo.x)                  # 直接访问名字
    

      第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。

    语法结构的解释:
    
    class Foo:
        __x=1         # 相当于 _Foo__x
        def __test(self):          # 相当于 _Foo__test
            print('from test')
    
    print(Foo.__dict__)
    Foo.test()                         # 报错调用失败 这个接口不可用了
    print(Foo._Foo__x)
    Foo._Foo__test(123)    
    

      只在类的内部使用、外部无法访问,示例如下:

    class People:
        __country='China'
        def __init__(self,name,age,sex):
            self.__name=name #self._People__name=name
            self.__age=age
            self.__sex=sex
    
        def tell_info(self):
            print('人的名字是:%s ,人的性别是:%s,人的年龄是:%s' %(
                self.__name, #p._People__name
                self.__age,
                self.__sex))
    
    p=People('alex',18,'male')
    print(p.__dict__)   # {'_People__name': 'alex', '_People__age': 18, '_People__sex': 'male'}
    p.tell_info()
    # print(p.__name)  #  AttributeError: 'People' object has no attribute 'People__name' 对象木有这个属性 外界访问不到的
    print(p._People__name)  # 正确
    
    
    p.__salary=3000 #{'_People__name': 'alex', '_People__age': 18, '_People__sex': 'male', '__salary': 3000}
                    # 可以看出只有初始化的被改变了
    print(p.__dict__)
    
    print(People.__dict__)
    
    People.__n=11111111111111111111111111
    print(People.__dict__)
    

      

    这种自动变形的特点:

    1.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果

    2.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。

    3.在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。

    注意:对于这一层面的封装(隐藏),我们需要在类中定义一个函数(接口函数)在它内部访问被隐藏的属性,然后外部就可以使用了

      举例3.在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

      

    #正常情况
    >>> class A:
    ...     def fa(self):
    ...         print('from A')
    ...     def test(self):
    ...         self.fa()
    ... 
    >>> class B(A):
    ...     def fa(self):
    ...         print('from B')
    ... 
    >>> b=B()
    >>> b.test()
    from B
    

      

    #把fa定义成私有的,即__fa
    >>> class A:
    ...     def __fa(self): #在定义时就变形为_A__fa
    ...         print('from A')
    ...     def test(self):
    ...         self.__fa() #只会与自己所在的类为准,即调用_A__fa
    ... 
    >>> class B(A):
    ...     def __fa(self):
    ...         print('from B')
    ... 
    >>> b=B()
    >>> b.test()
    from A
    

      

    制作一个接口:

    class People:
        def __init__(self,name,age):
            self.__name=name
            self.__age=age
    
        def tell_info(self):
            print('人的名字是:%s ,人的年龄是:%s' %(
                        self.__name, # p._People__name
                        self.__age))
    
        def set_info(self,x,y):                       # 提供一个接口,并且使用者可以更改内容
            if not isinstance(x,str):                      # 防止胡乱使用时,接口提供了一个判断类型机制
                raise TypeError('名字必须是字符串类型')
            if not isinstance(y,int):
                raise TypeError('年龄必须是整数类型')
    
            self.__name=x
            self.__age=y
    
    p=People('alex',1000)
    p.tell_info()
    
    p.set_info('alex_SB',123)     # 更改内容
    p.tell_info()
    

      

    property(内置函数)

    1.基本语法

    # property 基本语法
    
    class Foo:
        @property
        def test(self):
            print('from fooo')
        # test=property(test)         # property相当于把test本身返回
    
    f=Foo()
    # f.test()
    f.test        # 有了装饰器property test是数据属性 不用加括号直接用
    

      

    2.应用

    # property 应用--体质指数计算
    
    class People:
        def __init__(self,name,weight,height):
            self.name=name
            self.weight=weight
            self.height=height
    
        @property
        def bmi(self):
            return self.weight / (self.height ** 2)
    
    p=People('egon',75,1.80)
    p.height=1.82
    # print(p.bmi())
    print(p.bmi)            # 使用了装饰器后的属性方法不用括号直接用
    

      

    3.应用(对封装添加接口时,用装饰器来修饰添加想要的逻辑(如更改、删除...)来控制外界的访问)

    class People:
        def __init__(self,name,permmission=False):
            self.__name=name
            self.permmission=permmission
    
        @property
        def name(self):
            return self.__name
    
        @name.setter                    # 做了一个设置需求
        def name(self,value):
            if not isinstance(value,str):                   # 类型判断
                raise TypeError('名字必须是字符串类型')
            self.__name=value
    
        @name.deleter                   # 做了一个删除需求
        def name(self):
            if not self.permmission:                        # 默认权限关闭 不允许删除操作
                raise PermissionError('不允许的操作')
            del self.__name                                 # 这里是真是的删除语句__name
                                                            # 下面的del p.name是调用装饰器的封装函数
    
    p=People('egon')
    
    print(p.name)
    #
    p.name='egon666'
    print(p.name)           # 在没做设置装饰器前 用户是不能赋值的
    
    # p.name=35357
    p.permmission=True      # 开启权限
    del p.name
    

      

    五. 绑定方法与非绑定方法  

    类中定义的函数分成两大类:

      一:绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入):

        1. 绑定到类的方法:用classmethod装饰器装饰的方法。

        为类量身定制

        类.boud_method(),自动将类当作第一个参数传入

        (其实对象也可调用,但仍将类当作第一个参数传入)

        2. 绑定到对象的方法:没有被任何装饰器装饰的方法。

        为对象量身定制

        对象.boud_method(),自动将对象当作第一个参数传入

        (属于类的函数,类可以调用,但是必须按照函数的规则来,没有自动传值那么一说)

      二:非绑定方法:用staticmethod装饰器装饰的方法

       1. 不与类或对象绑定,类和对象都可以调用,但是没有自动传值那么一说。就是一个普通工具而已

      注意:与绑定到对象方法区分开,在类中直接定义的函数,没有被任何装饰器装饰的,都是绑定到对象的方法,可不是普通函数,对象调用该方法会自动传值,而staticmethod装饰的方法,不管谁来调用,都没有自动传值一说

    示例 1. 绑定方法

    1 HOST='127.0.0.1'
    2 PORT=3306
    3 DB_PATH=r'C:UsersAdministratorPycharmProjects	est面向对象编程	est1db'
    setting.py
    import settings
    class MySQL:
        def __init__(self,host,port):
            self.host=host
            self.port=port
            print('conneting...')
    
        # @classmethod                # 绑定到类的方法
        # def from_conf(cls):
        #     return cls(settings.HOST,settings.PORT)  # MySQL('127.0.0.1',3306)  调用配置文件里HOST、PORT
    
        @staticmethod               # 非绑定的方法 不与类或者对象绑定 谁都可以调用
        def from_conf():
            return MySQL(settings.HOST,settings.PORT)
    
        def select(self):           # 绑定到对象的方法
            print(self)
            print('select function')
    
    # # conn=MySQL('192.168.1.3',3306)
    # # conn.select()
    #
    # conn1=MySQL('192.168.1.3',3306)
    conn2=MySQL.from_conf()             # 使用类方法来实例化
    print(conn2.host,conn2.port)
    

      

     示例 2. 非绑定方法  添加 @staticmethod 

    import hashlib
    import time
    import settings
    class MySQL:
        def __init__(self,host,port):
            self.id=self.create_id()  # 非绑定类型 直接调用 不需要self返回值
            self.host=host
            self.port=port
            print('conneting...')
    
        @staticmethod
        def create_id(): #非绑定方法,就是类中的普通工具包
            m=hashlib.md5(str(time.clock()).encode('utf-8'))  # 哈希随机生成一个机器时间id
            return m.hexdigest()
    
        @classmethod
        def from_conf(cls):
            return cls(settings.HOST,settings.PORT) #MySQL('127.0.0.1',3306)
    
        def select(self): #绑定到对象的方法
            print(self)
            print('select function')
    
    conn1=MySQL.from_conf()
    conn2=MySQL.from_conf()
    conn3=MySQL.from_conf()
    conn4=MySQL.from_conf()
    
    print(conn1.id)
    print(conn2.id)
    print(conn3.id)
    print(conn4.id)
    

      

    六. staticmethod 与 classmethod 的区别

     1 #statcimethod 与classmethod的区别
     2 import settings
     3 class MySQL:
     4     def __init__(self,host,port):
     5         self.host=host
     6         self.port=port
     7 
     8     @classmethod
     9     def from_conf(cls):
    10         return cls(settings.HOST,settings.PORT) #Mariadb('127.0.0.1',3306)
    11 
    12     # @staticmethod
    13     # def from_conf():
    14     #     return MySQL(settings.HOST, settings.PORT)  # 这样的话实例化对象就写死在MySQL类中,下面的Mariab子类继承就不能实例化了
    15 
    16     def __str__(self):
    17         return '就不告诉你'
    18 # conn=MySQL.from_conf()
    19 # print(conn.host)
    20 
    21 class Mariab(MySQL):
    22     def __str__(self):
    23         return '这是子类'
    24 
    25 conn1=Mariab.from_conf()    # 此时from_conf 不能调自己的方法 因为被绑定了<__main__.MySQL object at 0x0000013FE0D0E6D8>
    26                             # conn1就是父类产生的 所以@staticmethod 不适用 我们来开启@classmethod 方法来解决
    27 print(conn1)
    示例代码

    七. 内置方法

    isinstance(obj,cls)检查是否obj是否是类 cls 的对象

    class Foo(object):
        pass
     
     obj = Foo()
      
     print(isinstance(obj, Foo))
    

      

    issubclass(sub, super)检查sub类是否是 super 类的派生类

    class Foo:
        pass
    
    class Bar(Foo):
        pass
    
    print(issubclass(Bar,Foo))
    

      

    八. 反射

      定义:程序可以访问、检测和修改它本身状态或行为的一种能力(自省)

      应用:通过字符串的形式操作对象相关的属性,python中的一切事物都是对象(都可以使用反射)

      四个可以实现自省的函数:

      下列方法适用于类和对象(一切皆对象,类本身也是一个对象)

     1 # 判断object中有没有一个name字符串对应的方法或属性
     2 class Chinese:
     3     country='China'
     4     def __init__(self,name,age):
     5         self.name=name
     6         self.age=age
     7 
     8 p=Chinese('egon',18)
     9 
    10 print(hasattr(p,'name'))
    11 print(hasattr(Chinese,'country'))
    hasattr(object,name)
     1 # setattr 设置进去值
     2 
     3 class Chinese:
     4     country='China'
     5     def __init__(self,name,age):
     6         self.name=name
     7         self.age=age
     8 
     9 p=Chinese('egon',18)
    10 
    11 p.x=1
    12 print(p.__dict__)
    13 print(p.x)
    14 setattr(p,'x',1231231231231)
    15 print(p.__dict__)
    16 print(p.x)
    setattr(x,y,v)
     1 # getattr 找值 找不到就第三个参数提示
     2 
     3 class Chinese:
     4     country='China'
     5     def __init__(self,name,age):
     6         self.name=name
     7         self.age=age
     8 
     9 p=Chinese('egon',18)
    10 
    11 print(getattr(p,'x','not exist'))
    12 print(getattr(p,'name','not exist'))
    getattr(object, name, default=None)
    # 组合应用
    
    setattr(p,'x',123123123123123) #添加
    if hasattr(p,'x'):             #判断
        res=getattr(p,'x')         #获取
        print(res)
    

      

    # 反射当前模块 组合应用
    
    import sys
    m=sys.module[__name__]
    
    if hasattr(m,'chinese'):
        res = getattr(m,'chinese')
        print(res)
        
        obj=res('egon',18)             # 也可以实例化 反射name
        print(obj.name)    
    

      

     1 # 删除
     2 
     3 class Chinese:
     4     country='China'
     5     def __init__(self,name,age):
     6         self.name=name
     7         self.age=age
     8 
     9 p=Chinese('egon',18).
    10 
    11 print(Chinese.country)
    12 delattr(Chinese,'country')
    13 print(Chinese.country)
    delattr(x,y)

    反射示范:

    class FtpCLient:
        def __init__(self,host):
            self.host=host
            print('connecting...')
    
        def run(self):
            while True:
                inp=input('>>: ').strip()
                inp_l=inp.split()
                if hasattr(self,inp_l[0]):
                    func=getattr(self,inp_l[0])
                    func(inp_l)
    
        def get(self,arg):
            print('download file',arg[1])
    
    f=FtpCLient('192.168.1.2')
    f.run()
    

      

    补充:

    父类与子类都有相同方法test时,子类调用父类的方式:super().test()

  • 相关阅读:
    MySQL Backup mysqldump 常用选项与主要用法--转发
    openssl 之RSA加密
    Windows 之Dll/lib导出
    缓存雪崩、击穿、穿透
    时间复杂度
    分布式事务
    mysql主从复制与读写分离
    什么是消息队列?
    微服务架构演化
    高并发问题常规思路
  • 原文地址:https://www.cnblogs.com/lipingzong/p/6991840.html
Copyright © 2011-2022 走看看