第13章 面向对象编程

一、基本概念

1、object类是所有类的基类,如果你的类没有继承任何其他父类,object 将作为默认的父类。

2、python创建实例时无需new:

  myFirstObject = MyNewObjectType()   #“函数调用”形式!!!

3、python类的所有非静态方法的第一个形参都是self

4、python创建类时的继承:

  class EmplAddrBookEntry(AddrBookEntry):  #括弧内的便是基类

    ……

5、python中所有的类属性均public,但名字可能被“混淆”以阻止未经授权的访问,仅此而已!

6、python中的OOP术语

  抽象/实现

  封装/接口

  合成

  派生/继承/继承结构

  泛化/特化

  多态

  自省/反射:

    该性质展示了某对象是如何在运行期取得自身信息的。即如果传一个对象给你,你可以查出它有什么能力。

    python中的type() dir()等内建函数都使用了反射机制

二、类

1 类

(1)创建类

  class ClassName( bases ):
  'class documentation string'   #'类文档字符串'
  class_suite             #类体

(2)类的属性

  属性 = 数据属性 + 方法属性

  特殊的类属性:

    C.__name__ 类C的名字(字符串)
    C.__doc__ 类C的文档字符串
    C.__bases__ 类C的所有父类构成的元组
    C.__dict__ 类C的属性
    C.__module__ 类C定义所在的模块(1.5 版本新增)
    C.__class__ 实例C对应的类(仅新式类中)

2 实例

(1)关于__init__()和__del__()方法

  不要忘记首先调用父类的__init__()和__del__()

  调用del x不表示调用了x.__del__(),其仅是减少x的引用计数,只有当引用计数为1时才会执行__del__()函数

  除非你知道你正在干什么,否则不要去实现__del__()

(2)实例属性 和 类属性

  内建函数 dir()可以显示类属性,也可以打印所有实例属性

  从实例中访问类属性须谨慎:

    任何对实例属性的赋值都会创建一个实例属性(如果不存在的话)并且对其赋值。如果类属性中存在同名的属性,则会覆盖对类属性的引用。所以,给一个与类属性同名的实例属性赋值,我们会有效地“隐藏”类属性,但一旦我们删除了这个实例属性,类属性又重见天日。

  类属性的持久性

3 绑定与方法调用

方法是类属性而非实例属性;

方法只有在其所属的类拥有实例时,才能被调用。当存在一个实例时,方法才被认为是绑定到那个实例了。没有实例时方法就是未绑定的;

任何一个方法定义中的第一个参数都是变量 self,它表示调用此方法的实例对象

(1)调用绑定方法

  即正常的先构建出一个类的实例,然后通过该实例调用该类的方法(因为此时方法已经与实例绑定了!)

(2)调用非绑定方法

  调用非绑定方法不常用。调用一个还没有任何实例的类中的方法的主要场景是:你在派生一个子类,而且你要覆盖父类的方法,这时你需要调用那个父类中想要覆盖掉的构造方法:

    class EmplAddrBookEntry(AddrBookEntry):
    'Employee Address Book Entry class' # 员工地址记录条目
    def __init__(self, nm, ph, em):
      AddrBookEntry.__init__( self, nm, ph)  #此即调用非绑定方法。当还没有实例且需要调用一个非绑定方法的时候必须传递self 参数
      self.empid = id
      self.email = em

(3)静态方法 和 类方法

创建方法1:使用staticmethod()和 classmethod()内建函数

    class TestStaticMethod:
      def foo():
        print 'calling static method foo()'
      foo = staticmethod(foo)

    

    class TestClassMethod:
      def foo(cls):
        print 'calling class method foo()'
        print 'foo() is part of class:', cls.__name__
      foo = classmethod(foo)

创建方法2:使用函数修饰符  

  class TestStaticMethod:
    @staticmethod
    def foo():
      print 'calling static method foo()'

  class TestClassMethod:
    @classmethod
    def foo(cls):
      print 'calling class method foo()'
      print 'foo() is part of class:', cls.__name__

