Rainie999 发表于 2018-8-7 11:10:10

VII python面向对象

  VII python面向对象
  以下概念及举例均在python3.*中实现;
  1、
  面向过程&面向对象:
  op
  oo
  产生背景
  科学计算为目标的必然产物
  软件应用领域的扩张和系统膨胀之后应运而生
  编程方法
  自顶向下
  自底向上
  代码主体结构
  程序=数据(变量)+算法(函数|过程)
  程序=对象+交互
  数据操作主体
  由函数|过程进行加工与展现
  在对象的方法中加工与展现
  模拟方法
  通过函数|过程操纵表现世界的数据与状态
  把世界描绘成具有主动性的对象之间交互
  编程思维
  搞清处理数据的步骤
  面向对象分析
  运行效率
  较高
  较低

  鸡兔同笼:
  先假设全部为鸡,计算出腿数;
  算出腿数量差;
  得出鸡数量;
  计算另一动物的数量;
  注:
  自猜想的数据类型;
  变量名为大写就认为是常量;
  大小写敏感;
  2、
  对象编程体验:
  自动运行小游戏模拟:
  在一维的地图上,有一只虫子和一只蚂蚁,每一次它们都走过一个-3,-2,2,3随机单位的距离(选定走法),若达到地图边界则放弃移动,当蚂蚁虫子处于同一位置时,蚂蚁吃掉虫子,程序结束;
  op:
  虫子的初始位置;
  蚂蚁的初始位置;
  进入循环(条件为蚂蚁和虫子不在同一位置);
  依照规则,蚂蚁和虫子移动位置;
  直到蚂蚁和虫子走到同一位置,程序结束;
  oo:
  游戏中的对象有:地图、虫子、蚂蚁;
  地图是一维的,只需要记录虫子和蚂蚁的位置;
  蚂蚁和虫子知道自己的位置;
  蚂蚁和虫子能按规则移动;
  定义地图、蚂蚁、虫子三个类;
  主程序中实例化它们,并通过对象间的交互来完成游戏的模拟;
  3、
  面向对象入门:
  理解对象:
  对象可以指自然界中的任何事物;
  计算机为解决某个领域问题所使用的事物(自然界中的事物的模型化);
  事物(对象)只有自身的特征或能力;
  计算机中的对象具有解决问题所需的特征或能力;
  对象优越性:
  封装(将模型的特征和能力打包在一起;模型的改变由模型自身来完成,就像自然界的事物一样;隐藏模型的细节,外界只能使用它,而不必(不能)改变它);
  继承(符合自然界的分类规律;快速的代码重用);
  多态(子类可以继承父类的特征与能力,还可通过自定义来修改其特征与能力;duck typing鸭子类型);
  组合(一个模型可以由其它的模型组成);
  注:
  duck typing来源于james whitcomb riley提出的鸭子测试:
  当看到一只鸟走起来像鸭子,叫起来像鸭子,游泳起来像鸭子,那么这只鸟就可被称为鸭子;
  在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的;
  在有的语言中必须用接口来实现;
  4、
  定义和使用类:
  最简类定义;
  类实例化;
  类与实例之间的关系(
  定义类就是建立模型;
  实例化就是建立真实事物;
  例如:模具、印章);
  有特征和能力的类(
  特征|属性,是类自身包含或知道的数据;
  能力,以方法体现,是类具有能动性的体现);
  实例化步骤(
  调用__new__()方法创建实例,__new__()方法自动从object继承;
  调用__init__()方法对其初始化,__init__()方法在类中定义);
  添加类说明docstring(
  紧跟在类名之后,以三引号包围的字符串;
  查看类说明,类名.__doc__或help(类名));
  新式类与经典类(
  python2.*版本,默认是经典类,继承object为新式类;
  python3.*版本,统一为新式类,不用继承object;
  区别:经典类继承为深度优先;新式类继承为广度优先)
  描述对象的特征(实例属性;类属性;私有属性;特殊属性):
  实例属性:
  类被实例化以后才具有的属性;
  一般在__init__()方法中创建并初始化;
  直接使用即定义,self.属性名;
  引用方法,self.属性名;
  self用来代表类的实例;
  类外用实例名.属性名方式定义和引用;
  相同类的不同实例,其实例属性是不相关的;
  一般不建议在__init__()方法之外创建和初始化实例属性;
  一般不推荐类外定义和修改,修改可以单独定义方法;

  In :>  ....:   def __init__(self):
  ....:         self.a = 0
  ....:         self.b = 10
  ....:   def info(self):
  ....:         print 'a:',self.a,'b:',self.b
  ....:   def define_c(self):
  ....:         self.c = 20
  In : tc=TestClass()
  In : tc.info()
  a: 0 b: 10
  In : tc.color='red'   #类外用
  In : print tc.color
  red
  In : tca = TestClass()
  In : tcb = TestClass()
  In : tca.a = 100
  In : tcb.a = 200
  In : tca.info()
  a: 100 b: 10
  In : tcb.info()
  a: 200 b: 10
  In : tc = TestClass()
  In : tc.define_c()
  In : print tc.c
  20
  类属性:
  类定义后就存在,而且不需要实例化;
  类属性使得相同类的不同实例共同持有相同变量;

  In :>  ....:   cssa = 'class-attribute'
  ....:   def __init__(self):
  ....:         self.a = 0
  ....:         self.b = 10
  ....:   def info(self):
  ....:         print 'a:',self.a,'b:',self.b,TestCss.cssa
  In : tc = TestCss()
  In : tc.info()

  a: 0 b: 10>  In : tc = TestCss()
  In : tc.info()

  a: 0 b: 10>  In : tca = TestCss()
  In : tca.info()

  a: 0 b: 10>  In : TestCss.cssa = 0   #类外修改其属性
  In : tc.info()
  a: 0 b: 10 0
  In : tca.info()
  a: 0 b: 10 0
  私有属性:
  不提供限制属性访问的关键字(无法限制类的各种属性在类外直接访问);
  使用__开头的变量名加以标示,只有类对象自己能访问(限制性的);
  使用_开头的变量名加以标示,只有类对象及其子类能访问(非强制性),对程序员来说,是标示性的而非限制性的,在类外还可以修改和查看;

  In :>  ....:   def __init__(self):
  ....:         self.__a = 0   #在此处初始化时实例属性就被隐藏了
  ....:   def info(self):
  ....:         print self.__a
  ....:
  In : a = TestPri()
  In : a.info()
  0
  In : a.__a = 3   #私有属性不能在外部进行修改,此处相当于重新定义了一个实例属性,与类中定义的self.__a = 0是不一样的
  In : a.info()
  0
  In : print a.__a
  3

  In :>  ....:   def __init__(self):
  ....:         self._a = 10
  ....:   def info(self):
  ....:         print self._a
  ....:
  In : a = TestPri()
  In : a.info()
  10
  In : a._a = 30   #在类外可修改和查看
  In : a.info()
  30
  In : print a._a
  30
  特殊属性:
  __doc__
  __name__   #类名称
  __dict__   #实例属性的所有属性名及值组成的dictionary
  __module__   #该类所在的模块名
  __base__   #该类的父类
  5、让对象具有能动性:
  类的方法的定义:
  def fun_name(self,…):
  pass
  其中,self表示类的实例,在调用方法时由系统自动提供;
  方法定义时必须指明self参数;
  类的方法的调用:
  与普通函数调用类似,即使参数列表为空也不能省略();
  在类的内部调用,self.方法名(参数列表);
  在类的外部调用,实例名.方法名(参数列表);
  以上两种调用方法,提供的参数列表中都不用包括self;
  类内方法相互调用:
  在一个类的内部,方法之间是可以相互调用的;
  调用方法,self.方法名(参数列表);
  构造方法及其作用:
  构造方法即使用__init__()方法;
  构造方法的作用是在类实例化时初始化实例;
  __init__()方法就是类实例化的第二步自动调用的函数,其方法名是固定的,但其参数同普通方法一样,至少要带self参数;
  初始化实例包括,定义和初始化实例属性,或调用类的一些方法;
  构造方法可带有除self外的其它各种参数,关键字参数、默认参数、用tuple收集参数、用字典收集关键字参数等,可以达到在实例化类时,为相应的属性传入指定的值;
  注:
  定义类的实例方法,和实例属性一样,必须进行类实例化之后,才能存在和调用它们;
  python3.*版本,print是函数;python2.*,print是语句;
  6、深入类的属性:
  同名的类属性与实例属性:
  实例名.属性名,优先引用实例属性;
  类名.属性名,只能引用类属性;
  属性访问的特殊方法(反射,或叫自省):
  用字符串来操作类的属性|方法的方式;
  主要工具函数(在编写框架或特殊项目时才用到):
  hasattr(obj_name,'属性名')
  setattr(obj_name,'属性名',值)
  getattr(obj_name,'属性名')

  In :>  ....:   a = 0
  ....:   def __init__(self):
  ....:         self.a = 10
  ....:         self.b = 20
  ....:
  In : a = TestClass()
  In : a.a
  Out: 10
  In : a.b
  Out: 20
  In : TestClass.a
  Out: 0
  In : TestClass.b   #抛异常,此类未定义b属性
  ---------------------------------------------------------------------------
  AttributeError                            Traceback (most recent call last)
  <ipython-input-55-39cab4ae7dc4> in <module>()
  ----> 1 TestClass.b

  AttributeError:>  In : getattr(a,'a')   #获取实例a的a属性
  Out: 10
  In : setattr(a,'a',20)
  In : a.a
  Out: 20
  In : hasattr(a,'b')
  Out: True
  属性包装:
  将方法包装成属性,以隐藏相关实现,用户使用时用属性的方式来用;
  控制属性的类型和范围,如某属性只能是正数且在0-100之间;
  虚拟属性(由其它属性处理后得来);
  三种属性操作(3个装饰器):
  @property   #可读
  @<property-name>.setter   #可写
  @<property-name>.deleter   #可删
  举例:
  attribute_package.py
  #!/usr/bin/env python3.6
  #
  class Washer:
  def __init__(self,water=100,scour=2):
  self._water = water
  self.scour = scour
  self.year = 2010
  @property
  def water(self):
  return self._water
  @water.setter
  def water(self,water):
  if 0 < water <= 500:
  self._water = water
  else:
  print('set failure')
  @property
  def total_year(self):
  return 2018 - self.year
  if __name__ == '__main__':
  w = Washer()
  print(w.water)
  w.water = -123
  print(w.water)
  print(w.total_year)
  描述符:
  将实现特殊协议方法的类作为另一个类的类属性;
  用来拦截和控制属性访问并可重复使用;
  协议方法:
  __get __()
  __set__()
  __delete__()
  分类:
  数据描述符(实现全部协议方法);
  非数据描述符(实现部分协议方法);
  说明:
  所有类成员函数都是非数据描述符;
  同名的实例属性和非数据描述符(以方法为例)访问优先级;
  注:
  描述符只能在新式类中使用;
  __call__(),让类的实例如函数一样可调用;
  举例(数据描述符):
  data_description.py
  #!/usr/bin/env python3.6
  #
  class NonNeg:
  def __init__(self,default=0):
  self.default = default
  def __get__(self,instance,owner):
  return self.default
  def __set__(self,instance,val):
  if val > 0:
  self.default = val
  else:
  print('the value must be nonnegative')
  def __delete__(self,instance):
  pass
  class Movie:
  rating = NonNeg()
  score = NonNeg()
  if __name__ == '__main__':
  m = Movie()
  print('rating:',m.rating)
  print('score:',m.score)
  m.rating = 80
  print('rating:',m.rating)
  m.score = 30
  print('score:',m.score)
  举例(非数据描述符):

  In :>  ...:   def pr(self):
  ...:         print('test')
  ...:
  In : t = Test()
  In : dir(t.pr)   #pr方法实现了__get__()方法
  Out:
  ['__call__',
  '__class__',
  '__delattr__',
  '__dir__',
  '__doc__',
  '__eq__',
  '__format__',
  '__func__',
  '__ge__',
  '__get__',
  '__getattribute__',
  In : t.pr = 10   #实例属性和非数据描述符同名,优先级为先实例属性再非数据描述符,此例中t.pr的属性掩盖了pr()方法
  In : t.pr
  Out: 10
  In : del t.pr
  In : t.pr
  Out: <bound method Test.pr of <__main__.Test object at 0x7f10ecd1c1d0>>
  In : t.pr()
  test
  7、
  类方法、静态方法:
  静态方法:
  定义:
  用staticmethod装饰;
  参数不用self;
  访问特性:
  不能引用或访问实例属性;
  可通过类、类变量访问类属性;
  调用方式:
  可用类、类实例调用;
  本质:
  在类中的一个普通函数;
  使面向对象程序中的函数归属于类,易于代码管理;
  用法:
  与类相关,但不依赖或改变类与实例;
  创建不同的实例;
  把类相关工具方法放入类中;
  举例:
  static_method.py
  class Washer:
  company = 'panasonic'
  def __init__(self,water=10,scour=2):
  self.water = water
  self.scour = scour
  self.year = 2010
  @staticmethod
  def spins_ml(spins):
  print('company:',Washer.company)
  #print('year:',self.year)   #报错,不能引用实例属性
  return spins * 0.4
  if __name__ == '__main__':
  print(Washer.spins_ml(8))
  w = Washer()
  print(w.spins_ml(9))
  w = Washer(200,Washer.spins_ml(10))
  print(w.company)
  print(w.year)
  print(w.water)
  print(w.scour)
  print(w.spins_ml(10))
  类方法:
  定义:
  @classmethod;
  必须提供参数cls;
  访问特性:不能引用或访问实例属性;
  调用方法:可以用类、类实例调用;
  继承特性:传入的类变量cls是子类,而非父类;
  用途:
  与类相关,但不依赖或改变类的实例;
  工厂方法,创建类实例,完成有关预处理;
  在类内调用静态方法时不用硬编码类名;
  举例:
  class_method.py
  class Washer:
  company = 'panasonic'
  def __init__(self,water=10,scour=2):
  self.water = water
  self.scour = scour
  self.year = 2010
  def spins_ml(spins):
  return spins * 0.4
  @classmethod
  def get_washer(cls,water,scour):
  print('company:',Washer.company)
  #print('year:',self.year)
  return cls(water,cls.spins_ml(scour))
  def start_wash(self):
  print(self.water)
  print(self.scour)
  print('start wash')
  if __name__ == '__main__':
  w = Washer.get_washer(100,8)
  w.start_wash()
  8、
  类的继承与方法重载:
  继承特点:
  oo编程的优点之一;
  减少代码和灵活制定新类;
  子类具有父类的属性和方法;
  子类不能继承父类的私有属性|方法;
  子类可添加新的方法;
  子类可修改父类的方法;
  继承语法:
  定义类时,在类名后写(继承的类名);
  多重继承时,括号中放多个父类名;
  例:
  class MyClass(BaseClass):
  重载的语法:
  直接定义和父类同名的方法;
  修改父类的方法:
  在重载的方法中调用父类方法;
  同时添加相应的业务逻辑;
  多重继承时如何调用父类方法;
  模拟游戏解析:
  sprite,ant,worm
  例(编写一个色子类):
  1、具有6个面,每个面为一种颜色;
  2、每种颜色代表一种数值1-6;
  3、实现一个通过颜色计算两种其代表数值和的静态方法;
  4、实现一个类方法gen_dice,用于产生这个类的实例;
  例:

  In :>  ...:   pass
  ...:
  In : A.__base__   #类A的父类是object,object是python中的新式类
  Out: object

  In :>  ...:   pass
  ...:
  In : B.__base__   #类B的父类是类A
  Out: __main__.A

  In :>  ...:   pass
  ...:

  In :>  ...:   pass
  ...:
  In : D.__bases__   #D的所有父类
  Out: (__main__.A, __main__.C)

  In :>  ...:   def foo(self):
  ...:         print('A foo')
  ...:

  In :>  ....:   def foo(self):
  ....:         print('B foo')
  ....:

  In :>  ....:   pass
  ....:
  In : c = C()
  In : c.foo()   #输出先继承的类的方法
  A foo

  In :>  ....:   pass
  ....:
  In : D().foo()
  B foo
  举例:
  wash.py
  9、
  类的特殊方法:
  深入理解类:
  类也是一个对象,但具有创建其自身实例的能力;
  类可以和一个变量进行绑定;
  可以为类增加属性;
  可把类作为函数的参数传递;
  元类:
  类的创建和管理者type;
  所有的类都是元类type的实例(python3.*);
  类实例化过程;
  例:

  In :>  ....:   pass
  ....:
  In : ept = Empty
  In : ept
  Out: __main__.Empty
  In : ept.__base__
  Out: object
  In : ept()
  Out: <__main__.Empty at 0x7fd0adf7c470>
  In : ept.foo='foo'
  In : ept.foo
  Out: 'foo'
  In : def use_class(mc):
  ....:   return mc()
  ....:
  In : use_class(Empty)
  Out: <__main__.Empty at 0x7fd0adf7ef28>
  In : type(Empty)
  Out: type
  In : Hello = type('Hello',(object,),dict(helo=lambda lf:print('hello')))
  In : h = Hello()
  In : h.helo()
  hello
  10、
  鸭子类型与多态:
  多态:
  一种类型具有多种类型的能力;
  允许不同的对象对同一消息作出灵活的反应;
  以一种通用的方式对待可使用的对象;
  非动态语言必须通过继承和接口来实现;
  python中的多态:
  通过继承实现多态(子类可作为父类使用);
  子类可重载父类的方法实现多态;
  例:

  In :>  ....:   def move(self):
  ....:         print('Animal is moving...')
  ....:

  In :>  ....:   pass
  ....:
  In : def move(obj):
  ....:   obj.move()
  ....:
  In : a = Animal()
  In : move(a)
  Animal is moving...
  In : d = Dog()
  In : move(d)
  Animal is moving...

  In :>  ....:   def move(self):
  ....:         print('Cat is moving...')
  ....:

  In :>  ....:   def move(self):
  ....:         print('Sheep is moving...')
  ....:
  In : move(Cat())
  Cat is moving...
  In : move(Sheep())
  Sheep is moving...
  In : move(7)   #报错
  动态语言与鸭子类型:
  变量绑定的类型具有不确定性;
  函数和方法可接受任何类型的参数;
  调用方法时不检查提供的参数类型;
  调用时是否成功由参数的方法和属性确定;
  调用不成功则抛出错误;
  python中不用定义接口;
  例:
  In : def test(foo):
  ....:   print(type(foo))
  ....:
  In : test(3)
  <class 'int'>
  In : test(3.1)
  <class 'float'>
  In : type(3)
  Out: int
  In : type(3.1)
  Out: float
  多态的好处:
  可实现开放的扩展与修改的封闭;
  使python更具灵活性;
  11、
  python与设计模式:
  设计模式:
  用来提高代码复用和可维护性的方式;
  能够很好的指导软件设计过程;
  是成功的软件设计模式和体系结构;
  用于解决特定类型问题的面向对象编程模型;
  python与设计模式:
  由于语言的特性不同,设计模式的实现方式和实现难度也会不同;
  有的模式已经在语言中内置了,如迭代器模式;
  单例模式可直接用模块级变量来实现;
  普通工厂模式可直接通过传入“类名”作为参数实现;
  策略模式:
  让一个对象的某个方法可以随时改变,而不用更改对象的代码;
  对于动态类型的python语言,不需要定义接口;
  基本的实现方法,用类作为参数传递;
  最简单的实例方法,函数作为参数传递;
  例(单例模式):
  single_class.py
  class singleClass:
  def __init__(self,x=0):
  self.x = 0
  sc = singleClass()
  def tsc():
  print(sc.x)
  sc.x = 10
  print(sc.x)
  def tsc2():
  print(sc.x)
  sc.x = 9
  print(sc.x)
  if __name__ == '__main__':
  tsc()
  tsc2()
  例(实现单实例的方式):
  singleton.py
  class Singleton:
  def __new__(cls,*args,**kwargs):
  if not hasattr(cls,'_sgl'):
  cls._sgl = super().__new__(cls,*args,**kwargs)
  return cls._sgl
  if __name__ == '__main__':
  sa = Singleton()
  sb = Singleton()
  print(id(sa))
  print(id(sb))
  例(普通工厂模式):
  normal_factory.py
  class Ab:
  a = 3
  class Ac:
  a = 0
  class MyFactory:
  def get_instance(self,ins):
  return ins()
  if __name__ == '__main__':
  mf = MyFactory()
  print(type(mf.get_instance(Ab)))
  例(策略模式——用类作为参数传递):
  class Moveable:
  def move(self):
  print('Move...')
  class MoveOnFeet(Moveable):
  def move(self):
  print('Move on feet...')
  class MoveOnWheel(Moveable):
  def move(self):
  print('Move on wheel...')
  class MoveObj:
  def set_move(self,moveable):
  self.moveable = moveable()
  def move(self):
  self.moveable.move()
  class Test:
  def move(self):
  print('i am fly')
  if __name__ == '__main__':
  m = MoveObj()
  m.set_move(Moveable)
  m.move()
  m.set_move(MoveOnFeet)
  m.move()
  m.set_move(MoveOnWheel)
  m.move()
  m.set_move(Test)
  m.move()
  例(策略模式——用函数作为参数传递):
  def movea():
  print('move a')
  def moveb():
  print('move b')
  class MoveObj:
  def set_move(self,moveable):
  self.moveable = moveable
  def move(self):
  self.moveable()
  if __name__ == '__main__':
  m = MoveObj()
  m.set_move(movea)
  m.move()
  m.set_move(moveb)
  m.move()
  12、
  装饰模式:
  一般,通过继承可获得父类的属性,还可通过重载修改其方法;
  装饰模式可不以继承的方式而返回一个被修改的类;
  类装饰器;
  例:
  decorator.py
  class BeDeco:
  def be_edit_fun(self):
  print('source fun')
  def be_keep_fun(self):
  print('keep fun')
  class Decorator:
  def __init__(self,dec):
  self._dec = dec()
  def be_edit_fun(self):
  print('start...')
  self._dec.be_edit_fun()
  def be_keep_fun(self):
  self._dec.be_keep_fun()
  if __name__ == '__main__':
  bd = BeDeco()
  bd.be_edit_fun()
  bd.be_keep_fun()
  dr = Decorator(BeDeco)
  dr.be_edit_fun()
  dr.be_keep_fun()
  例:
  decorator.py
  def deco(a_class):

  >  def __init__(self,age,color):
  self.wrapped = a_class(age)
  self.color = color
  def display(self):
  print(self.color)
  print(self.wrapped.age)
  return NewClass
  @deco
  class Cat:
  def __init__(self,age):
  self.age = age
  def display(self):
  print(self.age)
  if __name__ == '__main__':
  c = Cat(12,'black')
  c.display()
  13、
  通过组合来构建复杂的对象:
  组合:
  类似用各种零件组装机器(零件——基础类,机器——包含其它类的类);
  体现自下而上的面向对象编程方法;
  雪人案例:
  面向对象分析;
  抽象出其类;
  实现基类(shape不带角度参数的图形元素;shapeAngles需要角度参数的图形元素);
  实现子类(HatTop,HatBotton,Face,Sense,BodyOutline,Button);
  组装子类1(Hat,Head,Body,Shape);
  组装子类2(snow);
页: [1]
查看完整版本: VII python面向对象