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

时间:2022-02-01 21:49:16

今日概要:

  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("\n===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(),可以查看类的继承顺序

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

继承顺序:

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