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

  

原文地址:https://www.cnblogs.com/liujiliang/p/6992951.html