python之面向对象编程浅谈

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 >>>class MyFirstTestClass:
 2 
 3 class Spec="it is a test class"
 4 
 5 def__init__(self,word):
 6 
 7 print"say "+word
 8 
 9 def hello(self,name):
10 
11 print"hello "+name
12 
13  
View Code

在Python类中定义的方法通常有三种:实例方法,类方法以及静态方法。这三者之间的区别是实例方法一般都以self作为第一个参数,必须和具体的对象实例进行绑定才能访问,而类方法以cls作为第一个参数,cls表示类本身,定义时使用@classmethod;而静态方法不需要默认的任何参数,跟一般的普通函数类似.定义的时候使用@staticmethod

 1 >>>class MethodTest():
 2 
 3 count= 0
 4 
 5 defaddCount(self):
 6 
 7 MethodTest.count+=1
 8 
 9 print"I am an instance method,my count is"+str(MethodTest.count),self
10 
11 @staticmethod
12 
13 defstaticMethodAdd():
14 
15 MethodTest.count+=1
16 
17 print"I am a static methond,my count is"+str(MethodTest.count)
18 
19 @classmethod
20 
21 defclassMethodAdd(cls):
22 
23 MethodTest.count+=1
24 
25 print"I am a class method,my count is"+str(MethodTest.count),cls
26 
27  
28 
29 >>>
30 
31 >>>a=MethodTest()
32 
33 >>>a.addCount()
34 
35 Iam an instance method,my count is 1 <__main__.MethodTest instanceat 0x011EC990>
36 
37 >>>MethodTest.addCount()
38 
39  
40 
41 Traceback(most recent call last):
42 
43 File"<pyshell#5>", line 1, in <module>
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 is2
52 
53 >>>MethodTest.staticMethodAdd()
54 
55 Iam a static methond,my count is3
56 
57 >>>a.classMethodAdd()
58 
59 Iam a class method,my count is4 __main__.MethodTest
60 
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__.MethodTest
 4 
 5 >>>class subMethodTest(MethodTest):
 6 
 7 pass
 8 
 9 >>>b=subMethodTest()
10 
11 >>>b.staticMethodAdd()
12 
13 Iam a static methond,my count is6
14 
15 >>>b.classMethodAdd()
16 
17 Iam a class method,my count is7 __main__.subMethodTest
18 
19 >>>a.classMethodAdd()
20 
21 Iam a class method,my count is8 __main__.MethodTest
22 
23 >>>
View Code

如果父类中定义有静态方法a(),在子类中没有覆盖该方法的话,Sub.a()仍然指的是父类的a()方法。而如果a()是类方法的情况下,Sub.a()指向的是子类。@staticmethod只适用于不想定义全局函数的情况。

2.python的封装

面向对象程序设计中的术语对象(Object)基本上可以看做数据(特性)以及由一系列可以存取、操作这些数据的方法所组成的集合。传统意义上的“程序=数据结构+算法”被封装”掩盖“并简化为“程序=对象+消息”。对象是类的实例,类的抽象则需要经过封装。封装可以让调用者不用关心对象是如何构建的而直接进行使用。

一个简单的Python类封装如下:

 1 _metaclass_=type # 确定使用新式类
 2 class Animal:
 3 
 4     def __init__(self): #构造方法 一个对象创建后会立即调用此方法
 5         self.Name="Doraemon"
 6         print self.Name
 7       
 8     def accessibleMethod(self): #绑定方法 对外公开
 9         print "I have a self! current name is:"
10         print self.Name
11         print "the secret message is:"
12         self.__inaccessible()
13         
14     def __inaccessible(self): #私有方法 对外不公开 以双下划线开头
15         print "U cannot see me..."
16 
17     @staticmethod
18     def staticMethod():
19         #self.accessibleMethod() #在静态方法中无法直接调用实例方法 直接抛出异常
20         print "this is a static method"
21 
22     def setName(self,name): #访问器函数
23         self.Name=name
24 
25     def getName(self): #访问器函数
26         return self.Name
27 
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 >>>class A:
 2 
 3 defsayhi(self):
 4 
 5 print'I am A hi'
 6 
 7 >>>class B:
 8 
 9 defsayhi(self):
10 
11 print'I am B Hi'
12 
13 
14 
15 >>>class C(A,B):
16 
17 pass
18 
19 >>>d=C()
20 
21 >>>d.sayhi()
22 
23 Iam A hi
24 
25 >>>B.sayhi(d)
26 
27 Iam B Hi
View Code

 单继承

 1 _metaclass_=type # 确定使用新式类
 2 class Animal:
 3 
 4     def __init__(self): 
 5         self.Name="Animal"
 6       
 7     def move(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 class RobotCat(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 class Animal:
 2   
 3     def eat(self,food):
 4         print "eat %s" %food 
 5         
 6 class Robot:
 7       
 8     def fly(self,kilometers):
 9         print "flyed %skm." %kilometers 
10         
11 class RobotCat(Animal,Robot): #继承自多个超类
12 
13     def __init__(self):  
14         self.Name="Doraemon"
15 
16 robot=RobotCat() # 一只可以吃东西的会飞行的叫哆啦A梦的机器猫
17 print robot.Name
18 
19 robot.eat("cookies") #从动物继承而来的eat
20 
21 robot.fly(10000000) #从机器继承而来的fly
View Code

需要注意的地方,即如果一个方法从多个超类继承,那么务必要小心继承的超类(或者基类)的顺序:

 1 class Animal:
 2   
 3     def eat(self,food):
 4         print "eat %s" %food
 5 
 6     def move(self,kilometers): #动物的move方法
 7         pass
 8         
 9 class Robot:
10       
11     def move(self,kilometers): #机器的move方法
12         print "flyed %skm." %kilometers 
13         
14 class RobotCat(Animal,Robot): #继承自多个超类 如方法名称相同,注意继承的顺序
15 #class RobotCat(Robot,Animal): 
16     def __init__(self):  
17         self.Name="Doraemon"
18 
19 robot=RobotCat() # 一只可以吃东西的会飞行的叫哆啦A梦的机器猫
20 print robot.Name
21 
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 class calculator:
 2     def count(self, args):
 3         return 1
 4 
 5 
 6 calc = calculator()  # 自定义类型
 7 
 8 from random import choice
 9 
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 class Duck:
 4     def quack(self):
 5         print("Quaaaaaack!")
 6 
 7     def feathers(self):
 8         print("The duck has white and gray feathers.")
 9 
10 
11 class Person:
12     def quack(self):
13         print("The person imitates a duck.")
14 
15     def feathers(self):
16         print("The person takes a feather from the ground and shows it.")
17 
18 
19 def in_the_forest(duck):
20     duck.quack()
21     duck.feathers()
22 
23 
24 def game():
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 def add(x,y):
2     return x+y
3 
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

 

 

原文地址:https://www.cnblogs.com/wspcoding/p/5699049.html