面向对象总结:


面向对象编程:

1.面向对象编程与面向过程编程

面向过程:

​ 核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么…基于该思想编写程序就好比在设计一条流水线

​ 优点:复杂的问题流程化,进而简单化

​ 缺点:可扩展性差

面向对象:

​ 核心是对象二字,对象指的是特征与技能的结合体,基于该思想编写程序就好比在创造一个世界,程序员就是这个世界的上帝,在上帝眼里一切事物均是对象

​ 优点:可扩展性性高

​ 缺点:编程的复杂度相对于面向过程要高

2.定义类

类就是一系列属性和方法的结合体


class OldboyStudent:
 school='oldboy'

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

 def choose_course(self,course):
     pass
# 类你也可以把它理解成是一个容器,你往里面存了很多名字,
# 存不是我们首要的目的,取才是!
# 如果你要访问类里面的名字
# print(OldBoy.__dict__)
# print(OldBoy.__dict__['school'])
# print(OldBoy.school) python给你提供了访问属性的简便操作 统一采用句点符
# 只要是句点符操作的左边一定是一个容器(名称空间) 比如: 模块,类,对象

3.实例化对象

调用init完成实例化 self.name = name,这种语法不是在获取属性而是在往对象里面新增属性


obj = OldBoy('jason')
print(obj.__dict__)  # 查看对象独有的属性
print(obj.school)  # 还可以查看类里面共有的属性
  • 产生一个空对象

  • 调用init实例化(将空对象和传入的参数一并传给init)

  • 将实例化好的对象返回出来

4.属性查找

先从对象自己的名称空间找,如果没有则去类名称空间中找,如果还没有则去父类中找...

补充:


# python中一切皆对象
l = list([1,2,3])
obj1 = OldBoy('egon')
print(type(l))
print(type(obj1))
# 你定义一个类 可不可以认为就是定义了一个新的数据结构
# 你定义一个列表之后,是不是配套的有一堆相应的操作该列表的方法?append pop ...
# 那对象刚好也有对应的绑定方法

5.绑定给对象的方法

在类中定义的函数,叫方法,类可以调用但是需要手动传入self

该方法在没有被任何装饰器修饰的前提下,其实就是给对象用的而且是绑定给对象的绑定方法

绑定特点:谁来调就会将谁当作第一个参数自动传入

6.封装

1、什么是封装 “装”的意思就往一个容器中放入一系列属性 “封”的意思就是藏起来,在内部可以看到,但对外部是隐藏的

2、为什么要用封装

​ 将复杂的操作封装成简单的接口,并严格控制接口的调用过程

3、如何用封装 但凡是双下划线开头(不能是双下划线结尾)的属性,会被隐藏起来,类内部可以直接使用 而类外部无法直接使用,即封装是对外不对内的

