Python基础-面向对象基础

了解面向对象之前的一些知识

编程范式

是一种典型的编程风格,是一种方法学
编程范式决定了程序员对程序执行的看法
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
#!/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
#!/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

#!/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
#!/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.....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
__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
#!/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来选择子类该执行哪个方法的。

感谢阅读,欢迎指正。

-------------本文结束感谢您的阅读-------------