D:\>python Python 2.7.5 (default, May 15 2013, 22:43:36) [MSC v.1500 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. # Chapter 07 更加抽象 #7.1 对象的魔力 # 前几章介绍了Python主要的内建对象类型(数字, 字符串, 列表, 元组和字典),以及内建函数和标准库的用法,还有自定义函数的方式. # 本章介绍如何创建自己的对象. #7.1 对象的魔力 #多态: Polymorphism #封装: Encapsulation #继承: Inheritance #7.1.1 多态 >>> #object.getPrice() ... >>> 'abc'.count('a') 1 >>> [1,2,'a'].count('a') 1 >>> from random import choice >>> x=choice(['Hello, world', [1,2,'e','e',4]]) >>> >>> x 'Hello, world' >>> x.count('e') 1 >>> x=choice(['Hello, world', [1,2,'e','e',4]]) >>> x [1, 2, 'e', 'e', 4] >>> x.count('e') 2 >>> 1+2 3 >>> 'Fish' + 'license' 'Fishlicense' >>> def add(x,y): ... return x+y ... >>> add(1,2) 3 >>> add('Fish','license') 'Fishlicense' >>> def length_message(x): ... print "The length of", repr(x), "is", len(x) ... >>> length_message('Fnord') The length of 'Fnord' is 5 >>> length_message([1,2,3]) The length of [1, 2, 3] is 3 #7.1.2 封装 #7.1.3 继承 #7.2 类和类型 #7.2.1 类到底是什么 #7.2.3 创建自己的类 >>> __metaclass__ = type #确定使用新式类 >>> class 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 ... >>> foo = Person() >>> bar = Person() >>> foo.setName('Luke Skywalker') >>> bar.setName('Anakin Skywalker') >>> foo.greet() Hello, world! I'm Luke Skywalker. >>> bar.greet() Hello, world! I'm Anakin Skywalker. >>> foo.name 'Luke Skywalker' >>> bar.name 'Anakin Skywalker' >>> bar.name='Yoda' >>> bar.greet() Hello, world! I'm Yoda. >>> Person.greet(bar) Hello, world! I'm Yoda. >>> Person.greet(foo) Hello, world! I'm Luke Skywalker. >>> #7.2.3 特性, 函数和方法 >>> 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 <function function at 0x00BB2830> >>> def my_func(): ... print "I don't..." ... >>> instance.method=my_func >>> instance.method <function my_func at 0x00BB28F0> >>> >>> class Bird: ... song = 'Squaark!' ... def sing(self): ... print self.song ... >>> bird=Bird() >>> bird.sing() Squaark! >>> birdsong = bird.sing >>> birdsong() Squaark! >>> >>> class Secretive: ... def __inaccessible(self): ... print "Bet your can't see me..." ... # 类的内部定义中, 所有以双下划线开始的名字都被"翻译"为前加 单下划线 和 类名 的形式 # 如果想让其他对象不要访问内部数据, 那么可以使用单下划线 # 前面有下划线的名字都不会被带星号的imports语句(from module import *) 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.__inaccessibl() #python tt.py #Traceback (most recent call last): # File "tt.py", line 9, in <module> # s.__inaccessibl() #AttributeError: Secretive instance has no attribute '__inaccessibl' s.accessible() #The secret message is: #Bet you can't see me... Secretive._Secretive__inaccessible s._Secretive__inaccessible() #Bet you can't see me... #7.2.4 类的命名空间 >>> class C: ... print 'Class C being defined...' ... Class C being defined... >>> class MemberCounter: members = 0; def init(self): MemberCounter.members +=1 m1 = MemberCounter() m1.init() print MemberCounter.members m2 = MemberCounter() m2.init() print MemberCounter.members print m1.members print m2.members m1.members = 'Two' print m1.members print m2.members print MemberCounter.members #python tta.py #1 #2 #2 #2 #Two #2 #2 #7.2.5 指定超类 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): #SPAMFilter is subclass of Filter def init(self): # over-write init method from Filter self.blocked = ['SPAM'] f = Filter() f.init() print f.filter([1,2,3]) #python ttb.py #[1, 2, 3] s = SPAMFilter() s.init() print s.filter(['SPAM', 'SPAM', 'SPAM', 'SPAM', 'eggs', 'bacon', 'SPAM']) #['eggs', 'bacon'] print issubclass(SPAMFilter, Filter) print issubclass(Filter, SPAMFilter) #True #False print SPAMFilter.__bases__ print Filter.__bases__ #(<class __main__.Filter at 0x00AF7A78>,) #() print isinstance(s, SPAMFilter) print isinstance(s, Filter) print isinstance(s, str) #True #True #False print s.__class__ #__main__.SPAMFilter #7.2.6 调查继承 #多个超类 class Calculator: def calculate(self, expression): self.value = eval(expression) class Talker: def talk(self): print 'Hi, my value is', self.value class TalkingCalculator(Calculator, Talker): pass tc = TalkingCalculator() print tc.calculate('1+2*3') print tc.talk() print hasattr(tc, 'talk') print hasattr(tc, 'fnord') callable(getattr(tc, 'talk', None)) callable(getattr(tc, 'fnord', None)) setattr(tc, 'name', 'Mr. Gumby') print tc.name #python ttc.py #None #Hi, my value is 7 #None #True #False #Mr. Gumby #7.2.8 接口和内省 # inspect模块 #一些关于面向对象设计的思考 #将属于一类的对象放在一起. 如果一个函数操纵一个全局变量, 那么二者最好都在类内作为特性和方法出现. #不要让对象过于亲密. 方法应该只关心自己实例的特性.让其他实例管理自己的状态. #要小心继承, 尤其是多重继承. 继承机制有时很有用, 但也会在某些情况下让事情变得过于复杂. 多继承难以正确使用, 更难以调试. #简单就好. 让你的方法小巧. 一般来说, 多数方法都应能在30秒内读完(以及理解). 尽量将代码行数控制在一页或一屏之内. #当考虑需要什么类以及类要有什么方法是, 应该尝试下面的方法. #(1)写下问题的描述(程序要做什么?), 把所有名词, 动词 和 形容词 加下划线 #(2)对于所有名词, 用作可能的类 #(3)对于所有动词, 用作可能的方法 #(4)对于所有形容词, 用作可能的特性 #(5)把所有方法和特性分配到类 #现在已经有了 面向对象模型 的草图了. 还可以考虑类和对象之间的关系(比如继承或协作)以及它们的作用, 可以用以下步骤精炼模型: #(1) 写下(或者想象)一系列的用例--也就是程序应用时的场景, 试着包括所有的功能 #(2) 一步步考虑每个用例, 保证模型包括所有需要的东西. 如果有些遗漏的话,就添加进来. 如果某处不太正确则修改. 继续, 知道满意为止. #7.4 小结 # 对象--对象包括特性和方法. 特性只是作为对象的一部分的变量, 方法则是存储在对象内的函数. (绑定的)方法和其他函数的区别在于方法总是将对象 # 作为自己的第一个参数, 这个参数一般称为self. # 类: 类代表对象的集合(或一类对象), 每个对象(实例)都有(属于)一个类. 类的主要任务是定义它的实例会用到的方法. # 多态: 多态是实现将不同类型和类的对象进行同样对待的特性--不需要知道对象属于哪个类就能调用方法 # 封装: 对象可以讲它们的内部状态隐藏(或封装)起来. 在一些语言中, 这意味着对象的状态(特性)只对自己的方法可用. 在Python中, 所有的特性 # 都是公开可用的, 但是程序员应该在直接访问对象状态时谨慎行事, 因为他们可能无意中使得这些特性在某些方面不一致. # 继承: 一个类可以是一个或多个类的子类. 子类从超类继承所有方法. 可以使用多个超类, 这个特性可以用来组成功能的正交部分(没有任何联系). 普通的实现 # 方式是使用核心的超类和一个或多个混合的超类. # 接口和内省: 一般来说, 对于对象不用探讨过深. 程序员可以靠多态调用自己需要的方法. 不过如果想要知道对象到底有什么方法和特性, 有些函数可以帮助 # 完成这项工作 # 面向对象设计: 完全理解你的问题域,并且创建容易理解的设计是很重要的. #7.4.1 新函数 # callable 确定对象是否可调用(比如函数或方法) # getattr(object, name[, default] 确定特性的值, 可选择提供默认值 # hasattr(object, name) 确定对象是否有给定的特性 # isinstance(object, class) 确定对象是否是类的实例 # issubclass(A, B) 确定A是否为B的子类 # random.choice(sequence) 从非空序列中随机选择元素 # setattr(object, name, value) 设定对象的给定特性为value # type(object) 返回对象的类型