了解面向对象之前的一些知识
编程范式
是一种典型的编程风格,是一种方法学
编程范式决定了程序员对程序执行的看法
OOP中,程序是一系列对象之间的相互作用
Python中支持多种编程范式:面向过程、面向对象,面向切面(装饰器部分)等
OOP思想
面向对象的基本哲学:世界由具有各自运动规律和内部状态的对象组成,对象之间的相互作用和通讯构成了世界
唯一性,世界上没有两片相同的叶子,同样的,也没有两个完全相同的对象
分类性:分类是对现实世界的抽象
三大特性,继承,多态和封装
类与实例
类 是一类实例的抽象,抽象的属性和操作
实例 是类的具体化
定义类
class Name:
这种方式在python3和python2.3之前比较流行,但是在python2.4之后所有类都要继承自object 类。class Name(object):
class Name(Parents):
一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #!/usr/bin/env Python #coding=utf-8 class People(object): #object是所有类的基类,它定义了一些基本的操作。继承了object的类称为新式类 def __init__(self,name,sex,age): #__init__(self,...),初始化方法,self,对象自身 self.name = name #将传进来的值定义给对象自身的数据 self.sex = sex self.age = age def say(self,words): #一个普通的方法 print 'saying %s .....' % words def walk(self): print "walking....." tom = People('tom','man',17) #实例化一个对象,self参数会自动传入 tom.say('hello') #调用tom的say方法 tom.walk() print tom.age #打印tom的实例变量age ===============结果============= root@tonglele /code/Python/oop_base # python code1.py saying hello ..... walking..... 17 |
类的封装性
私有成员
以双下划线开始,但不以双下划线结束
Python中没有真正的私有成员,我们可以通过一些方法调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #!/usr/bin/env python # coding=utf-8 class People(object): def __init__(self,name,age): self.name = name self.__age = age #一个私有属性 def print_info(self): print self.name print self.__age def __test(self): #一个私有方法 print 'calling test.....' tom = People('tom',60) print tom.name print tom.__age ==========运行结果======== root@tonglele /code/Python/oop_base # python code2.py tom Traceback (most recent call last): File "code2.py", line 20, in <module> print tom.__age AttributeError: 'People' object has no attribute '__age' #报错。 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #!/usr/bin/env python # coding=utf-8 class People(object): def __init__(self,name,age): self.name = name self.__age = age def print_info(self): print self.name print self.__age def __test(self): print 'calling test.....' tom = People('tom',60) #print tom.name #print tom.__age tom.print_info() tom.__test() ===========运行结果============= 1 root@tonglele /code/Python/oop_base # python code2.py :( tom 60 Traceback (most recent call last): File "code2.py", line 23, in <module> tom.__test() AttributeError: 'People' object has no attribute '__test' |
类变量
定义在实例方法之外的变量
所有实例共享类变量,但某一个实例对类变量的修改不会影响其他的实例和类本身
类变量可以直接访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #!/usr/bin/env python #coding=utf-8 class People(object): count = 0 def __init__(self,name,sex,age): self.name = name self.sex = sex self.age = age def print_info(self): print self.name print self.sex print self.age tom = People('tom','man',19) marry = People('marry','women',18) print People.count print tom.count print marry.count People.count = 100 tom.count = 99 marry.count = 98 print '============' print People.count print tom.count print marry.count ==========结果=========== root@tonglele /code/Python/oop_base # python code3.py 0 0 0 ============ 100 99 98 |
类方法
使用@classmethod
装饰器装饰,第一个参数代表类本身,
类方法可以直接调用,类方法里可以定义类变量。在类方法里不能调用与实例相关的东西,即不能使用self
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #!/usr/bin/env python #coding=utf-8 class People(object): def __init__(self,name,sex,age): self.name = name self.sex = sex self.age = age def print_info(self): print self.name print self.sex print self.age @classmethod def test(cls): #cls代表类本身 cls.count = 10 #定义一个类变量 print 'calling test.....' People.test() #类方法可以直接调用 print People.count #打印类变量 tom = People('tom','man',19) tom.test() #用实例调用类方法 ==========运行结果======== root@tonglele /code/Python/oop_base # python code3.py calling test..... 10 calling test..... |
静态方法
以@staticmethod
装饰器装饰,可以直接调用,没有像类方法那样限定第一个参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #!/usr/bin/env python #coding=utf-8 class People(object): def __init__(self,name,sex,age): self.name = name self.sex = sex self.age = age def print_info(self): print self.name print self.sex print self.age @staticmethod def test(): print 'calling static--test.....' People.test() #直接调用静态方法 tom = People('tom','man',19) tom.test() #通过实例调用静态方法 ========结果========== root@tonglele /code/Python/oop_base # python code3.py calling static--test..... calling static--test..... |
属性
@property
装饰器可以使被装饰的方法称为一个属性,类似与其他语言中的get方法
属性的setter方法
其他的具体解释见代码片
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | #!/usr/bin/env python import time import datetime class Dog(object): def __init__(self,n): self.n = n self.__a = None def test(self): print 'calling test.....' @property #open_f方法被@property装饰器装饰了之后成为一个属性 def open_f(self): return self.__a == None @open_f.setter #当open_f方法被装饰之后它自己也变成了一个另一个装饰器,用来装饰这个open_f方法之后此时的这个open_f就相当于其他语言的set方法 def open_f(self,value): self.__a = value class Timef(object): def __init__(self): self.__time = datetime.datetime.now() @property def time(self): return self.__time.strftime('%Y-%m-%d %H:%M:%S') @time.setter def time(self,value): self.__time = datetime.datetime.strptime(value,'%Y-%m-%d %H:%M:%S') t = Dog(1212) print t.open_f t.open_f = 7878 #给该属性赋值,相当于调用了set方法 print t.open_f #调用该属性,相当于调用了get方法 tt = Timef() print tt.time tt.time = '2016-03-20 21:34:21' print tt.time #time例子: #默认以字符串的形式返回当前的时间,也可以以字符串的形式设置时间,整体来说是封装了私有属性__time。 ==========运行结果============= root@tonglele /code/Python/oop_base # python code4.py True False 2016-06-29 22:10:20 2016-03-20 21:34:21 |
另一个常用的运用:
在工作中,有些需求需要对IP地址进行处理,因为在计算机中IP都是以整数的形式做运算的,
但是展现出来的时候都是以字符串形式(点分十进制),便于人类查看,就可以用上述方法实现对IP操作的封装
魔术方法
魔术方法总是以双下划线开头,并以双下划线结尾的,这些方法都是由特殊用途的
下面简单介绍一些:
__init__
__init__
初始化方法,对实例对象的一些数据进行初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #!/usr/bin/env python # coding=utf-8 class People(object): def __init__(self,name,age): #初始化函数 self.name = name #将类=实例对象的一些数据初始化。。 self.age = age print "init....." tom = People('tom',19) #实例化一个对象 ==========运行结果===== root@tonglele /code/Python/oop_base # python code5.py init..... |
__new__,__del__
__new__
方法,相当于C++中的构造函数,下一篇具体介绍
__del__
相当于C++中的析构函数,当对象被回收时做一些清理工作
__eq__
__eq__
方法相当于重载了一个==
等于运算符
__gt__
__gt__
方法相当于重载了一个>
大于号运算符
__add__
__add__
方法相当与重载了一个+
号
__str__
__str__
方法,定义了我们使用str方法或直接print一个对象的时候的一个行为
__repr__
类似与__str__
,不过__repr__
返回的是机器可读的字符串,__str__
返回的是人类可读的
__hash__
__enter__和__exit__
只要一个类实现了这个两个方法就可以使用with 语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #!/usr/bin/env python #coding=utf-8 class W(object): def __init__(self): self.fileName = open('/mnt/file','w') def __enter__(self): return self.fileName def __exit__(self,*excinfo): #该方法接受一个可变参数,出现异常的时候将异常 self.fileName.close() #传值给该参数,在该函数里根据异常可以做相应的处理 with W() as f: f.write("hello world") |
以上魔术方法的一些应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | #!/usr/bin/env python #coding=utf-8 class Man(object): def __init__(self,name,sex,age): self.name = name self.sex = sex self.age = age def __eq__(self,other): return self.age == other.age and self.sex == other.sex and self.age == other.age def __gt__(self,other): return self.age > other.age def __ne__(self,other): return self.age != other.age or self.name != other.name or self.sex != other.sex def __add__(self,other): return Man(self.name+other.name,self.sex+other.sex,self.age+other.age) def __str__(self): return 'name: %s sex: %s age: %s \n' % (self.name,self.sex,self.age) def __del__(self): print 'del......' #做一些清理工作 man1 = Man('tom','man',19) man2 = Man('harry','man',17) print man1 == man2 print man1 > man2 print man1 != man2 print man1 print man1 + man2 ===========结果========== False True True name: tom sex: man age: 19 name: tomharry sex: manman age: 36 del...... del...... del...... |
继承
子类与父类:子类是对父类的扩展,在父类的属性和方法的基础上做一些扩展
一个继承的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | #!/usr/bin/env python class Phone(object): #父类 def __init__(self,size,color,mem): #父类的初始化方法,父类拥有尺寸,颜色,内存三个数据 self.size = size self.color = color self.mem = mem def call(self): #父类的call方法 print 'calling.....' def msg(self): #父类的msg方法 print 'sending msg......' class Phones(Phone): #Phones类,继承了Phone类 def __init__(self,size,color,mem,pix): #重写了初始化方法,加入了pix数据 self.pix = pix #将新加入的数据写入 super(Phones,self).__init__(size,color,mem) #再调用父类的初始化方法 def install_app(self,app): #在父类的方法基础上,增加了一个install_app方法 print 'installing %s ......' % app class Huawei(Phone): def weixin(self,msg): if msg.find('jiangfan') == -1: print 'can\'t send....' else: print 'sending.....' p = Phone('4,0','black','4M') p.call() iphone = Phones('4.7','white','4G','1080*699') iphone.install_app('dangdang') hua = Huawei('3.5','black','2G') hua.weixin('jiangfan') ==============结果=============== calling..... installing dangdang ...... sending..... |
多继承
我们大多数情况下只会使用单继承,但python也提供多继承class ClassName(c1,c2...)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/usr/bin/env python class A(object): def __init__(self): pass def m(self): print 'A -- m....' class B(object): def n(self): print 'B -- n....' class C(A,B): pass c = C() c.m() c.n() ===========运行结果======== A -- m.... B -- n.... |
但是多继承中也会出现一些问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #!/usr/bin/env python class A(object): def __init__(self): pass def m(self): print 'A -- m....' class B(object): def m(self): print 'B -- m....' class C(A,B): pass c = C() c.m() =========结果=========== A -- m.... #当多个父类中拥有同一个名称的方法时,子类采用继承顺序靠前的那个 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #!/usr/bin/env python class A(object): def __init__(self): pass def m(self): print 'A -- m....' class B(A): #B继承于A def m(self): print 'B -- m....' class C(A,B): pass c = C() c.m() =========结果=========== Traceback (most recent call last): #继承关系发生混淆 File "test5.py", line 16, in <module> class C(A,B): TypeError: Error when calling the metaclass bases Cannot create a consistent method resolution order (MRO) for bases A, B |
MRO:一种算法,在python中存在多继承,当继承列表中有同名方法的时候,python就是根据这个MRO来选择子类该执行哪个方法的。
感谢阅读,欢迎指正。