第七篇 面向对象编程

2018-06-14  本文已影响0人  张大志的博客

一、复习

logging :日志
    1、通过函数去控制
    2、logger对象
re :正则
time&datetime 时间
    时间戳:记录一个时间节点
    格式化时间:给人看的
    结构化时间:计算机计算
os:和操作系统交互
sys:和python解释器交互
hashlib:摘要算法模块
    1、文件的一致性校验
    2、用户的加密认证
    3、不可逆性、撞库和加盐
json/pickle/shelve
    1、为什么要序列化:数据存储、网络传输
    2、json:通用的序列化格式、支持的数据类型有限
    3、pickle:只能python程序使用、游戏
    4、shelve:把数据当成一个字典操作、操作简单
configpaser
    1、特殊格式的配置文件
random 随机数
    1、验证码

# subprocess : 多进程
# xml:tomcat的配置文件

二、time模块的补充

计算时间差
示例1
import time
true_time=time.mktime(time.strptime('2017-09-11 08:30:00','%Y-%m-%d %H:%M:%S')) #将格式化时间转化为时间戳
time_now=time.mktime(time.strptime('2017-09-12 11:00:00','%Y-%m-%d %H:%M:%S'))
dif_time=time_now-true_time #对于1970年1月1日,两个时间相差多少秒struct_time=time.gmtime(dif_time) #转化为结构化时间
print('过去了%d年%d月%d天%d小时%d分钟%d秒'%(struct_time.tm_year-1970,struct_time.tm_mon-1,
                                       struct_time.tm_mday-1,struct_time.tm_hour,
                                       struct_time.tm_min,struct_time.tm_sec))

示例2
import time
timestamp_before = time.mktime(time.strptime('2015-11-20 20:20:10','%Y-%m-%d %H:%M:%S')) #将格式化时间转化为时间戳
time_now = time.time()  #当前时间的时间戳
sub_time = time_now - timestamp_before   #对于1970年1月1日两者相差多少秒
res = time.gmtime(sub_time) #转化为结构化的时间
print(res.tm_year-1970)   #相差多少年
print(res.tm_mon-1)  #相差多少月
print(res.tm_mday-1) #相差多少日

三、面向对象

#游戏工作
#人狗大战
#人 、 狗
#人角色:攻击力 生命值 名字 等级
#狗角色:攻击力 生命值 名字 品种
def person(attack,life_value,name,level):
    def atk(dog_d):
        print('%s 打了 %s' % (name, dog_d['name']))
        dog_d['life_value'] -= attack
    person_dic = {'attack':attack,
              'life_value':life_value,
              'name':name,
              'level':level,
                  'atk':atk}
    return person_dic

def dog(attack,life_value,name,level):
    def bite(person_d):
        print('%s 咬了 %s' % (name, person_d['name']))
        person_d['life_value'] -=attack
    dog_dic = {'attack':attack,
              'life_value':life_value,
              'name':name,
              'level':level,
               'bite':bite}
    return dog_dic

alex = person(100,1000,'alex',2) #alex等于person函数的返回值person_dic,是一个字典
egg = dog(200,2000,'egon',10) #egg等于dog函数的返回值dog_dic,也是一个字典
alex['atk'](egg) #调用atk(egg)这个函数,dog_d=egg
print(egg['life_value'])
# 面向对象编程
# 对象 - 角色
#   alex
#   egg
# 类 :具有相同属性和方法的一类事物就是类
#   person
#   dog
# 对象和类的关系
# 对象是一个实实在在存在的事物,是独一无二的
# 类 是一个抽象的大致规范了一类事物的范围

四、初始面向对象和类

#面向过程编程
    #固定的目的 固定的结果
    #从头到尾把要执行的步骤堆积出来就好了
#面向对象编程
    #有一个抽象的过程
    #上帝视角:结果不能预测
class Person:  #类名开头字母要大写,定义函数的时候要用小写字母,这样写规范,但不会出现语法错误
    rol = '人'         #数据属性、静态属性
    country = '中国'
    def attack(self):  #函数属性、动态属性、方法,函数定义在类里面叫方法,定义在类外面叫函数
        pass

# person 类 Person也是类名
print(callable(Person)) #查看是否可以被调用,发现类也可以被调用
print(Person())   #调用类就会返回一个对象,一个类名加上括号就会返回一个对象
print(Person.rol)  #.属性名
Person.rol = '人类' #修改属性的值
print(Person.__dict__)  #不可以平时直接用的,可以查看字典里是否有这个类
#类也有一个属于自己的名称空间:存储的是静态属性和动态属性
print(Person.attack) #结果为一个内存地址
print(Person.attack())  #报错:没有self参数

#类的定义
class 类名:
    静态属性 = '值'
    def 方法(self):
        pass
对象 = 类名()
对象.静态属性
对象.方法 #可以调用不能执行