这种隐藏的特点:1、只是一种语法上的变形,会将__开头的属性变形为:_自己的类名__属性名(__n=1 #_Foo__n=1)2、该变形只在类定义阶段发生一次,在类定义阶段之后新增的__开头的属性并不会发生变形3、隐藏是对外不对内的4、在继承中,父类如果不想让子类覆盖自己的同名方法,可以将方法定义为私有的


class Teacher:
   def __init__(self,name,age):
       # self.__name=name
       # self.__age=age
       self.set_info(name,age)

   def tell_info(self):
       print('姓名:%s,年龄:%s' %(self.__name,self.__age))
       
   def set_info(self,name,age):
       if not isinstance(name,str):
           raise TypeError('姓名必须是字符串类型')
       if not isinstance(age,int):
           raise TypeError('年龄必须是整型')
       self.__name=name
       self.__age=age

t=Teacher('egon',18)
t.tell_info()

t.set_info('egon',19)
t.tell_info()

 

 

1.继承与派生

1.什么是继承

继承就是一种新建类的方式,新建的类称为子类或者派生类,被继承的类称之为父类或者基类或者超类

子类会继承所有父类的属性和方法,即可以直接使用这些属性和方法

2.为什么要用继承

减少代码冗余

3.如何使用


class Parent1:
 pass
class Parent2:
 pass
class Son1(parent1):
 pass
# python支持多继承,一个类可以有多个父类,但在java中只能有一个
class Son2(parent1,parent2):
 pass
print(Son1.__bases__)  # 查看当前类的所有的基类
print(Son2.__bases__)  

# 那你是否会好奇想看看我们定义的Parent类它有没有偷偷摸摸的继承谁呢?
print(Parent1.__bases__)
print(Parent2.__bases__)

# 切换python解释器3.x >>> 2.x得出一个结论
"""
在python3中,如果没有显示地继承任何类,那默认继承object类
在python2中,如果没有显示地继承任何类,也不会继承object类


在python中类分为两种:
      新式类:
          但凡继承object的类,或者该类的子类都是新式类
          >>>:在python3中所有的类都是新式类
      经典类
          没有继承object类,以及该类的子类都是经典类
          也就意味着经典类和新式类这对儿概念只在python2中有
          python3中只有新式类
"""

4.基于继承减少代码冗余的案例+派生/衍生

对象与对象之间总结相似的特征与技能得到类类与类之间总结相似的属性和特征得到父类

http://www.cnblogs.com/linhaifeng/articles/7340153.html

# 代码实例
import pickle

class OldboyStudent:
   school = 'oldboy'

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

   def choice_course(self):
       print('%s is choosing course'%self.name)

   def save(self):
       with open(self.name,'wb') as f:
           pickle.dump(self,f)

class OldboyTeacher:
   school = 'oldboy'

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

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

   def save(self):
       with open(self.name,'wb') as f:
           pickle.dump(self,f)
stu = OldboyStudent('alex',30,'male')
stu.save()

tea = OldboyTeacher('egon',18,'male',10)
tea.save()

# 回过头来看,上面的代码是否存在相似的部分。我们刚好学过解决类之间解决代码冗余的方式
class OldboyPeople:
   school = 'oldboy'

   def save(self):
       with open(self.name, 'wb') as f:
           pickle.dump(self, f)
# 初步继承类抽取,思考继承之后对象查找属性和方法的顺序
stu.save()
stu.school

# 刚刚只是讲属性和方法抽成了父类,但是init里面也有重复的代码,应该也可以抽取
class OldboyPeople:
   school = 'oldboy'
   def __init__(self,name,age,sex):
       self.name = name
       self.age = age
       self.sex = sex

   def save(self):
       with open(self.name, 'wb') as f:
           pickle.dump(self, f)
# 先不考虑老师和学生init中不同的,先全部继承这个父类统一的init,发现也可以使用到父类的init

# 派生概念
# 在子类能够使用父类所有的属性和方法的同时,自身还有一些额外的属性和方法
# 小思考:如果派生的属性和方法恰巧和父类的一样,那在查找属性和方法的时候先找到谁呢? >>> 还是按查找顺序来

# 再回过头来看老师的init中有额外的level参数,不应该在父类中添加默认参数,只能自己重写init方法,但是又有重复的代码出现
   def __init__(self,name,age,sex,level):
       OldboyPeople.__init__(self,name,age,sex)
       self.level = level
"""
在子类派生出的新方法中重用父类的方法
方式1:指名道姓访问,与继承没有任何关系
OldboyPeople.__init__(self,name,age,sex)
言外之意还有一种跟继承有关系的能够重用父类的方法的方式,先不着急说
"""

5.继承原理

刚刚我们一直在讨论的是单继承下属性查找的顺序,那如果是多继承情况呢?

单继承测试


class Foo:
   def f1(self):
       print('Foo.f1')

   def f2(self): #self=obj
       print('Foo.f2')
       self.f1() #obj.f1()

class Bar(Foo):
   def f1(self):
       print('Bar.f1')


obj=Bar()
obj.f2()

多继承


# F(A,B,C) 无论是新式类还是经典类,都是从左往右挨个走到底 画图 切换python版本演示,记得加文件头coding:utf-8
# 2、多继承的属性查找“:对象自己-》对象的类-》从左往右一个一个的分支找下去
class D:
   # def test(self):
   #     print('D')
   pass
class E:
   def test(self):
       print('E')

class F:
   def test(self):
       print('F')

class A(D):
   # def test(self):
   #     print('A')
   pass

class B(E):
   def test(self):
       print('B')

class C(F):
   def test(self):
       print('C')

class G(A,B,C):
   # def test(self):
   #     print('G')
   pass

obj=G()
obj.test()

如果是菱型继承的话就不一样了(不考虑object)>>>广度优先!


#3、新式类:广度优先
class A(object):
   def test(self):
       print('from A')
class B(A):
   # def test(self):
   #     print('from B')
   pass
class C(A):
   # def test(self):
   #     print('from C')
   pass
class D(B):
   # def test(self):
   #     print('from D')
   pass
class E(C):
   # def test(self):
   #     print('from E')
   pass
class F(D,E):
   # def test(self):
   #     print('from F')
   pass

obj=F()
print(F.mro())  # 查找属性的顺序遵循mro列表(只有新式类中才有mro方法)
obj.test()

回过头再来看通过继承关系调用父类的方法


# 方式二:super(自己的类名,self).父类中的方法名()
# 调用super会得到一个特殊的对象,该对象是专门用来引用父类中的方法的,
# 具体的:该对象会严格按照当前类的MRO列表从当前类的父类中依次查找属性,即这种方式是严格依赖于继承的
# ps:在python3中可以简写为super()
class OldboyPeople:
   def __init__(self,name,age,sex):
       self.name=name
       self.age=age
       self.sex=sex

class OldboyTeacher(OldboyPeople):
   def __init__(self,name,age,sex,level):
       # OldboyPeople.__init__(self,name,age,sex)
       super(OldboyTeacher,self).__init__(name,age,sex)
       self.level=level

tea1=OldboyTeacher('egon',18,'male',10)
print(tea1.name,tea1.level)


class A:
   def f1(self):
       print('A')
       super().f2() # super()会基于当前所在的查找位置继续往后查找
   def f2(self):
       print('A')
class B:
   def f2(self):
       print('B')
class C(A,B):
   def f2(self):
       print('C')

obj=C()
print(C.mro())
obj.f1()

实际工作中要谨慎使用多继承,编程是解耦合,而继承则是强耦合

 

 

6.多态与多态性

1.什么是多态

​ 同一种事物的多种形态(动物:人,猫,狗)

2.为何要用多态

​ 多态性:指的是可以在不用考虑对象具体类型的前提下,直接调用对象的方法

3.如何使用多态


class Animal:
   def talk(self):
       pass

class People(Animal):
   def talk(self):
       print('say hello')

class Dog(Animal):
   def talk(self):
       print('汪汪汪')

class Pig(Animal):
   def talk(self):
       print('哼哼哼')

peo1=People()
dog1=Dog()
pig1=Pig()

# 不用考虑对象具体类型的前提下,直接调用对象的方法
peo1.talk()
dog1.talk()
pig1.talk()
"""
再来想车是不是有很多牌子,你去学车需要说专门学哪个牌子的车的驾驶方式吗?
"""
# 来你之前也一直在用多态性:不用考虑对象具体类型的前提下,直接调用对象的方法
l=list([1,2,3])
s=str('hello')
t=tuple((4,5,6))

l.__len__()
s.__len__()
t.__len__()  # 我不需要考虑这三个具体是什么类型,只要是容器类型就都能调用len这个方法

# 再来看多态性能够实现的条件是什么?父类有的方法名子类也必须叫这个方法才行
class Animal:
   def talk(self):
       pass

class People(Animal):
   def jiao(self):
       print('say hello')

class Dog(Animal):
   def han(self):
       print('汪汪汪')

class Pig(Animal):
   def hou(self):
       print('哼哼哼')
# 多态性能实现的条件就是父类给子类定义了一个标准,动物都必须会叫,并且叫的方法都必须是talk
# 但是你现在能约束我说子类必须叫这个方法吗?

# 那有没有一种情况能够做到说子类必须按照父类定义的标准
import abc
class Animal(metaclass=abc.ABCMeta): # 父类存在的意义就是用来定义规范
   @abc.abstractmethod
   def talk(self):
       pass

# Animal() # 抽象基类不能被实例化!!!
class People(Animal):
   def jiao(self):
       print('say hello')
class Dog(Animal):
   def han(self):
       print('汪汪汪')
class Pig(Animal):
   def hou(self):
       print('哼哼哼')
# 上面三个类 一实例化都会报错

# 但是python推崇的是自由,简约并不希望限制程序员的开发
# 鸭子类型:只要你长得像鸭子,说话像鸭子,那你就是鸭子!
class People:
   def talk(self):
       print('say hello')
class Dog:
   def talk(self):
       print('汪汪汪')
class Pig:
   def talk(self):
       print('哼哼哼')

# 再来看linux中:一切皆文件!
class Disk:
   def read(self):
       print('disk read')
   def write(self):
       print('disk write')
class Process:
   def read(self):
       print('process read')
   def write(self):
       print('processes write')
class Memory:
   def read(self):
       print('memory read')
   def write(self):
       print('memory write')

7.类中的装饰器


# property
# 人体的BMI指数
"""
成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32
  体质指数(BMI)=体重(kg)/ 身高^2(m)
  EX:70kg÷(1.75×1.75)=22.86
"""
class People:
   def __init__(self,name,height,weight):
       self.name=name
       self.height=height
       self.weight=weight

   @property
   def bmi(self):
       return self.weight / (self.height ** 2)


egon=People('egon',1.80,75)
egon.height=1.82
# print(egon.bmi())

print(egon.bmi)



# 了解
class People:
   def __init__(self,name):
       self.__name=name

   @property
   def name(self):
       return self.__name

   @name.setter
   def name(self,val):
       # print('=====>准备修改名字的值:',val)
       if type(val) is not str:
           raise TypeError('名字的值必须为str类型')
       self.__name=val

   @name.deleter
   def name(self):
       # del self.__name
       print('不让删啊老铁')

# classmethod

# staticmethod

8.反射

通过字符串来获取类或对象的属性或方法


#1、反射:指的是通过字符串来操作类或者对象的属性
class People:
   country='China'
   def __init__(self,name):
       self.name=name


obj=People('egon')


#涉及四个内置函数
# hasattr
print('country' in People.__dict__)
print(hasattr(People,'country'))

# getattr
print(People.__dict__['country'])
print(getattr(People,'country'))
print(getattr(People,'country1111',None))

# setattr
People.__dict__['x']=111
print(People.x)
setattr(People,'x',111)
print(People.__dict__)

# delattr
delattr(People,'country')
print(People.__dict__)


# 应用
class Ftp:
   def get(self):
       print('get...')

   def put(self):
       print('put...')

   def auth(self):
       print('auth...')

   def run(self):
       while True:
           cmd=input('>>: ').strip() #cmd='get'
           if hasattr(self,cmd):
               method=getattr(self,cmd)
               method()
           else:
               print('输入的方法不存在')
obj=Ftp()
obj.run()

9.内置方法


# __str__
# __getattr__ 注意是对象获取自己没有的属性时才会触发(属性和方法)
# __setattr__

10.元类

https://www.cnblogs.com/Dominic-Ji/p/10520256.html

异常处理

1.什么是异常?

异常是错误发生的信号,程序一旦出错,如果程序中还没有相应的处理机制,那么该错误就会产生一个异常抛出来,程序的运行也随之终止


print('start')
x = 1
y = 2
if
print('end')  # 程序一句也不会运行直接报错,运行前会先检测语法

异常分为三部分: 异常的类型(一个个的类) 异常的内容、提示信息 异常的追踪/定位信息信息

异常的分类:

  • 语法上的错误(如上例)

  • 逻辑上的错误


    # NameError
    age = 12
    a
    # IndexError
    l = [1,2,3]
    l[123]
    # KeyError
    d = {'name':'jason'}
    d['password']

2 为何要进行异常处理

​ 增强程序的健壮性

3 如何进行异常处理


try
...
except
...
#针对逻辑上的异常才应该使用try...except去捕捉异常进行处理
#1、异常的单分支(单个except)
#2、异常的多分支(多个except)
#3、万能异常:Exception,可以匹配所有种类的异常(挨个注释挨个尝试)
try:
    age
    l=[1,2,3]
    l[100]
    d={'x':1}
    d['y']
    import os
    os.xxx
except Exception as e: # as语法将错误信息赋值给变量e
    print('万能异常')
print(e)  
print('其他代码')
#4、多分支+Exception,注意Exception一定要放到except 其他异常的的后面
#5、try...else,else会在被检测的代码块没有异常发生的情况下执行, else一定要与except连用,并且一定要放到多个except后面
#6、try...finally,finally的代码,无论被检测的代码有无异常,都会执行,通常在finally内做一些回收资源的事情
try:
f = open('a.txt','w',encoding='utf-8')
f.read()
finally:
f.close()
print('other...')
#7、主动触发异常raise 异常类型(’异常的内容‘)
# 应用于程序中自定义某种法则,一旦不遵循则会像抛出语法异常一样,终止程序的运行
class People:
def __init__(self,name):
  if not isinstance(name,str):
    raise TypeError('%s must be str type'%name)
    self.name = name

#8、断言
l = [1,2,3]
assert len(l) > 0

#9 自定义异常
class MyError(BaseException):
    def __init__(self,msg):
        super().__init__()
        self.msg=msg
    def __str__(self):
        return '<%s>' %self.msg

raise MyError('我自己定义的异常') # 主动抛出异常其实就是将异常类的对象打印出来,会走__str__方法

 

posted @ 2019-05-27 21:35  同济小孙  阅读(201)  评论(0编辑  收藏  举报