面向对象的概念及延伸
概念
Python使用类(class)和对象(object),进行面向对象(object-oriented programming,简称OOP)的编程。
可以理解为对象(object)即属性相近的东西,再进行归类(class)命名。
建立一个对象
1 class name(object): #定义名称为name的类,object为对象 2 attribute1 #定义name类的属性1 3 attribute2 #定义name类的属性2
说明:
1.对象为object命名为name的类class。
2.括号中为object时,表示这个类为最大的父类(到顶了)。
3.引用对象的属性为:object.attribute。
举例:
1 #定义一个鸟类 2 class Bird(object): #定义了一个类别(class),就是鸟(Bird) 3 have_feather = True #属性1,有羽毛 4 way_of_reproduction = 'egg' #属性2,产卵生殖方式 5 6 summer = Bird() #summer为小鸡,使用前面定义的鸟类 7 print summer.way_of_reproduction #使用对象.属性调用 8 9 10 #新增移动的方法-move 11 class Bird(object): 12 have_feather = True 13 way_of_reproduction = 'egg' 14 def move(self, dx, dy): #类的内部定义move方法 15 position = [0,0] #注意是list,所以使用[] 16 position[0] = position[0] + dx 17 position[1] = position[1] + dy 18 return position #返回dx,dy移动的结果值 19 summer = Bird() 20 print 'after move:',summer.move(5,8) 21 summer.move(5,8) #回顾下函数,可以直接输出结果,同上一步 22 23 24 #Chicken/Oriole继承Bird 25 class Chicken(Bird): #新定义小鸡类,继承于Bird类 26 way_of_move = 'walk' #小鸡类属性1,移动方式 27 possible_in_KFC = True #小鸡类属性2,KFC是否存在 28 29 class Oriole(Bird): #新定义黄鹂类,同样继承于Bird类 30 way_of_move = 'fly' #黄鹂类属性1,移动方式 31 possible_in_KFC = False #黄鹂类属性2,KFC是否存在 32 33 summer = Chicken() #summer使用小鸡类,小鸡继承鸟类,summer具备鸟类的属性 34 print summer.have_feather #调用鸟类的属性1 35 print summer.move(5,8) #调用鸟类的移动方法
小结:
1.有一只小鸡叫summer,它是个对象,且属于鸟类。我们使用开头定义的鸟类。
2.summer = Bird()为创建对象,并说明summer是类别鸟中的一个对象,summer就有了鸟的类属性。对属性的引用是通过对象.属性(object.attribute)的形式实现。
3.对于类的内部定义方法。区别与直接定义函数,它的参数中有一个self,它是为了方便我们引用对象自身,self代表了根据类定义而创建的对象。方法的第一个参数必须是self,无论是否用到。
4.类别可以细分为子类,子类可以通过继承(inheritance)获得父类的全部属性。
5.类定义括号中写了(bird),说明了Chicken是属于鸟类(bird)的一个子类,即Chicken继承自Bird。Bird就是Chicken的父类,Chicken将享有Bird的所有属性。
类的内部定义方法延伸
上面我们说到,对于类的内部定义方法第一个参数必须是self,我们实践一下。
1 class Human(object): #定义一个Human类 2 laugh = 'hahahaha' #属性laugh 3 def show_laugh(self): #定义show_laugh方法 4 print self.laugh #调用Human类属性并且输出 5 def laugh_100th(self): #定义laugh_100th方法 6 for i in range(100): #for循环100次 7 self.show_laugh() #调用show_laugh()方法 8 li_lei = Human() #li_lei为对象 9 li_lei.laugh_100th() #输出laugh_100th()结果
主要通过类和方法输出100次hahahaha。
想去掉show_laugh方法,直接用laugh_100th去实现。
实践一:
1 class Human(object): 2 laugh = 'hahahaha' 3 def laugh_100th(self): 4 for i in range(100): 5 self.laugh() #self.laugh()是错误的写法,实践二中会改正 6 7 8 >>> meng = Human() 9 >>> print (meng.laugh_100th) #输出错误,正确调用格式为meng.laugh_100th() 10 <bound method Human.laugh_100th of <__main__.Human object at 0x0000000002E75B70>> 11 >>> print (meng.laugh_100th()) #laugh_100th不可被调用 12 13 Traceback (most recent call last): 14 File "<pyshell#96>", line 1, in <module> 15 print (meng.laugh_100th()) 16 File "<pyshell#93>", line 5, in laugh_100th 17 self.laugh() 18 TypeError: 'str' object is not callable
19 class Human(object): 20 laugh = 'hahahaha' 21 def laugh_100th(self): 22 for i in range(100): 23 print self.laugh() #错误写法 24 25 26 >>> meng = Human() 27 >>> meng.laugh_100th() #错误调用 28 29 Traceback (most recent call last): 30 File "<pyshell#100>", line 1, in <module> 31 meng.laugh_100th() 32 File "<pyshell#98>", line 5, in laugh_100th 33 print self.laugh() 34 TypeError: 'str' object is not callable
35 class Human(object): 36 laugh = 'hahahaha' 37 def laugh_100th(self): 38 for i in range(100): 39 self.laugh() 40 print self.laugh() #错误写法 41 42 43 >>> meng = Human() 44 >>> meng.laugh_100th() #错误调用 45 46 Traceback (most recent call last): 47 File "<pyshell#105>", line 1, in <module> 48 meng.laugh_100th() 49 File "<pyshell#103>", line 5, in laugh_100th 50 self.laugh() 51 TypeError: 'str' object is not callable
分析:
报错:TypeError: 'str' object is not callable
字面意思为str不可被系统调用,就是正在调用一个不能被调用的变量或对象,具体表现就是你调用函数、变量的方式错误。
laugh为类属性,正确调用为self.laugh,而不是self.laugh()。
实践二:
1 class Human(object): 2 laugh = 'hahahaha' 3 def laugh_100th(self): 4 for i in range(100): 5 self.laugh #调用Human类属性,self.laugh写法正确 6 7 8 >>> li = Human() 9 >>> print li.laugh_100th() #函数无return值,并且内部无输出,返回结果为None 10 None
13 class Human(object): 14 laugh = 'hahahaha' 15 def laugh_100th(self): 16 for i in range(100): 17 self.laugh 18 print self.laugh #输出self.laugh值 19 20 21 >>> li = Human() 22 >>> li.laugh_100th() #输出一次结果值 23 hahahaha
分析:
在函数laugh_100th()中,for循环调用Human属性laugh,print在for循环的外层,输出时函数执行结束。
实践三:
1 class Human(object): 2 laugh = 'hahahaha' 3 def laugh_100th(self): 4 for i in range(100): 5 print self.laugh #直接在for循环中输出结果 6 7 8 >>> li = Human() 9 >>> li.laugh_100th() #正确输出100次结果 10 hahahaha 11 hahahaha 12 ... 13 hahahaha 14 hahahaha
分析:
把print放在for循环内层直接输出结果,for循环并未停止,所以可以循环100次。
直接li.laugh_100th() 调用,无None值返回。
实践四:
1 class Human(object): 2 laugh = 'hahahaha' 3 def laugh_100th(self): 4 for i in range(100): 5 return self.laugh #把实践三的print修改为return 6 7 8 >>> wang = Human() 9 >>> print (wang.laugh_100th()) #输出一次结果值 10 hahahaha
11 class Human(object): 12 laugh = 'hahahaha' 13 def laugh_100th(self): 14 for i in range(100): 15 self.laugh 16 return #再修改为return放在外部 17 18 19 >>> wang = Human() 20 >>> print (wang.laugh_100th()) #return后无值,返回None 21 None 22 >>> wang.laugh_100th() #直接调用,无结果值 23 >>>
分析:
1.把实践三的print修改为return,只返回一次结果值。因为执行到return时,函数停止执行函数内余下的语句。(复习一下函数总结)
2.把return放在外部,又变成了return后无返回值的场景。输出结果为None。
综上,正确输出为实践三。
__init__方法
__init__()是一个特殊方法(special method)。Python有一些特殊方法。Python会特殊的对待它们。特殊方法的特点是名字前后有两个下划线。
如果你在类中定义了__init__()这个方法,创建对象时,Python会自动调用这个方法。这个过程也叫初始化。
--大神总结的话少一句都不行。
1 class happyBird(Bird): 2 def __init__(self,more_words): #self后面要有变量值 3 print more_words #输出more_words
4 xiu = happyBird('ha') #输出格式,结果值为ha
我们创建xiu对象,__init__()方法被自动调用。最后一行的语句(xiu= happyBird...)先创建了对象,然后执行:
xiu.__init__(more_words)
'ha' 被传递给了__init__()的参数more_words
输出规范一点:
1 class happyBird(Bird): 2 def __init__(self,more_words): 3 print 'We are happy birds.',more_words 4 xin = happyBird('ha') #We are happy birds. ha
我们可以尝试用__init__方法输出实践中100次haha。
这是实践三:
1 class Human(object): 2 laugh = 'hahahaha' 3 def laugh_100th(self): 4 for i in range(100): 5 print self.laugh 6 7 8 >>> li = Human() 9 >>> li.laugh_100th() 10 hahahaha 11 hahahaha 12 ...13 hahahaha
__init__方法实现:
1 class human(object): 2 def __init__(self,laugh): #定义laugh 3 for i in range(100): 4 print laugh #输出laugh值 5 6 li = human('haha') #调用输出100次haha 7 ha 8 ha 9 ... 10 ha
对象的性质
我们讲到了许多属性,但这些属性是类的属性。所有属于该类的对象会共享这些属性。比如说,鸟都有羽毛,鸡都不会飞。
在一些情况下,我们定义对象的性质,用于记录该对象的特别信息。比如说,人这个类。性别是某个人的一个性质,不是所有的人类都是男,或者都是女。这个性质的值随着对象的不同而不同。李雷是人类的一个对象,性别是男;韩美美也是人类的一个对象,性别是女。
当定义类的方法时,必须要传递一个self的参数。这个参数指代的就是类的一个对象。我们可以通过操纵self,来修改某个对象的性质。比如用类来新建一个对象,即下面例子中的li_lei, 那么li_lei就被self表示。我们通过赋值给self.attribute,给li_lei这一对象增加一些性质,比如说性别的男女。self会传递给各个方法。在方法内部,可以通过引用self.attribute,查询或修改对象的性质。
这样,在类属性的之外,又给每个对象增添了各自特色的性质,从而能描述多样的世界。
1 class Human(object): 2 def __init__(self, input_gender): 3 self.gender = input_gender #self.attribute赋值 4 def printGender(self): 5 print self.gender #调用self.attribute 6 7 li_lei = Human('male') #这里,'male'作为参数传递给__init__()方法的input_gender变量 8 print li_lei.gender 9 li_lei.printGender()
在初始化中,将参数input_gender,赋值给对象的性质,即self.gender。
li_lei拥有了对象性质gender。gender不是一个类属性。Python在建立了li_lei这一对象之后,使用li_lei.gender这一对象性质,专门储存属于对象li_lei的特有信息。
对象的性质也可以被其它方法调用,调用方法与类属性的调用相似,正如在printGender()方法中的调用。
其他:
如果在语句7输入后,直接输出结果值的话,需要在语句3后加上print。如下。
2 ... 3 self.gender = input_gender 4 print self.gender #输出结果值 5 def printGender(self): 6 ...
因为我们在调用__init__时,函数中没有输出结果值。
参考下列写法:
1 class Human(object): 2 laugh = 'hahahaha' 3 def show_laugh(self): 4 print self.laugh #调用Human类属性值并且输出 5 def laugh_100th(self): 6 for i in range(100): 7 self.show_laugh() #调用show_laugh方法 8 li_lei = Human() 9 li_lei.laugh_100th()
本章小结:
1.self可以调用类属性,格式为self.attribute;self也可以改变对象的性质,通过赋值给self.attribute实现。
2.__init__()在建立对象时自动执行,self后必须带有变量值。