#类加上括号的过程就是实例化
    #1.先创建了一个对象 self = {}
    #2.执行初始化方法__init__,同时把创建的对象扔到了__init__参数里
#类 对象(实例) 实例化
#类是我们自己抽象出来的
#实例化 对象 = 类名()
#类经过实例化就产生了对象/实例,对象也叫实例
#真正使用类中方法的不是类而是对象

#类:静态属性 动态属性
#类可以调用静态属性
#类可以查看动态属性 却必须要带上具体的对象参数才能调用动态属性
#对象:可以拥有自己的对象属性,并且可以调用类中的方法

# 对象可以调用类的方法
class Person:
    rol = '人'         #数据属性、静态属性、类属性
    country = '中国'
    def __init__(self,name,age,life_value): #初始化方法
        # self.__dict__['name'] = name
        self.name = name       #属性、对象属性
        self.theage = age
        self.life_value = life_value

    def attack(self):  #函数属性、动态属性、方法
        #self只是一个形式参数,可以叫其他名字,但正常没人会这样
        #self是水性杨花,哪个对象调这个方法,self就是那个对象
        print('attack方法被%s执行了'%self.name)

egg = Person('egon',18,1000) #调用Person类产生一个对象egg,egg对象就等于self,同时将参数'egon',18,1000传给__init__(self,name,age,life_value)初始化方法中的参数,
alex = Person('alex',38,2000) #产生一个alex对象
print(alex.name)
print(egg.life_value)
print(alex.theage)
print(alex.rol)
print(alex.country)
alex.country = '印度' #修改alex的country属性
print(alex.country)
print(egg.country)
print(alex.attack()) #对象alex可以调用类中的attack方法
总结:
#类有属于自己的命名空间
#对象也是
#类不可以调用对象的属性
#但是对象在寻找属性的时候,是先找自己名称空间的,找不到就找类名称空间里的
class Dog:
    def __init__(self,name,type):
        self.name = name
        self.dog_type = type
        self.life_value = 2000 #这里没有定义形参

    def bite(self,name):
        print('%s咬了%s'%(self.name,name))

旺财 = Dog('旺财','土狗') #类被调用产生一个对象定义为旺财,self就是这个对象旺财,'旺财','土狗'这两个参数传给__init__形参的name和type
print(旺财.name)
print(旺财.dog_type)
print(旺财.life_value)
旺财.bite('alex')  

#练习1
#创建一个类,实例化对象,需要做一个计数器,这个类每实例化一次,计数器加一
#所有的对象共享这个计数个数

class Dog:
    counter = 0
    def __init__(self,name,type):
        self.name = name
        self.dog_type = type
        self.life_value = 2000
        Dog.counter += 1
史努比 = Dog('史努比','大白狗') #实例化一个对象counter
史努比2 = Dog('史努比','大白狗')
print(史努比.counter)
print(史努比2.counter)

#练习2
#创建一个圆形类
#有一个属性:圆的半径
#提供两个方法:计算圆面积 、计算圆周长
from math import pi
class Circle:
    def __init__(self,r): #初始化方法
        self.r = r #类中的属性

    def area(self):   #类中的方法
        return self.r**2*pi

    def perimeter(self):
        return 2*pi*self.r

c1 = Circle(5) #定义一个对象,调用Circle这个类,将参数5从传给,初始化方法中的形参r,此时r=5
print(c1.area()) #调用类中的area方法,函数在类中叫做方法
print(c1.perimeter())  #调用类中的perimeter方法,打印的是方法的返回值
c2 = Circle(20)
print(c2.area())
print(c2.perimeter())

# 在终端输出如下信息
#
# 小明,10岁,男,上山去砍柴
# 小明,10岁,男,开车去东北
# 小明,10岁,男,最爱大保健
# 老李,90岁,男,上山去砍柴
# 老李,90岁,男,开车去东北
# 老李,90岁,男,最爱大保健
class Person:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    def shangshan(self): #定义一个方法
        print('%s,%s岁,%s,上山去砍柴'%(self.name,self.age,self.sex))
xiaoming = Person('小明',10,'男') #定义一个对象xiaoming,xiaoming=self
old_li = Person('老李',90,'男')
xiaoming.shangshan() #调用对象中的方法
old_li.shangshan()
总结:
#面向过程和面向对象编程
#思路1 从只关心某一个对象变成抽象规范了一类对象
#思路2 当多个函数都需要传递同样的多个参数的时候,考虑面向对象的思想

五、面向对象之间的交互

#人狗大战
class Dog:
    def __init__(self,name,type,aggr):
        self.name = name
        self.dog_type = type
        self.aggr = aggr
        self.life_value = 2000

    def bite(self,person_obj):  #self==egg,person_obj=alex
        #属性的变化
        print('%s咬了%s'%(self.name,person_obj.name))
        person_obj.life_value -= self.aggr

