面向过程与面向对象:

面向过程:核心是过程二字,过程即解决问题的步骤,就是先干什么在干什么,基于该思想写程序就好比设计一条流水线,是一种机械的思维模式

优点:复杂的过程流程化,进而简单化

缺点:扩展性差

 

面向对象:核心是对象二字,对象是特征和方法的结合体,基于该思想编写程序就好比在创建一个世界,世界是由一个个对象组成,是一种‘上帝式’的思维方式

优点:可扩展性强

缺点:编程复杂度高,容易出现过度设计的问题

 

对象是特征与技能的结合体,类就是一系列对象相似的特征与技能的结合体

在现实世界中:一定先有的一个个具体的存在对象,后总结出的类

在程序中:一定保证先定义类,后产生对象

 

定义一个类

类里边的代码在类定义阶段就会执行

class Student:
    school = 'oldboy'

    def learn(self):
        print('is learning')

    def choose_course(self):
        print('choose course')


print(Student.__dict__)  # 类下边的所有特征方法
print(Student.school)  # 数据属性
print(Student.learn)  # 函数属性

Student.country = 'China'   # 向类中添加属性(特征)

Student.school = 'Oldboy'   # 修改属性

del Student.country   # 删除属性

 

 

类的实例化

调用类的过程又称之为实例化

1 得到一个返回值,即对象,该对象是一个空对象stu1

2 Student.__init__(stu1,'李三炮','男','18')

class Student:
    school = 'oldboy'

    # stu1,'李三炮','男','18'
    def __init__(self,name,sex,age):   # 在调用类的时候会自动触发执行
        self.Name = name
        self.Sex = sex
        self.Age = age
    # stu1.Name = '李三炮'
    # stu1.Age = '男'
    # stu1.Sex = 18

    def learn(self):
        print('is learning')
    def choose_course(self):
        print('choose course')

stu1 = Student('李三炮','','18')
print(stu1.__dict__)
print(stu1.Name)
print(stu1.Sex)
print(stu1.Age)

# __init__ 方法内部可以有逻辑语句
# __init__ 不能有返回值(实例化①调用类的时候会返回一个空对象(这个时候已经返回了),②调用__init__方法为这个空对象初始化属性(这个时候在返回值就与第一步冲突了))

  

 

 属性查找

1 查找一个对象的属性顺序是:先查找自己的名称空间(__dict__),再找类的名称空间(__dict__)

2 类的数据属性是所有对象共享的,所有对象都指向同一个内存地址

3 类中定义的函数是绑定给对象使用,不同的对象有不同的绑定方法,绑定给谁,就应该由谁来调用,谁来调用就会把谁当做第一个参数传给对应的函数。

 

小练习

新建一个老师的类,实例化老男孩的老师,并且每一位老师都可以知道当前已经实例化老师的数量

class Teacher:
    school = 'oldboy'
    count = 0

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex
        Teacher.count += 1

    def teacher(self):
        print('我在教python')


taibai = Teacher('快老师', '28', '纯爷们')
egon = Teacher('瞎驴', '28', '钢铁直男')
print(taibai.count)
print(egon.count)

 

 

对象之间的交互

class Gailun:  # 定义一个名叫盖伦的类,可以实例化出玩家的盖伦
    camp = '德玛西亚'  # 每一个实例化出来的角色都属于德玛西亚

    def __init__(self, name, life, fight):  # 根据每个玩家喜好实例化出个性的盖伦
        self.name = name  # 给盖伦起名字
        self.life = life  # 生命值
        self.fight = fight  # 攻击力

    def attack(self, enemy):  # 盖伦攻击敌人的方法,得到的是敌人剩余的血量
        enemy.life -= self.fight


gl = Gailun('草丛伦', 1000, 200)  # 实例化一个草丛伦出来


class Ruiwen:
    camp = '诺克萨斯'

    def __init__(self, name, life, fight):
        self.name = name
        self.life = life
        self.fight = fight

    def attack(self, enemy):
        enemy.life -= self.fight


rw = Ruiwen('猛男雯雯', 300, 500)

gl.attack(rw)  # 盖伦对瑞文发起攻击,瑞文血量减少
print(rw.life)  # 瑞文剩余血量

 

 

面向对象的继承

是一种新建类的方式,新建的类成为子类,子类会遗传父类的属性,减少代码冗余

在python中,子类(派生类)可以继承一个或多个父类(基类,超类)

class Parent1:
    pass
class Parent2:
    pass