三、组合

在代码中利用类的两种方法:组合 + 继承

组合是一种has-a关系

四、继承、子类和派生

1 __base__类属性

  它是一个包含其父类的集合的元组,

2 通过继承覆盖方法

举例说明:

  class P(object):
    def foo(self):
      print 'Hi, I am P-foo()'

  class C(P):
    def foo(self):
      print 'Hi, I am C-foo()'

  >>> c = C()
  >>> c.foo()
  Hi, I am C-foo()  尽管C继承了P的foo()方法,但因为C定义了自已的 foo()方法,所以P中的foo()方法被覆盖

如何调用那个被我覆盖的基类方法呢:

  方法一:

  >>> P.foo( c )     这是在调用非绑定方法
  Hi, I am P-foo()

  方法二:

  class C(P):
    def foo(self):
      P.foo( self )   在子类的重写方法里显式地调用基类方法(也是在调用非绑定方法) 
      print 'Hi, I am C-foo()'

  方法三:

  class C(P):
    def foo(self):
      super( C, self ).foo()
      print 'Hi, I am C-foo()'

3 从标准类型派生

举例1:继承不可变标准类型的例子

  假定你想在金融应用中,应用一个处理浮点数的子类。每次你得到一个贷币值(浮点数给出的),你都需要通过四舍五入,变为带两位小数位的数值。

  class RoundFloat(float):   继承float
    def __new__(cls, val):
      return float.__new__(cls, round(val, 2))

  或写成: 

  class RoundFloat(float):
    def __new__(cls, val):
      return super(RoundFloat, cls).__new__(cls, round(val, 2))

举例2:继承可变标准类型的例子

  该例子创建一个新的字典类型,其keys()方法会自动排序结果

  class SortedKeyDict(dict):
    def keys(self):
      return sorted( super( SortedKeyDict, self ).keys())

4 多重继承

复杂,暂且没看!

五、类、实例和其他对象的内建函数

issubclass(sub, sup)

isinstance(obj, class)

hasattr(myInst, 'foo')

getattr(myInst, 'foo')

setattr(myInst, 'bar', 'my attr')

delattr(myInst, 'foo')

dir( obj )

super( type[, obj] )  给出type,super()会返回此type的父类。若你希望父类被绑定,你可以传入obj参数(obj可以是type类型的一个实例;obj也可以是一个类型,但应当是type的一个子类)

vars(obj) 返回一个字典,它包含了对象存储于其__dict__中的属性(键)及值

六、用特殊方法定制类

可以重写python中的一些特殊方法以定制类,从而可以实现两大功能:

  模拟标准类型

  重载操作符

用来定制类的特殊方法列举如下:

基本定制型:
  C.__init__(self[, arg1, ...])              构造器(带一些可选的参数)
  C.__new__(self[, arg1, ...])            构造器(带一些可选的参数);通常用在设置不变数据类型的子类。
  C.__del__(self)                              解构器
  C.__str__(self)                               可打印的字符输出;内建 str()及 print 语句
  C.__repr__(self)                            运行时的字符串输出;内建 repr() 和‘‘ 操作符
  C.__unicode__(self)                      Unicode 字符串输出;内建 unicode()
  C.__call__(self, *args)                   表示可调用的实例
  C.__nonzero__(self)                     为 object 定义 False 值;内建 bool() (从 2.2 版开始)

  C.__len__(self)                             “长度”(可用于类);内建 len()

对象(值)比较:

  C.__cmp__(self, obj)                     对象比较;内建 cmp()
  C.__lt__(self, obj) and                   小于/小于或等于;对应<及<=操作符
  C.__gt__(self, obj) and                  大于/大于或等于;对应>及>=操作符
  C.__eq__(self, obj) and                 等于/不等于;对应==,!=及<>操作符

