• python自动化开发-[第七天]-面向对象


    今日概要:

      1、继承

      2、封装

      3、多态与多态性

      4、反射

      5、绑定方法和非绑定方法

    一、新式类和经典类的区别  

    大前提:
    1.只有在python2中才分新式类和经典类,python3中统一都是新式类
    2.新式类和经典类声明的最大不同在于,所有新式类必须继承至少一个父类
    3.所有类甭管是否显式声明父类,都有一个默认继承object父类
    在python2中的区分
    经典类:
    class 类名:
        pass
    
    经典类:
    class 类名(父类):
        pass
    
    在python3中,上述两种定义方式全都是新式类
    

    二、类的两种作用:属性引用和实例化

    例子:

    class gailun:
        country = 'demaxiya'
        def __init__(self,name,attack_id=50,flood=100):
            self.name = name
            self.attack_id = attack_id
            self.flood = flood
    
        def attack(self,persen):
    
            self.flood -= persen.attack_id

      1、属性引用(类名.属性)

    class gailun:  #定义一个英雄gailun类,不通玩家可以用他实例出自己的英雄
        country = 'demaxiya' #定义一个类变量
        def __init__(self,name,attack_id=50,flood=100):  #定义一个初始化函数
            self.name = name
            self.attack_id = attack_id
            self.flood = flood
    
        def attack(self,persen):  #定义一个函数属性
    
            self.flood -= persen.attack_id
    
    
    g = gailun('dragon')  #创建了一个对象
    print (g.country) #引用类的数据属性,该属性所有对象和实例共享
    gailun.country #引用类的属性,该属性所有对象和实例共享
    g.name = 'banana' #增加属性
    del g.name #删除属性

      2、实例化__init__,self

        类名加括号就执行类的__init__函数的运行,可以用__init__来定义每一个实例的特征

    g = gailun('德玛西亚')#就是在执行gailun.__init__(g,'德玛西亚'),然后执行__init__内的代码g.name=‘德玛西亚’等
    

      

    一,类的属性有两种属性可以查看
    dir(类名):查出的是一个名字列表
    类名.__dict__:查出的是一个字典,key为属性名,value为属性值
    二:特殊的类属性
    类名.__name__# 类的名字(字符串)
    类名.__doc__# 类的文档字符串
    类名.__base__# 类的第一个父类
    类名.__bases__# 类所有父类构成的元组
    类名.__dict__# 类的字典属性,名称空间
    类名.__module__# 类定义所在的模块
    类名.__class__# 实例对应的类(仅新式类中)
    

      3、对象/实例只有一种作用:属性作用

    三、类的名称空间与对象/实例的名称空间

      创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性

      类有两种属性:数据属性和函数属性

      类的数据属性是共享给所有对象的

    >>> id(r1.camp) #本质就是在引用类的camp属性,二者id一样
    4315241024
    >>> id(Riven.camp)
    4315241024

      类的函数属性是绑定给所有对象的

    >>> id(r1.attack) 
    >>> id(Riven.attack)
    
    '''
    r1.attack就是在执行Riven.attack的功能,python的class机制会将Riven的函数属性attack绑定给r1,r1相当于拿到了一个指针,指向Riven类的attack功能
    
    除此之外r1.attack()会将r1传给attack的第一个参数
    '''

      创建一个对象/实例就会创建一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性

      在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常 

    练习:每次对象实例化一次,就计数一次,最后打印出总次数

    class count(object):
        num = 0   #定义类变量
        def __init__(self,name):
            self.name = name
            count.num +=1
    
    
    g = count('alex')
    g1 = count('egon')
    
    print (count.num)

    四、类的继承

      1、继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类

    class ParentClass1:  #定义父类
        pass 
    
    
    class ParentClass2: #定义子类
        pass
    
    
    class SubClass1(ParentClass1): #继承ParentClass1类,派生出SubClass1子类
        pass
    
    
    class SubClass2(ParentClass1, ParentClass2): #继承ParentClass1类,ParentClass2,派生出SubClass1子类
        pass
    

       2、查看当前类的继承 类名.__bases__查看当前类所有的继承,   ****__base__只查看从左到右继承的第一个子类

    #查看当前类的继承顺序
    print(SubClass1.__bases__)
    print(SubClass2.__bases__)
    
    
    '''
    
    输出:
    (<class '__main__.ParentClass1'>,)
    (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>) 
    
    
    '''

       3、继承的好处:减少冗余代码

       4、派生的定义:在子类定义新的属性,覆盖掉父类的属性,称为派生

    例子:

    class Animal:
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def eat(self):
            print('eating')
    
        def talk(self):
            print('%s 正在叫' %self.name)
    
    
    class People(Animal):
        def __init__(self, name, age, sex,education):
            Animal.__init__(self,name,age,sex)
            self.education=education
    
        def talk(self):
            Animal.talk(self)
            print('%s say hello' %self.name)
    
    class Pig(Animal):
        pass
    
    class Dog(Animal):
        pass
    
    
    peo1=People('xiaoming',18,'male','小学肄业') #People.__init__
    
    pig1=Pig('xiaohong',20,'female')
    
    dog1=Dog('xiaogang',30,'male')
    
    print(peo1.education)
    
    
    peo1.talk()
    pig1.talk()
    dog1.talk()
    
    
    
    '''
    输出:
    小学肄业
    xiaohong 正在叫
    xiaohong say hello
    xiaoming 正在叫
    xiaogang 正在叫
    '''
    

       5、继承查找顺序:

    class Parent:
        def foo(self):
            print('Parent.foo')
            self.bar() #s.bar()
    
        def bar(self):
            print('Parent.bar')
    
    
    class Sub(Parent):
        def bar(self):
            print('Sub.bar')
    
    s=Sub()  #实例化
    s.foo() #s.foo 查看当前类里没有foo,就去继承的父类里去查找,父类里有foo,同时调用self.bar,
             由于传入的self为sub实例化的对象,所以子类和父类同时存在相同的函数属性,优先查找子类的
    
    '''
    输出
    Parent.foo
    Sub.bar
    '''
    
    
    class Parent:
        def foo(self):
            print('Parent.foo')
            self.bar() #s.bar()
    
        def bar(self):
            print('Parent.bar')
    
    
    class Sub(Parent):
        pass
    
    s=Sub()
    s.foo() #s.foo
    
    
    '''
    输出:
    Parent.foo
    Parent.bar
    '''
    

       6、子类继承,修改父类属性

    class Animal:
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def eat(self):
            print('eating')
    
        def talk(self):
            print('%s 正在叫' % self.name)
    
    
    class People(Animal):
        def __init__(self, name, age, sex, education):
            Animal.__init__(self, name, age, sex)   #继承父类的__init__功能
            self.education = education
    
        def talk(self):
            Animal.talk(self)
            print('%s say hello' % self.name)
    
    
    class Pig(Animal):
        pass
    
    
    class Dog(Animal):
        pass
    
    
    peo1 = People('alex', 18, 'male', '小学肄业')  # People.__init__
    pig1 = Pig('wupeiqi', 20, 'female')
    dog1 = Dog('yuanhao', 30, 'male')
    
    print(isinstance(peo1,People))
    print(isinstance(pig1,Pig))
    print(isinstance(dog1,Dog))
    
    
    print(isinstance(peo1,Animal))
    print(isinstance(pig1,Animal))
    print(isinstance(dog1,Animal))
    
    
    
    
    '''
    输出:
    True
    True
    True
    True
    True
    True
    '''

       7、继承反映的是一种什么什么的关系,组合也可以解决代码冗余问题,但是组合反映是一种什么有什么的关系

    组合例子:

      当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好

    class People:
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
    
    class Teacher(People):
        def __init__(self,name,age,sex,salary):
            People.__init__(self,name,age,sex)
            self.salary=salary
    
    class Student(People):
        pass
    
    
    
    
    
    class Date:
        def __init__(self, year, mon, day):
            self.year = year
            self.mon = mon
            self.day = day
    
        def tell(self):
            print('%s-%s-%s' % (self.year, self.mon, self.day))
    
    
    class Teacher(People):
        def __init__(self, name, age, sex, salary, year, mon, day):
            self.name = name
            self.age = age
            self.sex = sex
            self.salary = salary
            self.birth = Date(year, mon, day)
    
    
    class Student(People):
        def __init__(self, name, age, sex, year, mon, day):
            self.name = name
            self.age = age
            self.sex = sex
            self.birth = Date(year, mon, day)
    
    
    t=Teacher('egon',18,'male',3000,1995,12,31)
    t.birth.tell()  #组合的形成
    '''
    输出
    1995-12-31
    '''

    五、接口的定义  

      定义接口Interface类来模仿接口的概念,python中压根就没有interface关键字来定义一个接口。

      java中接口的定义  

    =================第一部分:Java 语言中的接口很好的展现了接口的含义: IAnimal.java
    /*
    * Java的Interface很好的体现了我们前面分析的接口的特征:
    * 1)是一组功能的集合,而不是一个功能
    * 2)接口的功能用于交互,所有的功能都是public,即别的对象可操作
    * 3)接口只定义函数,但不涉及函数实现
    * 4)这些功能是相关的,都是动物相关的功能,但光合作用就不适宜放到IAnimal里面了 */
    
    package com.oo.demo;
    public interface IAnimal {
        public void eat();
        public void run(); 
        public void sleep(); 
        public void speak();
    }
    
    =================第二部分:Pig.java:猪”的类设计,实现了IAnnimal接口 
    package com.oo.demo;
    public class Pig implements IAnimal{ //如下每个函数都需要详细实现
        public void eat(){
            System.out.println("Pig like to eat grass");
        }
    
        public void run(){
            System.out.println("Pig run: front legs, back legs");
        }
    
        public void sleep(){
            System.out.println("Pig sleep 16 hours every day");
        }
    
        public void speak(){
            System.out.println("Pig can not speak"); }
    }
    
    =================第三部分:Person2.java
    /*
    *实现了IAnimal的“人”,有几点说明一下: 
    * 1)同样都实现了IAnimal的接口,但“人”和“猪”的实现不一样,为了避免太多代码导致影响阅读,这里的代码简化成一行,但输出的内容不一样,实际项目中同一接口的同一功能点,不同的类实现完全不一样
    * 2)这里同样是“人”这个类,但和前面介绍类时给的类“Person”完全不一样,这是因为同样的逻辑概念,在不同的应用场景下,具备的属性和功能是完全不一样的 */
    
    package com.oo.demo;
    public class Person2 implements IAnimal { 
        public void eat(){
            System.out.println("Person like to eat meat");
        }
    
        public void run(){
            System.out.println("Person run: left leg, right leg");
        }
    
        public void sleep(){
            System.out.println("Person sleep 8 hours every dat"); 
        }
    
        public void speak(){
            System.out.println("Hellow world, I am a person");
        } 
    }
    
    =================第四部分:Tester03.java
    package com.oo.demo;
    
    public class Tester03 {
        public static void main(String[] args) {
            System.out.println("===This is a person==="); 
            IAnimal person = new Person2();
            person.eat();
            person.run();
            person.sleep();
            person.speak();
            
            System.out.println("
    ===This is a pig===");
            IAnimal pig = new Pig();
            pig.eat();
            pig.run();
            pig.sleep();
            pig.speak();
        } 
    }
    
    java中的interface
    

     继承的两种用途:

      一:继承基类的方法,并且做出自己的改变或者扩展(代码重用)

      二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能

    class File:
        def read(self): #定接口函数read
            raise TypeError('类型错误') #raise主动抛出异常
    
        def write(self): #定义接口函数write
            raise TypeError('类型错误')
    
    
    class Txt(File): #文本,具体实现read和write
        def read(self):
            print('文本数据的读取方法')
    
        def write(self):
            print('文本数据的读取方法')
    
    class Sata(File): #磁盘,具体实现read和write
        def read(self):
            print('硬盘数据的读取方法')
    
        def write(self):
            print('硬盘数据的读取方法')
    
    class Process(File):
        # def read(self):
        #     print('进程数据的读取方法')
        #
        # def write(self):
        #     print('进程数据的读取方法')
        def xie(self):
            pass
    
        def du(self):
            pass
    p=Process()
    p.read()
    
    
    t=Txt()
    p=Process()
    d=Sata()
    
    print(isinstance(t,File))
    print(isinstance(p,File))
    print(isinstance(d,File))
    
    t.read()
    p.read()
    d.read() 

      2、为什么要用接口

      接口提取了一群类共同的函数,可以把接口当做一个函数的集合。然后让子类去实现接口中的函数。

      这么做的意义在于归一化,什么叫归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样。

      归一化,让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。

      比如:我们定义一个动物接口,接口里定义了有跑、吃、呼吸等接口函数,这样老鼠的类去实现了该接口,松鼠的类也去实现了该接口,由二者分别产生一只老鼠和一只松鼠送到你面前,即便是你分别不到底哪只是什么鼠你肯定知道他俩都会跑,都会吃,都能呼吸。

      再比如:我们有一个汽车接口,里面定义了汽车所有的功能,然后由本田汽车的类,奥迪汽车的类,大众汽车的类,他们都实现了汽车接口,这样就好办了,大家只需要学会了怎么开汽车,那么无论是本田,还是奥迪,还是大众我们都会开了,开的时候根本无需关心我开的是哪一类车,操作手法(函数调用)都一样

    五、抽象类

      1 什么是抽象类

          与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

      2 为什么要有抽象类

          如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类是从一堆中抽取相同的内容而来的,内容包括数据属性和函数属性。

        比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。

          从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。

        从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的

    例子: 

    import abc
    class File(metaclass=abc.ABCMeta):#定义接口Interface类来模仿接口的概念,python中压根就没有interface关键字来定义一个接口。
        @abc.abstractmethod
        def read(self): #定接口函数read
            pass
    
        @abc.abstractmethod
        def write(self): #定义接口函数write
            pass
    
    class Process(File):
        def read(self):  #将read名字修改,或者缺少这两个参数,就会报错
            # print('进程数据的读取方法')
            pass
        def write(self):
            print('进程数据的读取方法')
    
        # def xie(self):   
        #     pass
        #
        # def du(self):
        #     pass
    p=Process()
    p.read()

    六、类的继承顺序

      新式类:广度优先

      经典类:深度优先

      通过mro(),可以查看类的继承顺序

    继承顺序:

    class A(object):
        def test(self):
            print('from A')
    
    class B(A):
        def test(self):
            print('from B')
    
    class C(A):
        def test(self):
            print('from C')
    
    class D(B):
        def test(self):
            print('from D')
    
    class E(C):
        def test(self):
            print('from E')
    
    class F(D,E):
        # def test(self):
        #     print('from F')
        pass
    f1=F()
    f1.test()
    print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性
    
    #新式类继承顺序:F->D->B->E->C->A
    #经典类继承顺序:F->D->B->A->E->C
    #python3中统一都是新式类
    #pyhon2中才分新式类与经典类
    
    继承顺序
    

    ***子类继承父类的方法super() 

    class Vehicle: #定义交通工具类
         Country='China'
         def __init__(self,name,speed,load,power):
             self.name=name
             self.speed=speed
             self.load=load
             self.power=power
    
         def run(self):
             print('开动啦...')
    
    class Subway(Vehicle): #地铁
        def __init__(self,name,speed,load,power,line):
            #super(Subway,self) 就相当于实例本身 在python3中super()等同于super(Subway,self)
            super().__init__(name,speed,load,power)
            self.line=line
    
        def run(self):
            print('地铁%s号线欢迎您' %self.line)
            super(Subway,self).run()
    
    class Mobike(Vehicle):#摩拜单车
        pass
    
    line13=Subway('中国地铁','180m/s','1000人/箱','电',13)
    line13.run()

    ***不用super()出现的问题

    #每个类中都继承了且重写了父类的方法
    class A:
        def __init__(self):
            print('A的构造方法')
    class B(A):
        def __init__(self):
            print('B的构造方法')
            A.__init__(self)
    
    
    class C(A):
        def __init__(self):
            print('C的构造方法')
            A.__init__(self)
    
    
    class D(B,C):
        def __init__(self):
            print('D的构造方法')
            B.__init__(self)
            C.__init__(self)
    
        pass
    f1=D()
    
    print(D.__mro__) #python2中没有这个属性
    

       当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表

    解决例子:

    #每个类中都继承了且重写了父类的方法
    class A:
        def __init__(self):
            print('A的构造方法')
    class B(A):
        def __init__(self):
            print('B的构造方法')
            super(B,self).__init__()
    
    
    class C(A):
        def __init__(self):
            print('C的构造方法')
            super(C,self).__init__()
    
    
    class D(B,C):
        def __init__(self):
            print('D的构造方法')
            super(D,self).__init__()
    
    f1=D()
    
    print(D.__mro__) #python2中没有这个属性

    七、多态和多态性

      1、多态是同一种事物的不同形态

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

        在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息(!!!obj.func():是调用了obj的方法func,又称为向obj发送了一条消息func),不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。

      3、多态性的优点:

        1.增加了程序的灵活性

        以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)

        2.增加了程序额可扩展性

        通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用   

      

    #!/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()
     
     
    def func(x):
        x.talk()
     
     
    func(peo1)
    func(pig1)
    func(dog1)
    func(cat1) 

    八、封装

      1、封装的定义:

        1:封装数据的主要原因是:保护隐私

        2:封装方法的主要原因是:隔离复杂度(快门就是傻瓜相机为傻瓜们提供的方法,该方法将内部复杂的照相功能都隐藏起来了)

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

      3、在python中用双下划线的方式实现隐藏属性(设置成私有的)

      类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:  

    class A:
        __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
        def __init__(self):
            self.__X=10 #变形为self._A__X
        def __foo(self): #变形为_A__foo
            print('from A')
        def bar(self):
            self.__foo() #只有在类内部才可以通过__foo的形式访问到.

    例子: 

    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__)
    p.tell_info()
    
    print(p.__name)
    
    p.__salary=3000  #__私有属性或者变量只在定义时候修改
    print(p.__dict__)
    
    print(People.__dict__)
    
    People.__n=11111111111111111111111111
    print(People.__dict__)
    print(People.__n)

    例子:

    class Parent:
        def foo(self):
            print('from parent.foo')
            self.__bar() #self._Parent__bar()
    
        def __bar(self): #_Parent__bar
            print('from parent.bar')
    
    
    class Sub(Parent):
        # def __bar(self): #_Sub__bar
        #     print('from SUb.bar')
        pass
    s=Sub()
    s.foo()
    
    s._Parent__bar()
    

    九、特性

      property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

    例子:

      1、求圆面积和圆的周长,人的体脂

    #!/usr/bin/python
    # -*- coding:utf-8 -*-
    
    import math
    class round(object):
    
        def __init__(self,leght):
            self.leght = leght
    
    
        @property
        def zhouchang(self):
            return math.pi * self.leght
    
    
        @property
        def mianji(self):
            return math.pi * ((self.leght/2) ** 2)
    
    
    g = round(10)
    print(g.zhouchang)
    
    print (g.mianji)
    
    
    
    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)
    
    a = People('alex',70,1.70)
    print (a.bmi)
    

       2、python并没有在语法上把它们三个内建到自己的class机制中,在C++里一般会将所有的所有的数据都设置为私有的,然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现

    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
    
    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装饰的方法,不管谁来调用,都没有自动传值一说
     
    简单例子:
    class Foo:
        def test1(self):
            pass
        @classmethod   #只能类进行调用
        def test2(cls): 
            print(cls)
        @staticmethod #类和对象都可以调用
        def test3():
            pass
    
    f=Foo()
    print(f.test1)
    print(Foo.test2)
    print(Foo.test3)
    print(f.test3)
    

      1、staticmethod

        statimethod不与类或对象绑定,谁都可以调用,没有自动传值效果,python为我们内置了函数staticmethod来把类中的函数定义成静态方法

    import hashlib
    import time
    class MySQL:
        def __init__(self,host,port):
            self.id=self.create_id()
            self.host=host
            self.port=port
        @staticmethod
        def create_id(): #就是一个普通工具
            m=hashlib.md5(str(time.clock()).encode('utf-8'))
            return m.hexdigest()
    
    
    print(MySQL.create_id) #<function MySQL.create_id at 0x0000000001E6B9D8> #查看结果为普通函数
    conn=MySQL('127.0.0.1',3306)
    print(conn.create_id) #<function MySQL.create_id at 0x00000000026FB9D8> #查看结果为普通函数
    

       2、classmethod

        classmehtod是给类用的,即绑定到类,类在使用时会将类本身当做参数传给类方法的第一个参数(即便是对象来调用也会将类当作第一个参数传入),python为我们内置了函数classmethod来把类中的函数定义成类方法

    settings.py

      

    HOST='127.0.0.1'
    PORT=3306
    

     示例:  

    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)
        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() #对象也可以调用,但是默认传的第一个参数仍然是类

       3、classmethod和staticmethod区别 

    import settings
    class MySQL:
        def __init__(self,host,port):
            self.host=host
            self.port=port
        @staticmethod
        def from_conf():
            return MySQL(settings.HOST,settings.PORT)
    
        # @classmethod
        # def from_conf(cls):
        #     return cls(settings.HOST,settings.PORT)
    
        def __str__(self):
            return '就不告诉你'
    
    
    
    class Mariadb(MySQL):
        def __str__(self):
            return '主机:%s 端口:%s' %(self.host,self.port)
    
    
    m=Mariadb.from_conf()
    print(m) #我们的意图是想触发Mariadb.__str__,但是结果触发了MySQL.__str__的执行,打印就不告诉你:
    

    时间练习:

    class Date:
        def __init__(self,year,month,day):
            self.year=year
            self.month=month
            self.day=day
        @staticmethod
        def now(): #用Date.now()的形式去产生实例,该实例用的是当前时间
            t=time.localtime() #获取结构化的时间格式
            return Date(t.tm_year,t.tm_mon,t.tm_mday) #新建实例并且返回
        @staticmethod
        def tomorrow():#用Date.tomorrow()的形式去产生实例,该实例用的是明天的时间
            t=time.localtime(time.time()+86400)
            return Date(t.tm_year,t.tm_mon,t.tm_mday)
    
    a=Date('1987',11,27) #自己定义时间
    b=Date.now() #采用当前时间
    c=Date.tomorrow() #采用明天的时间
    
    print(a.year,a.month,a.day)
    print(b.year,b.month,b.day)
    print(c.year,c.month,c.day)
    
    
    #分割线==============================
    import time
    class Date:
        def __init__(self,year,month,day):
            self.year=year
            self.month=month
            self.day=day
        @staticmethod
        def now():
            t=time.localtime()
            return Date(t.tm_year,t.tm_mon,t.tm_mday)
    
    class EuroDate(Date):
        def __str__(self):
            return 'year:%s month:%s day:%s' %(self.year,self.month,self.day)
    
    e=EuroDate.now()
    print(e) #我们的意图是想触发EuroDate.__str__,但是结果为
    '''
    输出结果:
    <__main__.Date object at 0x1013f9d68>
    '''
    因为e就是用Date类产生的,所以根本不会触发EuroDate.__str__,解决方法就是用classmethod
    
    import time
    class Date:
        def __init__(self,year,month,day):
            self.year=year
            self.month=month
            self.day=day
        # @staticmethod
        # def now():
        #     t=time.localtime()
        #     return Date(t.tm_year,t.tm_mon,t.tm_mday)
    
        @classmethod #改成类方法
        def now(cls):
            t=time.localtime()
            return cls(t.tm_year,t.tm_mon,t.tm_mday) #哪个类来调用,即用哪个类cls来实例化
    
    class EuroDate(Date):
        def __str__(self):
            return 'year:%s month:%s day:%s' %(self.year,self.month,self.day)
    
    e=EuroDate.now()
    print(e) #我们的意图是想触发EuroDate.__str__,此时e就是由EuroDate产生的,所以会如我们所愿
    '''
    输出结果:
    year:2017 month:3 day:3
    '''  

    练习:

      定义MySQL类

        1.对象有id、host、port三个属性

        2.定义工具create_id,在实例化时为每个对象随机生成id,保证id唯一

        3.提供两种实例化方式,方式一:用户传入host和port 方式二:从配置文件中读取host和port进行实例化

        4.为对象定制方法,save和get,save能自动将对象序列化到文件中,文件名为id号,文件路径为配置文件中DB_PATH;get方法用来从文件中反序列化出对象

    class Date:
        def __init__(self,year,month,day):
            self.year=year
            self.month=month
            self.day=day
        @staticmethod
        def now(): #用Date.now()的形式去产生实例,该实例用的是当前时间
            t=time.localtime() #获取结构化的时间格式
            return Date(t.tm_year,t.tm_mon,t.tm_mday) #新建实例并且返回
        @staticmethod
        def tomorrow():#用Date.tomorrow()的形式去产生实例,该实例用的是明天的时间
            t=time.localtime(time.time()+86400)
            return Date(t.tm_year,t.tm_mon,t.tm_mday)
    
    a=Date('1987',11,27) #自己定义时间
    b=Date.now() #采用当前时间
    c=Date.tomorrow() #采用明天的时间
    
    print(a.year,a.month,a.day)
    print(b.year,b.month,b.day)
    print(c.year,c.month,c.day)
    
    
    #分割线==============================
    import time
    class Date:
        def __init__(self,year,month,day):
            self.year=year
            self.month=month
            self.day=day
        @staticmethod
        def now():
            t=time.localtime()
            return Date(t.tm_year,t.tm_mon,t.tm_mday)
    
    class EuroDate(Date):
        def __str__(self):
            return 'year:%s month:%s day:%s' %(self.year,self.month,self.day)
    
    e=EuroDate.now()
    print(e) #我们的意图是想触发EuroDate.__str__,但是结果为
    '''
    输出结果:
    <__main__.Date object at 0x1013f9d68>
    '''
    因为e就是用Date类产生的,所以根本不会触发EuroDate.__str__,解决方法就是用classmethod
    
    import time
    class Date:
        def __init__(self,year,month,day):
            self.year=year
            self.month=month
            self.day=day
        # @staticmethod
        # def now():
        #     t=time.localtime()
        #     return Date(t.tm_year,t.tm_mon,t.tm_mday)
    
        @classmethod #改成类方法
        def now(cls):
            t=time.localtime()
            return cls(t.tm_year,t.tm_mon,t.tm_mday) #哪个类来调用,即用哪个类cls来实例化
    
    class EuroDate(Date):
        def __str__(self):
            return 'year:%s month:%s day:%s' %(self.year,self.month,self.day)
    
    e=EuroDate.now()
    print(e) #我们的意图是想触发EuroDate.__str__,此时e就是由EuroDate产生的,所以会如我们所愿
    '''
    输出结果:
    year:2017 month:3 day:3
    '''

    十一、反射

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

      hasatter 判断object中有没有一个变量字符串对应的方法或属性

      getatter 获取成员

      setatter 设置成员

      delatter 检查成员

    例子1:

    class Foo(object):
     
        def __init__(self):
            self.name = 'abc'
     
        def func(self):
            return 'ok'
     
    obj = Foo()
    #获取成员
    ret = getattr(obj, 'func')#获取的是个对象
    r = ret()
    print(r)
    #检查成员
    ret = hasattr(obj,'func')#因为有func方法所以返回True
    print(ret)
    #设置成员
    print(obj.name) #设置之前为:abc
    ret = setattr(obj,'name',19)
    print(obj.name) #设置之后为:19
    #删除成员
    print(obj.name) #abc
    delattr(obj,'name')
    print(obj.name) #报错
    

    例子2:ftp的client

       

    好处一:实现可插拔机制

        有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。

        总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能

    #!/usr/bin/python
    # -*- coding:utf-8 -*-
     
     
    class FtpClient:
        'ftp客户端,但是还么有实现具体的功能'
        def __init__(self,addr):
            print('正在连接服务器[%s]' %addr)
            self.addr=addr
     
        def get(self):
            print('is getting')
    

     使用ftp的client

    import ftpclient
    f1=ftpclient.FtpClient('192.168.1.1')
    
    if hasattr(f1,'get'):
        func=getattr(f1,'get')
        func()
    
    print('其他的代码1')
    print('其他的代码2')
    print('其他的代码3')

      

  • 相关阅读:
    进程二
    高德地图api的使用
    《架构即未来》读后感3
    三周总结
    性能战术:
    二周总结
    《 架构即未来》读后感2
    一周总结
    《架构即未来》读后感
    学生信息系统dao层
  • 原文地址:https://www.cnblogs.com/liujiliang/p/6992951.html
Copyright © 2020-2023  润新知