class Sub1(Parent1):  # 加括号 里边可以写要继承的父类
    pass
class Sub2(Parent1, Parent2):
    pass
print(Sub1.__bases__)  # 查看继承了哪些父类
print(Sub2.__bases__)
print(Parent1.__bases__)   # 默认继承了object类

 

在python2中类分为两种:

经典类:没有继承object类的类,以及该类的子类

新式类:继承了object类的类以及该类的子类

在python3中统一都为新式类

class Oldboypeople:
    school = 'oldboy'
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex

class Oldboyteacher(Oldboypeople):
    def teach(self):
        print('%s is teaching' %self.name)
t1 = Oldboyteacher('egon',18,'')
t1.teach()

class Oldboystudent(Oldboypeople):
    def learn(self):
        print('%s is learing' %self.name)
s1 = Oldboystudent('dw',22,'')
s1.learn()

继承之深度优先、广度优先

python中一个类可以同时继承多个父类,如A(B,C,D)

如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性

如果继承关系为菱形结构,那么属性的查找方式有两种,分别是:深度优先和广度优先

经典类:深度优先

新式类:广度优先

 

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

子类调用父类的方法有两种 

方法一:指名道姓,即父类名.父类方法()   这种方式不依赖与继承

#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'

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):
        Vehicle.__init__(self,name,speed,load,power)
        self.line=line

    def run(self):
        print('地铁%s号线欢迎您' %self.line)
        Vehicle.run(self)

line13=Subway('中国地铁','180m/s','1000人/箱','',13)
line13.run()
View Code

 

方法二: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()
View Code

 

 多态和多态性

多态:同一种事物的多种形态

多态性:在不考虑对象的具体类型的情况下直接使用对象

组合

 一种减少代码冗余的方式,可以实现对象之间的交互 

class OldboyPeople:
    school = 'Oldboy'
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    def tell_info(self):
        print('<名字:{} 年龄:{}  性别{}>'.format(self.name,self.age,self.sex))

class OldboyStutent(OldboyPeople):
    def __init__(self,name,age,sex,course,stu_id,year,mon,day):
        OldboyPeople.__init__(self,name,age,sex)
        self.course = course
        self.stu_id = stu_id

        self.year = year
        self.mon = mon
        self.day = day
    def tell_info(self):
        print('我是学生 ')
        OldboyPeople.tell_info(self)
    def tell_birth(self):
        print("出生日期是{}年{}月{}日".format(self.year,self.mon,self.day))


class OldboyTeacher(OldboyPeople):
    def __init__(self,name,age,sex,course,stu_id,year,mon,day):
        OldboyPeople.__init__(self,name,age,sex)
        self.course = course
        self.stu_id = stu_id

        self.year = year
        self.mon = mon
        self.day = day
    def tell_info(self):
        print('我是老师')
        OldboyPeople.tell_info(self)
    def tell_birth(self):
        print("出生日期是{}年{}月{}日".format(self.year,self.mon,self.day))

stu1 = OldboyStutent('田建宇',18,'','linux',10,1994,10,10)
stu1.tell_info()
stu1.tell_birth()
tea1 = OldboyTeacher('老白',20,'','python',10,1988,12,20)
tea1.tell_info()
tea1.tell_birth()

# 上述代码 可以查看每个学生和老师的生日,每个对象都有自己的生日,但是这样会造成代码冗余
# 采用组合的方法可以减少代码冗余 
View Code
class OldboyPeople:
    school = 'Oldboy'
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    def tell_info(self):
        print('<名字:{} 年龄:{}  性别{}>'.format(self.name,self.age,self.sex))

class OldboyStutent(OldboyPeople):
    def __init__(self,name,age,sex,course,stu_id):
        OldboyPeople.__init__(self,name,age,sex)
        self.course = course
        self.stu_id = stu_id
    def tell_info(self):
        print('我是学生 ')
        OldboyPeople.tell_info(self)


class OldboyTeacher(OldboyPeople):
    def __init__(self,name,age,sex,course,stu_id):
        OldboyPeople.__init__(self,name,age,sex)
        self.course = course
        self.stu_id = stu_id
    def tell_info(self):
        print('我是老师')
        OldboyPeople.tell_info(self)

class Birth:
    def __init__(self,year,mon,day):
        self.year = year
        self.mon = mon
        self.day = day
    def tell_birth(self):
        print('出生日期是:{}年{}月{}日'.format(self.year,self.mon,self.day))

stu1_birth = Birth(1994,8,8)
tea1_birth = Birth(1988,7,9)
# stu1_birth.tell_birth()
# tea1_birth.tell_birth()