属性:
  C.__getattr__(self, attr)                 获取属性;内建 getattr();仅当属性没有找到时调用
  C.__setattr__(self, attr, val)          设置属性
  C.__delattr__(self, attr)                 删除属性
  C.__getattribute__(self, attr)         获取属性;内建 getattr();总是被调用
  C.__get__(self, attr)                      (描述符)获取属性
  C.__set__(self, attr, val)                (描述符)设置属性

  C.__delete__(self, attr)                 (描述符)删除属性

数值类型:二进制操作符
  C.__*add__(self, obj)                    加;+操作符
  C.__*sub__(self, obj)                    减;-操作符
  C.__*mul__(self, obj)                    乘;*操作符
  C.__*div__(self, obj)                     除;/操作符
  C.__*truediv__(self, obj)               True 除;/操作符
  C.__*floordiv__(self, obj)              Floor 除;//操作符
  C.__*mod__(self, obj)                  取模/取余;%操作符
  C.__*divmod__(self, obj)             除和取模;内建 divmod()
  C.__*pow__(self, obj[, mod])       乘幂;内建 pow();**操作符
  C.__*lshift__(self, obj)                 左移位;<<操作符
  C.__*rshift__(self, obj)                 右移;>>操作符
  C.__*and__(self, obj)                   按位与;&操作符
  C.__*or__(self, obj)                     按位或;|操作符

  C.__*xor__(self, obj)                   按位与或;^操作符

数值类型:一元操作符
  C.__neg__(self)                           一元负
  C.__pos__(self)                           一元正
  C.__abs__(self)                           绝对值;内建 abs()
  C.__invert__(self)                        按位求反;~操作符

数值类型:数值转换
  C.__complex__(self, com)            转为 complex(复数);内建 complex()
  C.__int__(self)                           转为 int;内建 int()
  C.__long__(self)                         转为 long;内建 long()
  C.__float__(self)                         转为 float;内建 float()

数值类型:基本表示法(String)
  C.__oct__(self)                           八进制表示;内建 oct()
  C.__hex__(self)                         十六进制表示;内建 hex()

数值类型:数值压缩
  C.__coerce__(self, num)           压缩成同样的数值类型;内建 coerce()
  C.__index__(self)                      在有必要时,压缩可选的数值类型为整型(比如:用于切片索引等等)

序列类型
  C.__len__(self)                         序列中项的数目
  C.__getitem__(self, ind)           得到单个序列元素
  C.__setitem__(self, ind,val)     设置单个序列元素
  C.__delitem__(self, ind)           删除单个序列元素
  C.__getslice__(self, ind1,ind2) 得到序列片断
  C.__setslice__(self, i1, i2,val)   设置序列片断
  C.__delslice__(self, ind1,ind2)  删除序列片断

  C.__contains__(self, val)          测试序列成员;内建 in 关键字

  C.__*add__(self,obj)                串连;+操作符
  C.__*mul__(self,obj)                重复;*操作符

  C.__iter__(self)                        创建迭代类;内建 iter()

映射类型
  C.__len__(self)                         mapping中的项的数目
  C.__hash__(self)                      散列(hash)函数值
  C.__getitem__(self,key)           得到给定键(key)的值
  C.__setitem__(self,key,val)     设置给定键(key)的值
  C.__delitem__(self,key)           删除给定键(key)的值
  C.__missing__(self,key)          给定键如果不存在字典中,则提供一个默认值

1 简单定制举例

