# coding:utf-8程序员
#-------------------------------------------------- 对象魔力 -----------------------------------------express
#多态app
#多态方法dom
print 'abc'.count('a')ide
#1函数
print [1, 2, 'a'].count('a')工具
#1spa
#不用关心count('a')里面是什么类型数据,只要知道count方法,能够返回a出现多少次,就好了,这就是多态方法设计
#choice函数,能够从序列中随机选出元素。对象
from random import choice
x = choice(['Hello, world!', [1, 2, 'e', 'e', 4]])
#x多是Hello,world字符串,多是[1, 2, 'e', 'e', 4]列表,不用关心究竟是哪一个类型,只要关心变量x中字符e出现了多少次。无论x是字符串仍是列表,均可以使用count函数。
print x.count('e')
#2 #本例中,看来列表胜出了。
#多态多种形式
#当面对对象不知道是什么类型,但又要对对象作些何时,就会用到多态
#这不只限于方法,不少内建运算符和函数都有多态的性质。好比:
print 1 + 2
#3
print 'Fish' + 'license'
#Fishlicense
#这里的加运算符对于数字和字符串都能起做用。
#为说明这一点,假设有个叫作add的函数,它能够将两个对象相加。能够直接将其定义成上面的形式。
def add(x, y):
return x+y
#对于不少类型的参数均可以用:
print add(1, 2)
#3
print add('Fish', 'license')
#Fishlicense
#若是须要编写打印对象长度消息的函数,只需对象具备长度(len函数可用)便可。
def length_message(x):
print "The length of", repr(x), "is", len(x)
#能够看到,函数中还使用了repr函数,repr函数是多态特性。
length_message('Fnord')
#The length of 'Fnord' is 5
length_message([1, 2, 3])
#The length of [1, 2, 3] is 3
#不少函数和运算符都是多态的---你写的绝多数程序可能都是,即使你并不是有意这样。只要使用多态函数和运算符,就会与“多态”发生关联。
#事实上,惟一能毁掉多态的就是使用函数检查类型,好比type,isinstance以及issubclass函数等。
#若是可能的话,应该尽力避免使用这些毁掉多态的方式。真正重要的是如何让对象按照你所但愿的方式工做,无论它是不是正确的类型(或者类)。
#封装
#封装是指向程序中的其余部分隐藏对象的具体实现细节原则。
#接下面再论私有化进行详细解释
#继承
#就是函数,类等调用,相同代码不想重复写,直接调用给其余代码,就是继承。
#-------------------------------------------- 类和类型 ------------------------------------------
#建立类
__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
#这个例子包含3个方法定义,除了它们是写在class语句里,一切都像是函数定义。Person是类的名字。class语句会在函数定义的地方建立本身的命名空间。
#self参数看起来有点奇怪,它是对于对象自身的引用。那么它是什么对象?建立一些实例看看:
foo = Person()
bar = Person()
foo.setName('Luke Skywalker') #foo将本身为第一个参数传入到self里
bar.setName('Anakin Skywalker')
foo.greet()
#Hello, world! I'm Luke Skywalker.
bar.greet()
#Hello, world! I'm Anakin Skywalker.
#在调用foo的setName和greet函数时,foo自动将本身做为第一个参数传入函数中---所以形象地命名为self。对于这个变量,每一个人可能都会有本身的叫法,可是由于它老是对象本身,因此习惯上老是叫作self
#显然这就是self的用处和存在的必要性。没有它的话,成员方法就无法访问它们要对其特性进行操做的对象自己了。
#特性能够在外部访问:
#就是setName函数里的self.name = name
print foo.name
#Luke Skywalker
bar.name = 'Yoda'
bar.greet()
#Hello, world! I'm Yoda.
#若是知道foo是Person的实例的话,那么能够把foo.greet()写成:
Person.greet(foo) #方便的简写
#Hello, world! I'm Luke Skywalker.
#特性,函数,方法
__metaclass__ = type
class Class:
def method(self):
print 'I have a self!'
def function():
print "I don't..."
instance = Class() #调用类
instance.method() #instance是实例,method是方法,有self参数
#I have a self!
instance.method = function #绑定到一个普通函数上,没有self参数
instance.method()
#I don't...
__metaclass__ = type
class Bird:
song = 'Squaawk!'
def sing(self):
print self.song
bird = Bird()
bird.sing()
#Squaawk!
birdsong = bird.sing
birdsong() #调用方法和函数十分类似,但变量绑定方法bird.sing仍是会对self参数进行访问
#Squaawk!
#再论私有化,接上面的封装
#使用上面类的例子:
__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
o = Person() #调用类
o.setName('Sir Lancelot')
print o.getName()
#Sir Lancelot
#变量o绑定到对象(Person类)上,可使用setName和getName方法。一切看起来很完美。可是假设变量o将它的名字存储在全局变量globalName中:
#但假设变量o将它的名字存储在全局变量globalName中:
#globalName
#'Sir Lancelot'
#这意味着在使用OpenObject类的实例时候,不得不关心globalName的内容。实际上要确保不会对它进行任何更改:
#globalName = 'Sir Gumby'
#o.getName()
#'Sir Gumby'
#若是建立了多个OpenObject实例的话就会出现问题,由于变量相同,因此可能会混淆:
#o1 = OpenObject()
#o2 = OpenObject()
#o1.setName('Robin Hood')
#o2.getName()
#'Robin Hood'
#设定一个名字后,其余名字也自动设定了。
#为了让方法或者特性变成私有(外部没法访问),只要在它的名字前面加上双下划线便可。
__metaclass__ = type
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() #报错没法调用
s.accessible() #内部能够调用
#The secret message is:
#Bet you can`t see me...
s._Secretive__inaccessible() #也有外部调用方法,但不该该这么作
#Bet you can`t see me...
#类的命名空间
__metaclass__ = type
class MemberCounter:
members = 0
def init(self):
MemberCounter.members += 1
#上面代码中,在类做用域内定义了一个可供全部成员(实例)访问的变量(members),用来计算类的成员数量。注意init用来初始化全部实例。
m1 = MemberCounter() #调用类
m1.init()
print MemberCounter.members
#1
m2 = MemberCounter()
m2.init()
print MemberCounter.members
#2
#类做用域内的变量也能够被全部实例访问:
print m1.members
#2
print m2.members
#2
m1.members = 'Two' #新的numbers值被写到了m1特性中,屏蔽了类范围内的变量。这跟函数内的局部和全局变量的行为十分相似。
print m1.members
#Two
print m2.members
#2
#指定超类
__metaclass__ = type
class Filter: #写一个过滤做用的类(超类)
def init(self):
self.blocked = []
def filter(self, sequence):
return [x for x in sequence if x not in self.blocked] # 如何理解这句话,同等于下面注释
# l = []
# for x in sequence:
# if x not in self.blocked:
# l.append(x)
# return l
#Filter是个用于过滤序列的通用类,事实上它自身不能过滤任何东西
f = Filter()
f.init()
print f.filter([1, 2, 3])
#[1, 2, 3]
#Filter类的用处在于它能够用做其余类的(基类)超类,好比下面SPAMFilter类,能够将序列中的'SPAM'过滤出去。
class SPAMFilter(Filter): #继承上面的类,能够不用写一大堆过滤的类,从上面继承更加方便。SPAMFilter是Filter的子类,Filter是SPAMFilter的超类
def init(self): #重写超类Filter中的init方法
self.blocked = ['SPAM'] #原本过滤关键字没写,如今写入SPAM
s = SPAMFilter()
s.init()
print s.filter(['SPAM','SPAM','SPAM','eggs','bacon','SPAM'])
#['eggs', 'bacon']
#检查继承
#若是想要查看一个类是不是另一个的子类,可使用内建的issubclass的函数:
print issubclass(SPAMFilter, Filter) #查看SPAMFilter是不是Failter的子类
#True
print issubclass(Filter, SPAMFilter)
#False
#若是想要知道已知类的基类(们)(注意下节解释),可使用特殊特性__bases__:
print SPAMFilter.__bases__ #已知类的基类,使用__bases__
#(<class '__main__.Filter'>,)
print Filter.__bases__
#(<type 'object'>,)
#使用isinstance方法检查一个对象是不是一个类的实例:
s = SPAMFilter()
print isinstance(s, SPAMFilter)
#True
print isinstance(s, Filter)
#True
print isinstance(s, str)
#False
#想知道一个对象属于哪一个类,可使用__class__特性
print s.__class__
#<class '__main__.SPAMFilter'>
#多个超类
#上节提到一个类的基类(们),也就暗示它的基类可能会多于一个。事实上就是这样,创建几个新类来试试:
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
#子类(TalkingCalculator)本身不作任何事,它从本身的超类继承全部的行为。它从Calculator类那里继承calculate方法,从Talker类那里继承talk方法,这样它就成了会说话的计算器。
tc = TalkingCalculator()
tc.calculate('1+2*3')
tc.talk()
#Hi, my value is 7
#这种行为称为多重继承,是个很是有用的工具。但除非特别熟悉多重继承,不然应该尽可能避免使用,由于有些时候会出现不可预见的麻烦。
#须要注意是若是一个方法从多个超类继承(也就是说有两个具备相同名字的不一样方法),那么必须注意下超类的顺序(在class语句中):先继承的类中的方法会重写后继承的类中的方法。
#若是前例中Calculator:类也有个叫talk方法(函数),那么它会覆盖Talker的talk方法(使其没法访问)。若是把它们顺序掉过来,像下面这样:
#class TalkingCalculator(Talker, Calculator): pass
#就会让Talker的talk方法可用了。
#接口和内省
#能够查看方法是否存在(接口)
print hasattr(tc, 'talk')
#True
print hasattr(tc, 'fnord')
#False
#小结
#对象
#对象包括特性和方法。特性只是做为对象的一部分的变量,方法则是存储在对象内的函数。(绑定)方法和其余函数的区别在于方法老是将对象做为本身的第一个参数,这个参数通常称为self。
#类
#类表明对象的集合(或一类对象),每一个对象(实例)都有一个类。类的主要任务是定义它的实例会用到方法。
#多态
#多态是实现将不一样类型和类的对象进行一样对待的特性---不须要知道对象属于哪一个类就能调用的方法。
#封装
#对象能够将它们的内部状态隐藏(或封装)起来。在一些语言中,这意味着对象的状态(特性)只对本身的方法可用。在Python中,全部的特性都是公开可用的,可是程序员应该在直接访问对象状态时谨慎行事,由于他们可能无心中使得这些特性在某些方面不一致。
#继承
#一个类能够是一个或者多个类的子类。子类从超类继承全部方法。可使用多个超类,这个特性能够用来组成功能的正交部分(没有任何联系)。普通的实现方式是使用核心的超类和一个或者多个混合的超类。
#接口和内省
#通常来讲,对于对象不用探讨过深。程序猿能够靠多态调用本身须要的方法。不过若是想要知道对象到底有什么方法和特性,有些函数能够帮助完成这项工做。
#面向对象设计
#关于如何(或者说是否应该进行)面向对象设计有不少的观点。无论你持什么观点,彻底理解这个问题,而且建立容易理解的设计是很重要的。