1.python中的类与对象
1 Python中定义类的方式比较简单:2
3 class类名:4
5 类变量6
7 def __init__(self,paramers):8
9 def函数(self,...)10
11 …...12
13 其中直接定义在类体中的变量叫类变量,而在类的方法中定义的变量叫实例变量。类的属性包括成员变量和方法,其中方法的定义和普通函数的定义非常类似,但方法必须以self作为第一个参数。
举例:
1 >>>classMyFirstTestClass:2
3 class Spec="it is a test class"
4
5 def__init__(self,word):6
7 print"say"+word8
9 defhello(self,name):10
11 print"hello"+name12
13
View Code
在Python类中定义的方法通常有三种:实例方法,类方法以及静态方法。这三者之间的区别是实例方法一般都以self作为第一个参数,必须和具体的对象实例进行绑定才能访问,而类方法以cls作为第一个参数,cls表示类本身,定义时使用@classmethod;而静态方法不需要默认的任何参数,跟一般的普通函数类似.定义的时候使用@staticmethod。
1 >>>classMethodTest():2
3 count=04
5 defaddCount(self):6
7 MethodTest.count+=1
8
9 print"I am an instance method,my count is"+str(MethodTest.count),self10
11 @staticmethod12
13 defstaticMethodAdd():14
15 MethodTest.count+=1
16
17 print"I am a static methond,my count is"+str(MethodTest.count)18
19 @classmethod20
21 defclassMethodAdd(cls):22
23 MethodTest.count+=1
24
25 print"I am a class method,my count is"+str(MethodTest.count),cls26
27
28
29 >>>
30
31 >>>a=MethodTest()32
33 >>>a.addCount()34
35 Iam an instance method,my count is 1 <__main__.methodtest instanceat>
36
37 >>>MethodTest.addCount()38
39
40
41 Traceback(most recent call last):42
43 File"", line 1, in
44
45 MethodTest.addCount()46
47 TypeError:unbound method addCount() must be called with MethodTest instance asfirst argument (got nothing instead)48
49 >>>a.staticMethodAdd()50
51 Iam a static methond,my count is252
53 >>>MethodTest.staticMethodAdd()54
55 Iam a static methond,my count is356
57 >>>a.classMethodAdd()58
59 Iam a class method,my count is4 __main__.MethodTest60
61 >>>MethodTest.classMethodAdd()62
63 Iam a class method,my count is5 __main__.MethodTest
View Code
从上面的例子来看,静态方法和类方法基本上区别不大,特别是有Java编程基础的人会简单的认为静态方法和类方法就是一回事,可是在Python中事实是这样的吗?看下面的例子:
1 >>>MethodTest.classMethodAdd()2
3 Iam a class method,my count is5 __main__.MethodTest4
5 >>>classsubMethodTest(MethodTest):6
7 pass
8
9 >>>b=subMethodTest()10
11 >>>b.staticMethodAdd()12
13 Iam a static methond,my count is614
15 >>>b.classMethodAdd()16
17 Iam a class method,my count is7 __main__.subMethodTest18
19 >>>a.classMethodAdd()20
21 Iam a class method,my count is8 __main__.MethodTest22
23 >>>
View Code
如果父类中定义有静态方法a(),在子类中没有覆盖该方法的话,Sub.a()仍然指的是父类的a()方法。而如果a()是类方法的情况下,Sub.a()指向的是子类。@staticmethod只适用于不想定义全局函数的情况。
2.python的封装
面向对象程序设计中的术语对象(Object)基本上可以看做数据(特性)以及由一系列可以存取、操作这些数据的方法所组成的集合。传统意义上的“程序=数据结构+算法”被封装”掩盖“并简化为“程序=对象+消息”。对象是类的实例,类的抽象则需要经过封装。封装可以让调用者不用关心对象是如何构建的而直接进行使用。
一个简单的Python类封装如下:
1 _metaclass_=type #确定使用新式类
2 classAnimal:3
4 def __init__(self): #构造方法 一个对象创建后会立即调用此方法
5 self.Name="Doraemon"
6 printself.Name7
8 def accessibleMethod(self): #绑定方法 对外公开
9 print "I have a self! current name is:"
10 printself.Name11 print "the secret message is:"
12 self.__inaccessible()13
14 def __inaccessible(self): #私有方法 对外不公开 以双下划线开头
15 print "U cannot see me..."
16
17 @staticmethod18 defstaticMethod():19 #self.accessibleMethod() #在静态方法中无法直接调用实例方法 直接抛出异常
20 print "this is a static method"
21
22 def setName(self,name): #访问器函数
23 self.Name=name24
25 def getName(self): #访问器函数
26 returnself.Name27
28 name=property(getName,setName) #属性 可读可写
View Code
构造函数和析构函数
Python的构造函数有两种,__init__和__new__,__init__的调用不会返回任何值,在继承关系中,为了保证父类实例正确的初始化,最好显示的调用父类的__init__方法。与__init__不同,__new__实际是个类方法,以cls作为第一个参数。
如果类中同时定义了__init__和__new__方法,则在创建对象的时候会优先使用__new__.
class A(object):
def __init__(self):
print("in init")
def __new__(self):
print("in new")
A()
如果__new__需要返回对象,则会默认调用__init__方法。利用new创建一个类的对象的最常用的方法为:super(currentclass,cls).__new__(cls[, ...])
class A(object):
def __new__(cls):
Object = super(A,cls).__new__(cls)
print "in New"
return Object
def __init__(self):
print "in init"
class B(A):
def __init__(self):
print "in B's init"
B()
__new__构造函数会可变类的定制的时候非常有用,后面的小节中会体现。
Python由于具有垃圾回收机制,通常不需要用户显示的去调用析构函数,即使调用,实例也不会立即释放,而是到该实例对象所有的引用都被清除掉后才会执行。
>>>class P:
def__del__(self):
print"deleted"
>>>class S(P):
def__init__(self):
print'initialized'
def__del__(self):
P.__del__(self)
print"child deleted"
>>>a=S()
initialized
>>>b=a
>>>c=a
>>>id(a),id(b),id(c)
(18765704,18765704, 18765704)
>>>del a
>>>del b
>>>del c
deleted
childdeleted
>>>
3. Python中的继承
Python同时支持单继承与多继承,继承的基本语法为class新类名(父类1,父类2,..),当只有一个父类时为单继承,当存在多个父类时为多继承。子类会继承父类的所有的属性和方法,子类也可以覆盖父类同名的变量和方法。在传统类中,如果子类和父类中同名的方法或者属性,在查找的时候基本遵循自左到右,深度优先的原则。如下列:
1 >>>classA:2
3 defsayhi(self):4
5 print'I am A hi'
6
7 >>>classB:8
9 defsayhi(self):10
11 print'I am B Hi'
12
13
14
15 >>>classC(A,B):16
17 pass
18
19 >>>d=C()20
21 >>>d.sayhi()22
23 Iam A hi24
25 >>>B.sayhi(d)26
27 Iam B Hi
View Code
单继承
1 _metaclass_=type #确定使用新式类
2 classAnimal:3
4 def __init__(self):5 self.Name="Animal"
6
7 defmove(self,meters):8 print "%s moved %sm." %(self.Name,meters)9
10 class Cat(Animal): #Cat是Animal的子类
11
12 def __init__(self): #重写超类的构造方法
13 self.Name="Garfield"
14
15 ## def move(self,meters): #重写超类的绑定方法
16 ## print "Garfield never moves more than 1m."
17
18 classRobotCat(Animal):19
20 def __init__(self): #重写超类的构造方法
21 self.Name="Doraemon"
22
23 ## def move(self,meters): #重写超类的绑定方法
24 ## print "Doraemon is flying."
25
26 obj=Animal()27 obj.move(10) #输出:Animal moved 10m.
28
29 cat=Cat()30 cat.move(1) #输出:Garfield moved 1m.
31
32 robot=RobotCat()33 robot.move(1000) #输出:Doraemon moved 1000m.
View Code
多重继承
1 classAnimal:2
3 defeat(self,food):4 print "eat %s" %food5
6 classRobot:7
8 deffly(self,kilometers):9 print "flyed %skm." %kilometers10
11 class RobotCat(Animal,Robot): #继承自多个超类
12
13 def __init__(self):14 self.Name="Doraemon"
15
16 robot=RobotCat() #一只可以吃东西的会飞行的叫哆啦A梦的机器猫
17 printrobot.Name18
19 robot.eat("cookies") #从动物继承而来的eat
20
21 robot.fly(10000000) #从机器继承而来的fly
View Code
需要注意的地方,即如果一个方法从多个超类继承,那么务必要小心继承的超类(或者基类)的顺序:
1 classAnimal:2
3 defeat(self,food):4 print "eat %s" %food5
6 def move(self,kilometers): #动物的move方法
7 pass
8
9 classRobot:10
11 def move(self,kilometers): #机器的move方法
12 print "flyed %skm." %kilometers13
14 class RobotCat(Animal,Robot): #继承自多个超类 如方法名称相同,注意继承的顺序
15 #class RobotCat(Robot,Animal):
16 def __init__(self):17 self.Name="Doraemon"
18
19 robot=RobotCat() #一只可以吃东西的会飞行的叫哆啦A梦的机器猫
20 printrobot.Name21
22 robot.eat("cookies") #从动物继承而来的eat
23
24 robot.move(10000000) #本来是要从机器继承move方法,但是因为继承的顺序,这个方法直接继承自动物而pass掉
View Code
关于继承的构造函数:
1.如果子类没有定义自己的构造函数,父类的构造函数会被默认调用,但是此时如果要实例化子类的对象,则只能传入父类的构造函数对应的参数,否则会出错
classAddrBookEntry(object):
'addressbook entry class'
def__init__(self, nm, ph):
self.name= nm
self.phone= ph
print'Created instance for:', self.name
defupdatePhone(self, newph):
self.phone = newph
print'Updated phone# for:', self.name
classEmplAddrBookEntry(AddrBookEntry):
'EmployeeAddress Book Entry class'
defupdateEmail(self, newem):
self.email= newem
print'Updated e-mail address for:', self.name
john= EmplAddrBookEntry('John Doe', '408-555-1212')
printjohn.name
2.如果子类定义了自己的构造函数,而没有显示调用父类的构造函数,则父类的属性不会被初始化
classAddrBookEntry(object):
'addressbook entry class'
def__init__(self, nm, ph):
self.name= nm
self.phone= ph
print'Created instance for:', self.name
defupdatePhone(self, newph):
self.phone = newph
print'Updated phone# for:', self.name
classEmplAddrBookEntry(AddrBookEntry):
'EmployeeAddress Book Entry class'
def__init__(self, nm, ph, id, em):
#AddrBookEntry.__init__(self, nm,ph)
self.empid= id
self.email= em
defupdateEmail(self, newem):
self.email= newem
print'Updated e-mail address for:', self.name
john= EmplAddrBookEntry('John Doe', '408-555-1212',42, 'john@spam.doe')
printjohn.email
printjohn.empid
输出:
john@spam.doe
42
Traceback(most recent call last):
printjohn.name
AttributeError:'EmplAddrBookEntry' object has no attribute 'name'
3.如果子类定义了自己的构造函数,显示调用父类,子类和父类的属性都会被初始化
classAddrBookEntry(object):
'addressbook entry class'
def__init__(self, nm, ph):
self.name= nm
self.phone= ph
print'Created instance for:', self.name
defupdatePhone(self, newph):
self.phone = newph
print'Updated phone# for:', self.name
classEmplAddrBookEntry(AddrBookEntry):
'EmployeeAddress Book Entry class'
def__init__(self, nm, ph, id, em):
AddrBookEntry.__init__(self, nm,ph)
self.empid= id
self.email= em
defupdateEmail(self, newem):
self.email= newem
print'Updated e-mail address for:', self.name
john= EmplAddrBookEntry('John Doe', '408-555-1212',42, 'john@spam.doe')
printjohn.email
printjohn.empid
printjohn.name
4.python的多态
1 classcalculator:2 defcount(self, args):3 return 1
4
5
6 calc = calculator() #自定义类型
7
8 from random importchoice9
10 obj = choice(['hello,world', [1, 2, 3], calc]) #obj是随机返回的 类型不确定
11 print(type(obj))12 print(obj.count('a'))#方法多态
View Code
对于一个临时对象obj,它通过Python的随机函数取出来,不知道具体类型(是字符串、元组还是自定义类型),都可以调用count方法进行计算,至于count由谁(哪种类型)去做怎么去实现我们并不关心。
1 #!/usr/bin/env python
2 #-*- coding:utf-8 -*-
3 classDuck:4 defquack(self):5 print("Quaaaaaack!")6
7 deffeathers(self):8 print("The duck has white and gray feathers.")9
10
11 classPerson:12 defquack(self):13 print("The person imitates a duck.")14
15 deffeathers(self):16 print("The person takes a feather from the ground and shows it.")17
18
19 defin_the_forest(duck):20 duck.quack()21 duck.feathers()22
23
24 defgame():25 donald =Duck()26 john =Person()27 in_the_forest(donald)28 in_the_forest(john)29
30
31 game()
View Code
就in_the_forest函数而言,参数对象是一个鸭子类型和person类型,它实现了两个类型的相同名称的方法,打印的内容不一样,只是因为
下面是运算符号(方法)的多态
1 defadd(x,y):2 return x+y3
4 print add(1,2) #输出3
5
6 print add("hello,","world") #输出hello,world
7
8 print add(1,"abc") #抛出异常 TypeError: unsupported operand type(s) for +: 'int' and 'str'
View Code