目标:自定义一个类来保存浮点数,且自动实现四舍五入并保留两位小数

  class RoundFloatManual(object):
    def __init__(self, val):
      assert isinstance(val, float), \
      "Value must be a float!"
      self.value = round( val, 2 )

  此时若如下用会出现这样的效果:

  >>> rfm = RoundFloatManual(42)
  Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "roundFloat2.py", line 5, in __init__
    assert isinstance(val, float), \ AssertionError: Value must be a float!

  >>> rfm = RoundFloatManual(4.2)
  >>> rfm             本来此处按常理理解应该打印出浮点数最好,但实际并没有,因为我们没有对类进行定制
  <roundFloat2.RoundFloatManual object at 0x63030>
  >>> print rfm     本来此处按常理理解应该打印出浮点数最好,但实际并没有,因为我们没有对类进行定制
  <roundFloat2.RoundFloatManual object at 0x63030>

  

  解决办法:好的办法是,去实现__str__()和__repr__()二者之一,或者两者都实现

  现添重载__str__()和__repr__()方法,以覆盖默认的行为:

    def __str__(self):
      return '%.2f' % self.value

    __repr__ = __str_     #由于本例中两个函数的代码可以完全一样,所以可以仅让__repr__()作为__str__()的一个别名

  这样打印操作就正常了:

  >>> rfm = RoundFloatManual(5.5964)
  >>> rfm         此处显示正常是由于重写了__repr__()方法的效果
  5.60
  >>> print rfm    此处显示正常是由于重写了__str__()方法的效果
  5.60

2 数值定制举例

目标:创建一个Time60时间类

  class Time60(object):

    def __init__(self, hr, min): # constructor 构造器
      self.hr = hr    # assign hours 给小时赋值
      self.min = min  # assign minutes 给分赋值

显示:

  def __str__(self):    #重写方法
    return '%d:%d' % (self.hr, self.min)

  __repr__ = __str__  #重写方法

加法:

  def __add__(self, other):  #重写方法

    return self.__class__(self.hr + other.hr, self.min + other.min)

原位加法:用来支持像 mon += tue 这样的操作符  

  def __iadd__(self, other):   #重写方法
    self.hr += other.hr
    self.min += other.min
    return self

3 迭代器定制举例

  class AnyIter(object):

    def __init__(self, data, safe=False):
      self.safe = safe
      self.iter = iter(data)

    def __iter__(self):
      return self

    def next(self, howmany=1):
      retval = []
      for eachItem in range(howmany):
        try:
          retval.append( self.iter.next() )
        except StopIteration:
          if self.safe:
            break
          else:
            raise
      return retval

  使用:

   >>> a = AnyIter(range(10))
   >>> i = iter(a)
   >>> for j in range(1,5):
   >>> ... print j, ':', i.next(j)
   1 : [0]
   2 : [1, 2]
   3 : [3, 4, 5]
   4 : [6, 7, 8, 9]

七、私有化

python的属性默认是public

双下划线:

  由双下划线开始的属性在运行时被“混淆”,所以不允许直接访问

单下划线:(验证有问题?)

  简单的模块级私有化只需要在属性名前使用一个单下划线字符。这就防止模块的属性用“from mymodule import*”来加载。这是严格基于作用域的,所以这同样适合于函数。

八、授权与包装

九、新式类的高级特性

