Python的学习之旅---开始篇(五)

来源:互联网 发布:海带缠潜艇淘宝 编辑:程序博客网 时间:2024/05/17 23:16

面向对象

        在面向对象程序设计中,术语对象(object)基本上可以看做数据(特性)以及由一系列可以存取、操作这些数据的方法所组成的集合。使用对象替代全局变量和函数的原因可能有很多。其中对象最重要的优点包括以下几个方面。

  1. 多态:意味着可以对不同类的对象使用同样的操作,他们会像被"施了魔法一般"工作。
  2. 封装:对外部世界隐藏对象的工作细节。
  3. 继承:以通用的类为基础建立专门的类对象。
多态意味着就算不知道变量所引用的对象类型是什么,还是能对它进行操作,而它也会根据对象(或类)类型的不同而表现出不同的行为。
>>> 'abc'.count('a')1>>> [1,2,'a'].count('a')1>>> from random import choice>>> x = choice(['Hello,world',[1,2,'e','e',4]])>>> x.count('e')1>>> x = choice(['Hello,world',[1,2,'e','e',4]])>>> x.count('e')2
(标准库random中包含choice函数,可以从序列中随机选出元素,给变量赋值)
        关键点在于:不需要检测类型,只需要知道x有个叫做count的方法,带有一个字符作为参数,并且返回整数值就够了。如果其他人创建的对象也有Count方法,那也无所谓,你只需要像用字符串和列表一样使用该对象就行了。
在Python里面,很多内建运算符和函数都有多态的性质------你写的绝大多数程序可能都是,即使你并非有意这样。
        事实上,唯一能够毁掉多态的就是使用函数显示地检查类型,比如type、isinstance、以及issubclass函数等。如果可能的话,应该尽力避免使用这些毁掉多态的方法。真正重要的是如何让对象按照你所希望的方式工作,不管它是否是正确的类型。
        封装,指的是向程序中的其他部分隐藏对象的具体实现细节的原则,它会帮助处理程序组件而不用过多关心多余细节,就像函数做的一样。对象的状态由它的特性(比如名称)来描述。对象的方法可以改变它的特性。所以就像是将一大堆函数(方法)捆在一起,并且给予它们访问变量(特性)的权力,它们可以在函数调用之间保持保存的值。
(Python 中,习惯上都使用单数名词,并且首字母大写,比如Bird和Lark)
类和类型
         定义子类只是个定义更多方法的过程。
(在旧版本的Python中,类和类型之间有很明显的区别。内建的对象是基于类型的,自定义的对象是基于类的。可以创建类但是不能创建类型。但是在最近的版本的Python中,事情有了些变化。基本类型和类之间的界限开始模糊了。可以创建内建类型的子类(或子类型),而这些类型的行为更类似于类。)
         
__metaclass__ = typeclass Person:    def setName(self,name):        self.name = name    def getName(self):        return self.name    def greet(self):        print ("Hello, world! I'm %s." % self.name)
self 参数实际上正是方法和函数的区别。方法(更专业一点可以称为绑定方法)将它们的第一个参数绑定到所属的实例上,因此你无需显示地提供该参数。当然也可以将特性绑定到一个普通函数上,这样就不会有特殊的self参数了:
>>> class Class:def method(self):print ("i have  a self")>>> def function():print ("I don't...")>>> instance = Class()>>> instance.method()i have  a self>>> instance.method = function>>> instance.method()I don't...>>> 
(注意,self 参数并不依赖于调用方法的方式,前面我们使用的是instance.method(实例.方法)的形式,可以随意使用其他变量引用同一个方法)
>>> class Bird:song = 'Squaawk'def sing(self):print (self.song)>>> bird = Bird()>>> bird.sing()Squaawk>>> birdsong = bird.sing>>> birdsong()Squaawk
Python并不直接支持私有方式,而是靠程序员自己把握在外部进行特性修改的时机。毕竟在使用对象前应该知道如何使用。但是,可以使用一些小技巧达到私有特性的效果。
       为了让方法或者特性变为私有(从外部无法访问),只要在它的名字墙面加上双下划线即可。但是在类的内部定义中,所有以双下划线开始的名字都被“翻译”成前面加上单下划线和类名的形式。所以在类外还是能够访问这些私有方法,尽管不应该这么做:
>>> s._Secretive__inaccessible()
       简而言之,确保其他人不会访问对象的方法和特性是不可能的,但是这类“名称变化术”就是他们不应该访问这些函数或者特性的强有力信号。如果不需要使用这种方法但是又想让其他对象不要访问内部数据,那么可以使用单下划线。这个的确有实际效果。例如前面有下划线的名字都不会被带星号的Import语句(from module import *) 导入。
>>> class MemberCounter:members = 0def init(self):MemberCounter.members +=1>>> m1 = MemberCounter()>>> m1.init()>>> MemberCounter.members1>>> m2 = MemberCounter()>>> m2.init()>>> MemberCounter.members2>>> m1.members2>>> m2.members2>>> m1.members = 3>>> m1.members3>>> m2.members2>>> MemberCounter.members=5>>> m1.members3>>> m2.members5
新numbers值被写到m1的特性中,屏蔽了类范围内的变量。这跟函数内的局部和全局变量的行为十分类似。
>>> class Filter:def init(self):self.blocked = []def filters(self,sequence):return [x for x in sequence if x not in self.blocked]>>> class SPAMFilter(Filter): # SPAMFilter 是Filter的子类def init(self): # 重写Filter超类中的init方法self.blocked = ['SPAM']
测试一:
>>> f = Filter()>>> f.init()>>> f.filters([1,2,3])[1, 2, 3]
测试二:
>>> s.filters(['SPAM','SPAM','SPAM','SPAM','eggs','bacon','SPAM'])['eggs', 'bacon']>>> 
Python支持多重继承,是个非常有用的工具,但是当使用多重继承的时候,有个特别需要注意的地方。如果一个方法从多个超类继承(也就是说你有两个相同名字的不同方法),那么必须要注意下超类的顺序(在class语句中):先继承的类中方法会重用后继承的方法。
接口
接口的概念与多态有关。在处理多态对象时,只要关心它的接口(或称为协议)即可,也就是公开的方法和特性。在Python中,不用显式地指定对象必须包含哪些方法才能作为参数接收。
除了调用方法,然后期待一切顺利之外,还可检查所需方法是否已经存在。如果不存在,就需要做些其他事情:
>>> hasattr(tc, 'talk')True>>> hasattr(tc,'fnord')False
一些与面向对象设计有关的思考:
1、将属于一类的对象放在一起。如果一个函数操纵一个全局变量,那么两者最好都在类内作为特性和方法出现。
2、不要让对象过于亲密。方法应该只关心自己实例的特性。让其他实例管理自己的状态。

注:以上代码和笔记来自《Python基础编程 第二版》





0 0