Python学习笔记【七】——《python基础教程》:: 更加抽象

第7章 更加抽象

创建自己的对象(类型或者类的对象)是Python的核心概念——非常核心。事实上,Python被称为面向对象的语言。

7.1. 对象的魔力

面向对象程序设计中的属于对象(object)基本上可以看作数据(特性)以及由一系列可以存取、操作这些数据的方法所组成的集合。
多态:即使不知道变量所引用的对象类型是什么,还是能对她进行操作,而它会根据对象(或类)类型的不同而表现出不同的行为。
封装:对全局作用域中其他区域隐藏多余信息的原则。不用关心对象是如何构建的。
继承:子类可以从超类继承方法,在子类上调用方法时,程序会自动从超类调用该方法。

7.2. 类和类型

7.2.2. 创建自己的类

创建类的格式

>>> __metaclass__ = type #确定使用新式类
>>> class Person:
...     def set_name(self, name):
...         self.name = name
...     def get_name(self):
...         return self.name
...     def greet(self):
...         print "Hello, world! I'm %s." % self.name
... 

关于类有以下说明:
1. 旧式类和新式类有区别。除非Python3.0之前默认附带的代码,没必要使用旧式类。在新式类中,要在模块或脚本开始的地方放置赋值语句metaclass = type。
2. class语句会在函数定义的地方创建自己的命名空间。
3. 方法参数的self表示对象自己。在方法被调用时,自动将对向自己传递给方法(不需要用户显式传递)。例如:

```
>>> foo=Person()
>>> foo.set_name('holly')
>>> foo.get_name()
'holly'
>>> foo.greet()
Hello, world! I'm holly.

```

4. 类的特性(例如例子中self.name)可以在外部访问。

```
>>> foo.name
'holly'

```

7.2.3. 特性、函数和方法

  1. 方法将它的第一个参数绑定到所属的实例上,调用方法时可以不必提供该参数。可以将特性绑定到普通函数上,就不会有特殊的self参数了。

    >>> class Class:
    ...     def method(self):
    ...         print 'I have a self!'
    ... 
    >>> def function():
    ...     print "I don't..."
    ... 
    >>> foo = Class()
    >>> foo.method()
    I have a self!
    >>> foo.method = function
    >>> foo.method()
    I don't...
    
  2. self参数不取决于调用方法的方式,可以随意使用引用同一个方法的其他变量。

    >>> class Bird:
    ...     song = 'Squaawk!'
    ...     def sing(self):
    ...         print self.song
    ... 
    >>> bird = Bird()
    >>> bird.sing()
    Squaawk!
    >>> birdsong = bird.sing
    >>> birdsong()
    Squaawk!
    
  3. 为了让方法或特性变为私有,只要在它的名字前添加双下划线。

    >>> class Secretive:
    ...     def __inaccessible(self):   #定义私有方法
    ...         print 'Bet you can\'t see me...'
    ...     def accessible(self):
    ...         print 'The secret message is:'
    ...         self.__inaccessible()
    ... 
    >>> s = Secretive()
    
    #外部无法访问私有方法
    
    >>> s.__inaccessible()
    Traceback (most recent call last):
      File "", line 1, in 
    AttributeError: 'Secretive' object has no attribute '__inaccessible'
    >>> s.accessible()
    The secret message is:
    Bet you can't see me...
    

    ★在类的内部定义中,所有双下划线开始的名字都被“翻译”称前面加上下划线和类名的形式。因此可以采用这种方式访问私有方法。

    >>> Secretive._Secretive__inaccessible
    method Secretive.__inaccessible>
    
  4. 不想使用3中的方法但是又想让其他对象不要访问内部数据,可以使用单下划线。但下划线的名字不会被带星号的imports语句(from module import *)导入。

有些语言支持多种层次的成员变量(特性)私有性。比如Java就支持4中级别。尽管单双下划线在某种程度上给出两个级别的私有性,但Python并没有真正的私有化支持。

7.2.4. 类的命名空间

定义类时,所有位于class语句中的代码都在特殊的命名空间中执行——类命名空间(class namespace)。该空间可由类内所有成员访问。
★Python中,类的定义就是执行代码块,例如:

>>> class C:
...     print 'Class C being defined...'
... 
Class C being defined...

