摘要
经过前面的学习我们已经掌握了内建对象类型(函数 字符串 列表 元祖 字典)
以及内建函数和标准库的用法,还有定义函数的方法 。
next We are will Study 创建自己的对象(自定义对象)
类型或者叫做类的对象》》这是Python非常核心的概念。As we all known
Python 被称为面向对象的语言(SmallTalk 、C++、 Java、)
接下来 我们会介绍如何创建对象,以及多态、封装、方法、特性、超类以及继承的概念。
新知识很多,Now We Are Starting .
=========================================================================
对象最重要的优点:
多态:
意味着可以对不同类的对象使用相同的操作。
封装
对外部世界隐藏对象的工作细节
继承
以通用的类为基础建立专门的类的对象
术语:多态来自希腊语,意思是“有多种形式”。
多态意味着就算不知道变量所引用的对象类型是什么,还是能对它进行操作,而它也会根据对象(或类)类型的不同而表现出不同的行为。
- 让对象自己进行操作
多态和方法
绑定到对象特性上面的函数称为方法(method),
封装
可以不用关心对象是如何构建的而直接进行使用。
继承
它是另外一个懒惰(褒义)的行为。程序员不想把同一段代码输入好几次,
类和类型
类为种类或类型的同义词。从很多方面来说,这就是类—一种对象。
所有的对象都属于一个类,称为类的实列(instance)。
鸟类(所有鸟的集合)具有很多子类(百灵鸟类)子类(subclass)
故:鸟类为百灵鸟类的超类(Superclass)
在面向对象程序设计中,子类的关系是隐式的,因为一个类的定义取决于它所支持的方法。
类的所有(instance)都会包含这些方法,所以所有子类的所有实列都有这些方法。
定义子类:
只是个定义更多(也有可能是重载已经存在的方法的过程)。
Eg:
Bird(可能支持fly方法),而企鹅类(Penguin)可能会增加个Eatfish的方法。
当创建penguin类时。可能会想重写(override)超类的fly方法。对于penguin的实列来说,
这个方法要么什么也不做,要么就产生异常(因为企鹅不会飞)。
区别
在旧版本的python中,内奸的对象是基于类型的,自定义的对象则是基于类的。可以创建类但是不可以创建类型。
最近版本的Python中,游乐一定变化,基本类型和类之间的界限开始模糊了。可以创建内建类型的子类,而这些类型的行为更类似于类。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
创建自己的类
先来看一个简单的类!!
_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)
新式类:需要在模块或者脚本开始的地方放置赋值语句:
_metaclass_=typepyth
3.0之后已不存在旧式类。
接下来让我们创建一些实列看看:
foo=Person()
bar=Person()
foo.setName('ChengKaoAo')
bar.setName('MeiXuanZheng')
···
>特性、函数和方法
self参数事实上正是方法和函数的区别:
方法(更专业一点可以成为绑定方法)将它们的第一个参数绑定到所属的实列上,因此你无需显示提供参数。当然你也可以将特性绑定到一个普通函数上,这样就不会有特殊的self参数了。
再论私有化
默认情况下,程序可以从外部访问一个对象特性。
为了让方法或者特性变为私有(从外部无法访问),只要在它的名字前面加上双下划线即可:
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.accessible()
类的命名和空间
所有位于class语句中的代码都在特殊命名空间执行——类命名空间。这个命名空间可由类内所有成员访问。并不是所有python程序员都知道类的定义其实就是执行代码块
这一点非常有用,比如在类的定义区并不只限定只能使用def语句:
class C:
print ('Class C being defined:')
#继续>>>
class MemberCounter:
members=0
def init(self):
MemberCounter.menbers+=1
指定超类
子类可以扩展超类的定义。将其他类名写在class语句后的圆括号内可以指定超类:
#_*_ coding:utf8 _*_
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是Filter的子类
def init(self):#重写Filter超类中的init方法
self.blocked = ['SPAM']
f = Filter()
f.init()
print f.filter([1,2,3])
s = SPAMFilter()
s.init()
print s.filter(['SPAM','SPAM','SPAM','SPAM','eggs','bacon','SPAM'])
Run Result:
这里用提供新定义的方式重写了Filter的init定义。
filter方法的定义是从Filter类中拿过来的,所以不用重写它的定义。
第二个要点就是揭示了继承的用处:我们可以写一大堆不同的过滤类,全都从Filter继承,每一个我都可以使用已经实现的filter方法。
检查继承
如果想要查看一个类是否是否是另一个的子类,可以使用内建的issubclass函数:
# _*_ coding:utf8 _*_
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是Filter的子类
def init(self): # 重写Filter超类中的init方法
self.blocked = ['SPAM']
print issubclass(SPAMFilter, Filter)
print issubclass(Filter, SPAMFilter)
The Run Result
多个超类
一个类地基类可能会多于一个,EG:
子类(TalkingCalculator)自己不做任何事,它从自己的超类继承所有的行为。
它从Calculator类哪里继承Calculate方法,从Talke类哪里继承talk方法,这样它就成了会说话的
计算器(talking calculator)
这种行为叫做多重继承。除非非常熟悉,否则应尽量避免使用,因为有时会出现不可预见的麻烦,
# _*_ coding:utf8 _*_
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()
tc.calculate('1+2*3+1')
tc.talk()
当有2个相同名字的不同方法时,需要注意超类的顺序(在Class语句中),先继承的类中的方法会重写后继承的类中的方法,
接口和内省
“接口”的概念与多态有关。
在处理多态对象时,只要关心他的接口(或称“协议”)即可,也就是公开的方法和特征。
在Python中,不用显式地指定对象必须包含哪些方法才能作为参数接收。
一般来说只需要让对象符合当前的接口(就是实现当前的方法),但是还可以更灵活一些。
除了调用方法然后期待一切顺利之外,还可检查所需方法是否已经存在。
关于面向对象的思考
要点:
将属于一类的对象放在一起。如果一个函数操纵一个全局变量,那么两者最好都在类内作为特征和方法出现。
不要让对象过于亲密。方法应该只关心自己实例的特征。让其他实例管理自己的状态。
- 要小心继承,尤其是多重继承。继承机制有时很有用,但也会在某些情况下让事情变得过于复杂。多继承难以正确使用,更难以调试。
- 简单就好。让你的方法小巧。一般来说,多数方法都应该在30秒内被读完(以及理解),尽量将代码行数控制在一页或者一屏之内。
当考虑需要什么类以及类要有什么方法时,应该尝试下面的方法。
(1)写下问题的描述(程序要做什么),把所有名词、动词、形容词加下划线
(2)对于所有名词,用作可能的类。
(3)对于所有动词,用作可能的方法。
(4)对于所有形容词,用作可能的特性。
(5)把所有方法特性分配到类。
现在已经有了面向对象模型的草图了,还可以考虑类和对象之间的关系(比如继承或协作)
以及它们的作用,可以用以下步骤精炼模型。
(1)写下(想象)一系列使用实列,也就是程序应用时的场景,试着包括所有的功能。
(2)一步步考虑每个使用实列,保证每个模型包括所有需要的东西,如果有遗漏的话就添加进来,
如果某处不太正确则改正。继续,到满意为止。