class Person:
    rol = '人'         #数据属性、静态属性、类属性
    country = '中国'
    def __init__(self,name,age,life_value): #初始化方法
        self.name = name       #属性、对象属性
        self.theage = age
        self.life_value = life_value
        self.aggr = 1

    def attack(self,dog_obj):  #函数属性、动态属性、方法
        print('%s攻击了%s'%(self.name,dog_obj.name))
        dog_obj.life_value -= self.aggr

alex = Person('alex',38,500)
egg = Dog('egon','二哈',20)
print(alex.life_value)
egg.bite(alex)   #掉用egg对象中的bite方法
print(alex.life_value)
print(egg.life_value)
alex.attack(egg) #alex对象调用attack方法,此时alex=self,egg=dog_obj
print(egg.life_value)
500
egon咬了alex
480
2000
alex攻击了egon
1999
总结:self水性杨花,谁调用她就等于谁

六、面向对象的组合

#组合 —— 面向对象的一种功能
#什么有什么的关系,人有出生年月,人和生日就是一种组合关系,两者是所属关系
#每个人都有生日,生日是由年月日组成
#一个类的对象做为另外一个类的属性来使用
class Birthday:
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day

class Person:
    def __init__(self,name):
        self.name = name
        # self.birthday = birth

alex_birth = Birthday(1968,1,1)
print(alex_birth.year)
alex = Person('alex')
alex.birth = alex_birth   #Birthday类的对象是Alex的birth属性,也就是创建一个新的alex的属性birth,等于Birthday类的对象
print(alex.birth.year)
#组合 - 两个类之间的事儿
#描述的是一种所属关系

#组合例二:
#人狗大战
#人
#武器:伤害、属性
#人有武器,人和武器之间就是一种组合关系
class Weapon:
    def __init__(self,aggr,name,money):
        self.aggr = aggr #攻击力
        self.name = name
        self.money = money

    def kill(self,dog_obj):
        print('%s武器暴击%s,伤害%s'%(self.name,dog_obj.name,self.aggr))
        dog_obj.life_value -= self.aggr

class Dog:
    def __init__(self, name, type, aggr):
        self.name = name
        self.dog_type = type
        self.aggr = aggr
        self.life_value = 2000

    def bite(self, person_obj):  # self==egg,person_obj=alex
        # 属性的变化
        print('%s咬了%s' % (self.name, person_obj.name))
        person_obj.life_value -= self.aggr

class Person:
    rol = '人'  # 数据属性、静态属性、类属性
    country = '中国'

    def __init__(self, name, age, life_value):  # 初始化方法
        self.name = name  # 属性、对象属性
        self.theage = age
        self.life_value = life_value
        self.aggr = 1

    def attack(self, dog_obj):  # 函数属性、动态属性、方法
        print('%s攻击了%s' % (self.name, dog_obj.name))
        dog_obj.life_value -= self.aggr

alex = Person('alex', 38, 500)
egg = Dog('egon', '二哈', 20)
alex.money = 2000
knife = Weapon(200,'杀猪刀',1900) #定义knife这个对象
if alex.money > knife.money:
    alex.money -= knife.money
    alex.weapon = knife #给alex创建一个新的属性等于knife这个对象,knife这个对象可以使用Weapon这个类中的属性和方法

print(egg.life_value)
alex.weapon.kill(egg)
print(egg.life_value)
2000
杀猪刀武器暴击egon,伤害200
1800
#对于任何数据类型的静态属性:他的修改操作尽量用类名
#尤其是对于不可变数据类型:修改必须用类名

七、面向对象的继承


image.png
#继承 —— 面向对象的三大特性之一
#想产生继承关系,必然是两个类以上
#继承表达的是一种 什么 是 什么的关系
#派生属性和派生方法是子类中有而父类中没有的
class Animal:
    def __init__(self,name,aggr,life_value):
        self.name = name
        self.aggr = aggr
        self.life_value = life_value
def func(self):
        print(self.name)

class Dog(Animal): #Dog类继承Animal类,在类名后面加括号,括号里面就是要继承的类
    def __init__(self,name,aggr,life_value,type):
        Animal.__init__(self,name,aggr,life_value) #继承父类init方法
#super().__init__(name,aggr,life_value) #也可以用此种方式调用父类的方法,但只适用于新式类

        self.dogtype = type    #再增加一条自己的属性,叫做派生属性
def bite(self): #派生方法
        Animal.func(self)    #继承父类的方法

class Person(Animal):
    def __init__(self,name,aggr,life_value,money):
        Animal.__init__(self,name,aggr,life_value)
        self.money = money
