手记

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 [13]: class TestClass:

   ....:     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 [14]: tc=TestClass()

In [15]: tc.info()

a: 0 b: 10

In [16]: tc.color='red'   #类外用

In [17]: print tc.color

red

In [18]: tca = TestClass()

In [19]: tcb = TestClass()

In [20]: tca.a = 100

In [21]: tcb.a = 200

In [22]: tca.info()

a: 100 b: 10

In [23]: tcb.info()

a: 200 b: 10

In [24]: tc = TestClass()

In [25]: tc.define_c()

In [26]: print tc.c

20

 

类属性:

类定义后就存在,而且不需要实例化;

类属性使得相同类的不同实例共同持有相同变量;

 

In [27]: class TestCss:

   ....:     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 [29]: tc = TestCss()

In [30]: tc.info()

a: 0 b: 10 class-attribute

In [29]: tc = TestCss()

In [30]: tc.info()

a: 0 b: 10 class-attribute

In [31]: tca = TestCss()

In [33]: tca.info()

a: 0 b: 10 class-attribute

In [34]: TestCss.cssa = 0   #类外修改其属性

In [35]: tc.info()

a: 0 b: 10 0

In [36]: tca.info()

a: 0 b: 10 0

 

私有属性:

不提供限制属性访问的关键字(无法限制类的各种属性在类外直接访问);

使用__开头的变量名加以标示,只有类对象自己能访问(限制性的);

使用_开头的变量名加以标示,只有类对象及其子类能访问(非强制性),对程序员来说,是标示性的而非限制性的,在类外还可以修改和查看;

 

In [37]: class TestPri:

   ....:     def __init__(self):

   ....:         self.__a = 0   #在此处初始化时实例属性就被隐藏了

   ....:     def info(self):

   ....:         print self.__a

   ....:        

 

In [38]: a = TestPri()

In [39]: a.info()

0

In [40]: a.__a = 3   #私有属性不能在外部进行修改,此处相当于重新定义了一个实例属性,与类中定义的self.__a = 0是不一样的

In [41]: a.info()

0

In [43]: print a.__a

3

In [44]: class TestPri:

   ....:     def __init__(self):

   ....:         self._a = 10

   ....:     def info(self):

   ....:         print self._a

   ....:        

In [45]: a = TestPri()

In [46]: a.info()

10

In [47]: a._a = 30   #在类外可修改和查看

In [48]: a.info()

30

In [49]: 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 [50]: class TestClass:

   ....:     a = 0

   ....:     def __init__(self):

   ....:         self.a = 10

   ....:         self.b = 20

   ....:        

In [51]: a = TestClass()

In [52]: a.a

Out[52]: 10

In [53]: a.b

Out[53]: 20

In [54]: TestClass.a

Out[54]: 0

In [55]: TestClass.b   #抛异常,此类未定义b属性

---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

<ipython-input-55-39cab4ae7dc4> in <module>()

----> 1 TestClass.b

AttributeError: class TestClass has no attribute 'b'

In [56]: getattr(a,'a')   #获取实例a的a属性

Out[56]: 10

In [57]: setattr(a,'a',20)

In [58]: a.a

Out[58]: 20

In [59]: hasattr(a,'b')

Out[59]: 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 [1]: class Test:

   ...:     def pr(self):

   ...:         print('test')

   ...:        

 

In [2]: t = Test()

In [3]: dir(t.pr)   #pr方法实现了__get__()方法

Out[3]:

['__call__',

 '__class__',

 '__delattr__',

 '__dir__',

 '__doc__',

 '__eq__',

 '__format__',

 '__func__',

 '__ge__',

 '__get__',

 '__getattribute__',

In [4]: t.pr = 10   #实例属性和非数据描述符同名,优先级为先实例属性再非数据描述符,此例中t.pr的属性掩盖了pr()方法

In [5]: t.pr

Out[5]: 10

In [6]: del t.pr

In [7]: t.pr

Out[7]: <bound method Test.pr of <__main__.Test object at 0x7f10ecd1c1d0>>

In [8]: 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 [2]: class A:

   ...:     pass

   ...:

In [3]: A.__base__   #类A的父类是object,object是python中的新式类

Out[3]: object

In [4]: class B(A):

   ...:     pass

   ...:

In [5]: B.__base__   #类B的父类是类A

Out[5]: __main__.A

In [6]: class C:

   ...:     pass

   ...:

In [7]: class D(A,C):

   ...:     pass

   ...:

In [8]: D.__bases__   #D的所有父类

Out[8]: (__main__.A, __main__.C)

In [9]: class A:

   ...:     def foo(self):

   ...:         print('A foo')

   ...:        

In [10]: class B:

   ....:     def foo(self):

   ....:         print('B foo')

   ....:        

In [11]: class C(A,B):

   ....:     pass

   ....:

In [12]: c = C()

In [13]: c.foo()   #输出先继承的类的方法

A foo

In [14]: class D(B,A):

   ....:     pass

   ....:

In [15]: D().foo()

B foo

 

举例:

wash.py

 

 

 

9、

类的特殊方法:

深入理解类:

类也是一个对象,但具有创建其自身实例的能力;

类可以和一个变量进行绑定;

可以为类增加属性;

可把类作为函数的参数传递;

 

元类:

类的创建和管理者type;

所有的类都是元类type的实例(python3.*);

类实例化过程;

 

例:

In [16]: class Empty:

   ....:     pass

   ....:

In [17]: ept = Empty

In [18]: ept

Out[18]: __main__.Empty

In [19]: ept.__base__

Out[19]: object

In [20]: ept()

Out[20]: <__main__.Empty at 0x7fd0adf7c470>

In [21]: ept.foo='foo'

In [22]: ept.foo

Out[22]: 'foo'

In [23]: def use_class(mc):

   ....:     return mc()

   ....:

In [25]: use_class(Empty)

Out[25]: <__main__.Empty at 0x7fd0adf7ef28>

In [26]: type(Empty)

Out[26]: type

In [27]: Hello = type('Hello',(object,),dict(helo=lambda lf:print('hello')))

In [28]: h = Hello()

In [29]: h.helo()

hello

 

 

 

10、

鸭子类型与多态:

多态:

一种类型具有多种类型的能力;

允许不同的对象对同一消息作出灵活的反应;

以一种通用的方式对待可使用的对象;

非动态语言必须通过继承和接口来实现;

 

python中的多态:

通过继承实现多态(子类可作为父类使用);

子类可重载父类的方法实现多态;

 

例:

In [31]: class Animal:

   ....:     def move(self):

   ....:         print('Animal is moving...')

   ....:        

In [32]: class Dog(Animal):

   ....:     pass

   ....:

In [33]: def move(obj):

   ....:     obj.move()

   ....:    

In [34]: a = Animal()

In [35]: move(a)

Animal is moving...

In [36]: d = Dog()

In [37]: move(d)

Animal is moving...

In [38]: class Cat(Animal):

   ....:     def move(self):

   ....:         print('Cat is moving...')

   ....:        

In [41]: class Sheep(Animal):

   ....:     def move(self):

   ....:         print('Sheep is moving...')

   ....:        

In [42]: move(Cat())

Cat is moving...

In [43]: move(Sheep())

Sheep is moving...

In [44]: move(7)   #报错

 

动态语言与鸭子类型:

变量绑定的类型具有不确定性;

函数和方法可接受任何类型的参数;

调用方法时不检查提供的参数类型;

调用时是否成功由参数的方法和属性确定;

调用不成功则抛出错误;

python中不用定义接口;

 

例:

In [48]: def test(foo):

   ....:     print(type(foo))

   ....:    

In [49]: test(3)

<class 'int'>

In [50]: test(3.1)

<class 'float'>

In [51]: type(3)

Out[51]: int

In [52]: type(3.1)

Out[52]: 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):

    class NewClass:

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


0人推荐
随时随地看视频
慕课网APP