Python核心编程读笔 12:OOP的更多相关文章

  1. Python核心编程读笔 10:函数和函数式编程

    第11章 函数和函数式编程 一 调用函数  1 关键字参数 def foo(x): foo_suite # presumably does some processing with 'x' 标准调用 ...

  2. Python核心编程读笔 1

    第一章 欢迎来到Python世界 1 Python特点: 高级的可进行系统调用的解释性语言 面向对象 可升级.扩展.移植 自动内存管理器(内存管理由Python解释器负责) 2 安装 Windows的 ...

  3. Python核心编程读笔 11:模块

    第12章 模块 1.基本概念 模块的文件名就是模块名字.py 每个模块都定义了自己唯一的名称空间 模块的搜索路径:会被保存在 sys 模块的 sys.path 变量里 >>>sys. ...

  4. Python核心编程读笔 13:执行环境

    第14章  执行环境 一.可调用对象 python有四种可调用对象:函数.方法.类.一些类的实例 1 函数 (1)内建函数(BIF) BIF是用c/c++写的,编译后放入python解释器,然后把它们 ...

  5. Python核心编程读笔 8: 文件和输入输出

    第九章 文件和输入输出 一.文件内建函数.方法.属性 1 文件内建函数 file_object = open(file_name, access_mode='r', buffering=-1) 工厂函 ...

  6. Python核心编程读笔 7: 条件和循环

    第八章 条件和循环 一.if python中的条件表达式:很奇葩!!! smaller = (x < y and [x] or [y])[0] 或者: smaller = x if x < ...

  7. Python核心编程读笔 6: 映射和集合类型

    第七章 映射和集合能力 一 字典(python中唯一的映射类型) 1 基本 创建和赋值: 正常创建:>>>dict = {'name':'earth', 'port':80} 用工厂 ...

  8. Python核心编程读笔 5: python的序列

    第六章 序列:字符串.列表.元组 一.序列 (1)序列类型操作符 seq[ind] 获得下标为 ind 的元素 seq[ind1:ind2] 切片操作 seq * expr 序列重复 expr 次 s ...

  9. Python核心编程读笔 4

    第五章 数字 二.整形 1 布尔型 2 标准整数类型 3 长整型 数字后面加L,能表示非常非常大的数字 目前,整形和长整型逐渐统一!!! 三.双精度浮点数 四.复数 有关复数的几个概念: 表示虚数的语 ...

随机推荐

  1. Cocos2d-x优化中多线程并发訪问

    多线程并发訪问在Cocos2d-x引擎中用的不是非常多,这主要是由于中整个结构设计没有採用多线程. 源自于Objective-C的Ref对象,须要使用AutoreleasePool进行内存管理,Aut ...

  2. 解决Mac OS Adobe Flash Builder 4.7 java heap space 问题【转】

    1. 在Finder中打开Adobe Flash Builder 4.7的安装目录 2. 在Adobe Flash Builder 4.7.app上点击右键“Show Package contents ...

  3. 【贪心】【TOJ4107】【A simple problem】

    Given three integers n(1≤n≤1018), m(1≤m≤105), k(1≤k≤1018). you should find a list of integer A1,A2,- ...

  4. C#整理3——运算符和语句

    运算符: 一.算术运算符:+ - * / % ——取余运算 取余运算的应用场景:1.奇偶数的区分. 2.把数变化到某个范围之内.——彩票生成. 3.判断能否整除.——闰年.平年. using Syst ...

  5. 使用fat jar和exe4j把java程序打包成exe执行文件---转载的

    java应用编写测试好之后都是jar包或class文件,客户拿到这个东西后一般是不会java开发者那样在命令窗口下面输入运行的.客户要求的就是直接点击应用名称运行.java在方面做得很不友好,开发人员 ...

  6. Inno setup complier将文件添加注册表

    [Registry] Root: HKCR; Subkey:.; ValueType: string; ValueName: ; ValueData:"264file" Root: ...

  7. 关于AutoCAD.NET的辅助方法

    求中点坐标: /// <summary> /// 中点 /// </summary> /// <param name="StartPoint"> ...

  8. iOS学习心得——UITableViewCell的复用

    UITableView是在iOS开发中最常用的控件之一.我的第一篇学习心得献给它了         UITableView是由一行一行的UITableViewCell构成的.         首先想这 ...

  9. 初学DIV+CSS要记住的

    初学DIV+CSS?有六个问题需要您关注一下!作为DIV+CSS初学者,如果在动手写代码之前对网页整体结构由一个清晰认识的话,写起来会事半功倍!但是,写的过程中总是有这样那样的问题,使得我们不得不停下 ...

  10. <转>泛型的内部原理:类型擦除以及类型擦除带来的问题

    参考:java核心技术 一.Java泛型的实现方法:类型擦除 前面已经说了,Java的泛型是伪泛型.为什么说Java的泛型是伪泛型呢?因为,在编译期间,所有的泛型信息都会被擦除掉.正确理解泛型概念的首 ...