stu1 = OldboyStutent('田建宇',18,'','linux',10)
stu1.birth = stu1_birth
stu1.tell_info()
stu1.birth.tell_birth()

tea1 = OldboyTeacher('老白',20,'','python',10)
tea1.tell_info()
tea1.birth = tea1_birth
tea1.birth.tell_birth()

# 因为出生日期年月日是冗余的代码,并且后边的对象都用的到,所以定义一个年月日类,查看生日
# 已经实例化的学生和老师的对象与生日类实例出来的对象绑定,就可以使用生日类里边的方法
View Code
# 对象的组合 实现对象之间的关联(学生选择课程)
class OldboyPeople:
    school = 'Oldboy'

    def __init__(self, name, age, sex, date_obj):
        self.name = name
        self.age = age
        self.sex = sex
        self.birth = date_obj

    def tell_info(self):
        print('<名字:%s 年龄:%s 性别:%s>' % (self.name, self.age, self.sex))


class OldboyStudent(OldboyPeople):
    def __init__(self, name, age, sex, stu_id, date_obj):
        OldboyPeople.__init__(self, name, age, sex, date_obj)
        self.courses = []
        self.stu_id = stu_id

    def learn(self):
        print('%s is learning' % self.name)

    def tell_info(self):
        print('我是学生:', end='')
        OldboyPeople.tell_info(self)


class OldboyTeacher(OldboyPeople):
    def __init__(self, name, age, sex, level, salary, date_obj):
        OldboyPeople.__init__(self, name, age, sex, date_obj)
        self.level = level
        self.salary = salary
        self.courses = []

    def teach(self):
        print('%s is teaching' % self.name)

    def tell_info(self):
        print('我是老师:', end='')
        OldboyPeople.tell_info(self)


class OldboySale(OldboyPeople):
    def __init__(self, name, age, sex, kpi, date_obj):
        OldboyPeople.__init__(self, name, age, sex, date_obj)
        self.kpi = kpi

    def tell_info(self):
        print('我是销售: ', end='')
        OldboyPeople.tell_info(self)


class Date:
    def __init__(self, year, mon, day):
        self.year = year
        self.mon = mon
        self.day = day

    def tell_birth(self):
        print('出生日期是:<%s-%s-%s>' % (self.year, self.mon, self.day))


class Course:
    def __init__(self, name, price, period):
        self.name = name
        self.price = price
        self.period = period

    def tell_info(self):
        print('课程详细信息:<%s,%s,%s>' % (self.name, self.price, self.period))


Python = Course('python自动化养猪', 3000, '3mon')
Linux = Course('大数据分析-linux', 3000, '3mon')
date_obj = Date(1993, 3, 13)

stu1 = OldboyStudent('田建宇', 28, 'female', 1, date_obj)

stu1.courses.append(Python)
stu1.courses.append(Linux)

for course in stu1.courses:
    print(course.name)
View Code

 

抽象类

 

1 什么是抽象类

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

2 为什么要有抽象类

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

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

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

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

3. 在python中实现抽象类

#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
#一切皆文件
import abc #利用abc模块实现抽象类

class All_file(metaclass=abc.ABCMeta):
    all_type='file'
    @abc.abstractmethod #定义抽象方法,无需实现功能
    def read(self):
        '子类必须定义读功能'
        pass

    @abc.abstractmethod #定义抽象方法,无需实现功能
    def write(self):
        '子类必须定义写功能'
        pass

# class Txt(All_file):
#     pass
#
# t1=Txt() #报错,子类没有定义抽象方法

class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('文本数据的读取方法')

    def write(self):
        print('文本数据的读取方法')

class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('硬盘数据的读取方法')

    def write(self):
        print('硬盘数据的读取方法')

class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('进程数据的读取方法')

    def write(self):
        print('进程数据的读取方法')

wenbenwenjian=Txt()

yingpanwenjian=Sata()

jinchengwenjian=Process()

#这样大家都是被归一化了,也就是一切皆文件的思想
wenbenwenjian.read()
yingpanwenjian.write()
jinchengwenjian.read()

print(wenbenwenjian.all_type)
print(yingpanwenjian.all_type)
print(jinchengwenjian.all_type)
View Code

4. 抽象类与接口

抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。

抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计  

 

isinstance 和 issubclass

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

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

反射:用字符串类型的名字去操作变量

name = 1

eval(print(name))# 用eval会产生安全隐患

用反射的话没有安全问题,