egg = Dog('egon',100,2000,'金毛') #实例化一个对象egg
egg.bite()#egg对象调用bite方法,就会调用父类的方法func(self)
alex = Person('alex',100,2000,2000) #实例化一个对象alex
print(egg.__dict__)
print(alex.__dict__)
alex.func() #因为alex对象中没有func()方法,就会调用父类Animal中的func()方法
打印结果:
egon
{'name': 'egon', 'aggr': 100, 'life_value': 2000, 'dogtype': '金毛'}
{'name': 'alex', 'aggr': 100, 'life_value': 2000, 'money': 2000}
alex
#Dog继承了Animal
#父类 :Animal
#子类 :Dog
#一个类可以有多个子类
#子类调用方法;先调自己的属性,自己没有就调用父类的属性
#写继承的过程:是先抽象,后继承,写代码的时候是先抽象后继承,也就思考的时候是先考虑子类后考虑父类
#派生:父类没有的属性和方法在子类中就是派生出来的


#多继承
#一个类可以拥有多个父类
class A: #A继承object 
    pass

class B: #B继承object
    pass

class C(A,B): #C继承A和B
    pass

print(A.__base__) #打印出A的父类,就是object
执行结果:
<class 'object'>

八、继承的原理和总结

#object  类祖宗
#如果一个类有指定的父类,那么他的父类就是被指定的那个
#如果一个类没有指定的父类,那么他的父类就是object
#凡是继承了object类的类都是新式类
#python3里所有的类都是新式类
#新式类调用父类的方法:
    # 指名道姓:父类名.方法名(self,aggr1...);   ---->经典类
    # super关键字:super().方法名(aggr1,...)    ----> 只适用于新式类

#教授类
    #属性 年龄 姓名
    #行为 讲课 写专利
#教师类:
    #属性 年龄 姓名
    #行为 讲课
#教授是教师
#教师是父类/基类
#教授是子类
class Teacher:
    def __init__(self,name,age,salary):
        self.name = name
        self.age = age
        self.salary = salary

    def teach(self):
        print('%s正在讲课'%self.name)

class Professor(Teacher): #继承父类Teacher
    def print_write(self):
        print('%s正在写专利'%self.name)

egon = Professor('egon',18,20000) #格式化一个对象,子类中没有init方法,就会调用父类的init方法
print(egon.__dict__)
print(egon.salary)
egon.teach() #调用teach()方法,子类中没有就会调用父类中的
egon.print_write() #调用print_write()方法,子类中有就调用子类中的
执行结果:
{'name': 'egon', 'age': 18, 'salary': 20000}
20000
egon正在讲课
egon正在写专利

当父类和子类中都有teach(self)方法时,先调用子类中的方法
class Teacher:
    def __init__(self,name,age,salary):
        self.name = name
        self.age = age
        self.salary = salary
        # self.teach()

    def teach(self):
        print('%s正在讲课'%self.name)

class Professor(Teacher):
    def print_write(self):
        print('%s正在写专利'%self.name)

    def teach(self):
        # super().teach()
        print('教授%s正在讲课'%self.name)

egon = Professor('egon',18,20000)
egon.teach()
执行结果:教授egon正在讲课

#新式类多继承, 执行父类的方法是 广度优先
image.png
class A:
    def func(self):
        print('A')

class B(A):
    def func(self):
        print('B')

class C(A):
    def func(self):
        print('C')

class D(B):pass
    # def func(self):
    #     print('D')

class E(C):
    def func(self):
        print('E')

class F(D,E):pass
    # def func(self):
    #     print('F')

f = F()#实例化一个对象f
f.func()
执行结果为:B
# 广度优先
print(F.mro()) #可以使用mro()方法,查看广度优先的顺序,只有新式类才有,python2中的经典类是没有这个方法的
[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
先找F,F里面没有,再找D,D里面也没有找B,因为不找B,下次就没有机会找B了,为什么不找A,因为通过E这条线路也可以找到A

九、Python2的继承


image.png
#coding:utf-8
class A:#pass
    def func(self):
        print('A')

class B(A):pass
    # def func(self):
    #     print('B')

class C(A):
    def func(self):
        print('C')

class D(B,C):pass

d = D()
d.func()
执行结果为:A,python2里面的经典类是深度优先

class A1(object): #python2中的新式类:广度优先
    pass
#经典类和新式类的区别
#1、关于基类 : 新式类默认继承object
#2、关于在子类中执行父类的方法:新式类有super,经典类只能用指名道姓
#3、关于多继承:新式类 广度优先(mro),经典类:深度优先
#在py3没有经典类;在py2里经典类和新式类共存

#关于继承:
#子类继承父类
#子类的对象调用方法,优先在子类中找,如果子类中有,就执行子类中的
#                                 如果子类中没有,就执行父类的
                                    #多个父类以广度优先为准
#关注self到底是哪个类的实例化
上一篇下一篇

猜你喜欢

热点阅读