书中对命名空间的说明有点简略,可参考
http://blog.csdn.net/heli200482128/article/details/74990347

7.2.5. 指定超类

将其他类名写在class语句后的圆括号内可以指定超类。

>>> class Filter:
...     def init(self):
...         self.blocked = []
...     def filter(self, sequence):
...         return [x for x in sequence if x not in self.blocked]
... 
>>> class SPAMFilter(Filter):
...     def init(self): #重载init()
...         self.blocked = ['SPAM']
... 
>>> s = SPAMFilter()
>>> s.init()
#filter方法是从Filter类中继承的
>>> s.filter(['SPAM', 'SPAM','eggs','bacon','SPAM'])
['eggs', 'bacon']

7.2.6. 调查继承

★参照7.2.5,假定SPAMFilter是Filter的子类。

  1. 查看一个类是否是另一个的子类,可使用内建函数issubclass()。

    >>> issubclass(SPAMFilter, Filter)
    True
    >>> issubclass(Filter, SPAMFIlter)
    False
    
  2. 若想知道已知类的基类,可以使用特性__bases__

    >>> SPAMFilter.__bases__
    (<class '__main__.Filter'>,)
    
  3. 检查对象是否是一个类的实例,可以使用函数isinstance()

    >>> s = SPAMFilter()
    >>> isinstance(s, SPAMFilter)   #s是SPAMFilter类的直接实例
    True
    >>> isinstance(s, Filter)   #s是SPAMFilter类的间接实例
    True
    >>> isinstance(s, str)
    False
  4. 直接检查对象属于哪个类,可以使用__class__特性

    >>> s.__class__
    <class '__main__.SPAMFilter'>
    

7.2.7. 多个超类

  1. 多重继承(multiple inheritance)**:子类有多个基类

    >>> class Calculator:
    ...     def calculate(self, expression):
    ...         self.value = eval(expression)
    ... 
    >>> class Talker:
    ...     def talk(self):
    ...         print 'Hi, my value is', self.value
    ... 
    >>> class TalkingCaculator(Calculator, Talker):
    ...     pass
    ... 
    >>> tc = TalkingCaculator()
    >>> tc.calculate('1+2*3*4/6')
    >>> tc.talk()
    Hi, my value is 5
    

2.多重继承需要注意多个超类的继承顺序:先继承的类中的方法会重写后继承的类的方法。 即上个例子中,若Calculator类中也有talk()方法,由于先继承Calculator后继承Talker,当外部调用talk()方法时,将调用Calculator中的talk()。
3. 若超类们共享了一个超类,在查找给定方法或者特性时,访问超类的顺序称为MRO(Method Resolution Order,方法判定顺序)

7.2.8. 接口和内省

  1. 接口:即公开的方法和特性。这个概念于多态有关。
  2. Python中,不需要显式指定对象必须包含哪些方法才能作为参数接收。使用对象时,默认对象可以实现要求的方法,若不能实现,程序会失败。
    调用对象时,可以使用函数hasattr()、callable()、hasattr(x, ‘__call__’)检查方法是否存在,避免上述问题。

7.3. 一些关于面向对象设计的思考

面向对象设计要点

将属于一类的对象放在一起。若一个函数操纵一个全局变量,两者最好作为类内的特性和方法。
不要让对象过于亲密。方法应只关心自己实例的特性。让其它实例管理自己的状态。
小心继承,尤其是多重继承。继承机制有时很有用,但某些情况下让事情变得过于复杂。多继承难以正确使用,更难以调试。
简单就好。让方法小巧。一般来说,多数方法都应能在30秒内被理解,尽量将代码行数控制在一页或一屏之内。

建立面向对象模型方法

♦写下问题的描述,把名词、动词、形容词加下划线。
♦对于所有名词,用作可能的类。
♦对于所有动词,用作可能的方法。
♦对于所有形容词,用作可能的特性。
♦把所有方法和特性分配到类。

精炼模型步骤

♦设计一系列使用实例——即程序应用时的场景,试着包括所有的功能。
♦逐个考虑每个场景,保证模型包含所有需要的东西。若有遗漏,则添加;若有错误,则修正。直到满意为止。

可以开工了

你可能感兴趣的:([软件开发]python,python,更加抽象)