什么是面向对象编程?
面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)是一种计算机编程架构。Python就是这种编程语言。
面向对象程序设计中的概念主要包括:对象、类、继承、动态绑定、封装、多态性、消息传递、方法。
1)对象:类的实体,比如一个人。
2)类:一个共享相同结构和行为的对象的集合。通俗的讲就是分类,比如人是一类,动物是一类。
3)继承:类之间的关系,比如猫狗是一类,他们都有四条腿,狗继承了这个四条腿,拥有了这个属性。
4)动态绑定:在不修改源码情况下,动态绑定方法来给实例增加功能。
5)封装:把相同功能的类方法、属性封装到类中,比如人两条腿走路,狗有四条腿走路,两个不能封装到一个类中。
6)多态性:一个功能可以表示不同类的对象,任何对象可以有不同的方式操作。比如一个狗会走路、会跑。
7)消息传递:一个对象调用了另一个对象的方法。
8)方法:类里面的函数,也称为成员函数。
对象=属性+方法。
属性:变量。
方法:函数。
实例化:创建一个类的具体实例对象。比如一条泰迪。
什么是类?
类是对对象的抽象,对象是类的实体,是一种数据类型。它不存在内存中,不能被直接操作,只有被实例化对象时,才会变的可操作。
类是对现实生活中一类具有共同特征的事物的抽象描述。
6.1 类和类方法语法
1
2
3
4
5
6
|
# 类 class ClassName(): pass # 类中的方法 def funcName( self ): pass |
self代表类本身。类中的所有的函数的第一个参数必须是self。
6.2 类定义与调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#!/usr/bin/python # -*- coding: utf-8 -*- class MyClass(): x = 100 def func( self , name): return "Hello %s!" % name def func2( self ): return self .x mc = MyClass() # 类实例化,绑定到变量mc print mc.x # 类属性引用 print mc.func( "xiaoming" ) # 调用类方法 print mc.func2() # python test.py 100 Hello xiaoming! 100 |
上面示例中,x变量称为类属性,类属性又分为类属性和实例属性:
1)类属性属于类本身,通过类名访问,一般作为全局变量。比如mc.x
2)如果类方法想调用类属性,需要使用self关键字调用。比如self.x
3)实例属性是实例化后对象的方法和属性,通过实例访问,一般作为局部变量。下面会讲到。
4)当实例化后可以动态类属性,下面会讲到。
类方法调用:
1)类方法之间调用:self.<方法名>(参数),参数不需要加self
2)外部调用:<实例名>.<方法名>
6.3 类的说明
给类添加注释,提高可阅读性,可以通过下面方式查看。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
方法 1 : >>> class MyClass: ... """ ... 这是一个测试类. ... """ ... pass ... >>> print MyClass.__doc__ 这是一个测试类. >>> 方法 2 : >>> help (MyClass) Help on class MyClass in module __main__: class MyClass | 这是一个测试类. |
6.4 类内置方法
__init__(self, ...) | 初始化对象,在创建新对象时调用 |
__del__(self) | 释放对象,在对象被删除之前调用 |
__new__(cls, *args, **kwd) | 实例的生成操作,在__init__(self)之前调用 |
__str__(self) | 在使用print语句时被调用,返回一个字符串 |
__getitem__(self, key) | 获取序列的索引key对应的值,等价于seq[key] |
__len__(self) | 在调用内建函数len()时被调用 |
__cmp__(str, dst) | 比较两个对象src和dst |
__getattr__(s, name) | 获取属性的值 |
__setattr__(s, name, value) | 设置属性的值 |
__delattr__(s, name) | 删除属性 |
__gt__(self, other) | 判断self对象是否大于other对象 |
__lt__(self, other) | 判断self对象是否小于other对象 |
__ge__(self, other) | 判断self对象是否大于或等于other对象 |
__le__(self, other) | 判断self对象是否小于或等于other对象 |
__eq__(self, other) | 判断self对象是否等于other对象 |
__call__(self, *args) | 把实例对象作为函数调用 |
6.5 初始化实例属性
很多类一般都有初始状态的,常常定义对象的共同特性,也可以用来定义一些你希望的初始值。
Python类中定义了一个构造函数__init__,对类中的实例定义一个初始化对象,常用于初始化类变量。当类被实例化,第二步自动调用的函数,第一步是__new__函数。
__init__构造函数也可以让类传参,类似于函数的参数。
__init__构造函数使用:
1
2
3
4
5
6
7
8
9
10
11
12
|
#!/usr/bin/python # -*- coding: utf-8 -*- class MyClass(): def __init__( self ): self .name = "xiaoming" def func( self ): return self .name mc = MyClass() print mc.func() # python test.py xiaoming |
__init__函数定义到类的开头.self.name变量是一个实例属性,只能在类方法中使用,引用时也要这样self.name。
类传参:
1
2
3
4
5
6
7
8
9
10
11
12
|
#!/usr/bin/python # -*- coding: utf-8 -*- class MyClass(): def __init__( self , name): self .name = name def func( self , age): return "name: %s,age: %s" % ( self .name, age) mc = MyClass( 'xiaoming' ) # 第一个参数是默认定义好的传入到了__init__函数 print mc.func( '22' ) # python test.py Name: xiaoming, Age: 22 |
博客地址:http://lizhenliang.blog.51cto.com
QQ群:Shell/Python运维开发群 323779636
6.6 类私有化(私有属性)
6.6.1 单下划线
实现模块级别的私有化,以单下划线开头的变量和函数只能类或子类才能访问。当from modulename import * 时将不会引入以单下划线卡头的变量和函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#!/usr/bin/python # -*- coding: utf-8 -*- class MyClass(): _age = 21 def __init__( self , name = None ): self ._name = name def func( self , age): return "Name: %s, Age: %s" % ( self ._name, age) mc = MyClass( 'xiaoming' ) print mc.func( '22' ) print mc._name print mc._age # python test.py Name: xiaoming, Age: 22 xiaoming 21 |
_age和self._name变量其实就是做了个声明,说明这是个内部变量,外部不要去引用它。
6.6.2 双下划线
以双下划线开头的变量,表示私有变量,受保护的,只能类本身能访问,连子类也不能访问。避免子类与父类同名属性冲突。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#!/usr/bin/python # -*- coding: utf-8 -*- class MyClass(): __age = 21 def __init__( self , name = None ): self .__name = name def func( self , age): return "Name: %s, Age: %s" % ( self .__name, age) mc = MyClass( 'xiaoming' ) print mc.func( '22' ) print mc.__name print mc.__age # python test.py Name: xiaoming, Age: 22 Traceback (most recent call last): File "test.py" , line 12 , in <module> print mc.__name AttributeError: MyClass instance has no attribute '__name' |
可见,在单下划线基础上又加了一个下划线,同样方式类属性引用,出现报错。说明双下划线变量只能本身能用。
如果想访问私有变量,可以这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#!/usr/bin/python # -*- coding: utf-8 -*- class MyClass(): __age = 21 def __init__( self , name = None ): self .__name = name def func( self , age): return "Name: %s, Age: %s" % ( self .__name, age) mc = MyClass( 'xiaoming' ) print mc.func( '22' ) print mc._MyClass__name print mc._MyClass__age # python test.py Name: xiaoming, Age: 22 xiaoming 21 |
self.__name变量编译成了self._MyClass__name,以达到不能被外部访问的目的,并没有真正意义上的私有。
6.6.3 特殊属性(首尾双下划线)
一般保存对象的元数据,比如__doc__、__module__、__name__:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
>>> class MyClass: """ 这是一个测试类说明的类。 """ pass # dic()返回对象内变量、方法 >>> dir (MyClass) [ '__doc__' , '__module__' ] >>> MyClass.__doc__ '\n\t\xd5\xe2\xca\xc7\xd2\xbb\xb8\xf6\xb2\xe2\xca\xd4\xc0\xe0\xcb\xb5\xc3\xf7\xb5\xc4\xc0\xe0\xa1\xa3\n\t' >>> MyClass.__module__ '__main__' >>> MyClass.__name__ 'MyClass' |
这里用到了一个新内置函数dir(),不带参数时,返回当前范围内的变量、方法的列表。带参数时,返回参数的属性、方法的列表。
Python自己调用的,而不是用户来调用。像__init__ ,你可以重写。
6.7 类的继承
子类继承父类,子类将继承父类的所有方法和属性,提高代码重用。
1)简单继承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#!/usr/bin/python # -*- coding: utf-8 -*- class Parent(): def __init__( self , name = None ): self .name = name def func( self , age): return "Name: %s, Age: %s" % ( self .name, age) class Child(Parent): pass mc = Child( 'xiaoming' ) print mc.func( '22' ) print mc.name # python test.py Name: xiaoming, Age: 22 xiaoming |
2)子类实例初始化
如果子类重写了构造函数,那么父类的构造函数将不会执行:
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/python # -*- coding: utf-8 -*- class Parent(): def __init__( self ): self .name_a = "xiaoming" def funcA( self ): return "function A: %s" % self .name_a class Child(Parent): def __init__( self ): self .name_b = "zhangsan" def funcB( self ): return "function B: %s" % self .name_b mc = Child() print mc.name_b print mc.funcB() print mc.funcA() # python test.py zhangsan function B: zhangsan Traceback (most recent call last): File "test2.py" , line 17 , in <module> print mc.funcA() File "test2.py" , line 7 , in funcA return "function A: %s" % self .name_a AttributeError: Child instance has no attribute 'name_a' |
抛出错误,提示调用funcA()函数时,没有找到name_a属性,也就说明了父类的构造函数并没有执行。
如果想解决这个问题,可通过下面两种方法:
方法1:调用父类构造函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#!/usr/bin/python # -*- coding: utf-8 -*- class Parent(): def __init__( self ): self .name_a = "xiaoming" def funcA( self ): return "function A: %s" % self .name_a class Child(Parent): def __init__( self ): Parent.__init__( self ) self .name_b = "zhangsan" def funcB( self ): return "function B: %s" % self .name_b mc = Child() print mc.name_b print mc.funcB() print mc.funcA() # python test.py zhangsan function B: zhangsan function A: xiaoming |
方法2:使用supper()函数继承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#!/usr/bin/python # -*- coding: utf-8 -*- class Parent( object ): def __init__( self ): self .name_a = "xiaoming" def funcA( self ): return "function A: %s" % self .name_a class Child(Parent): def __init__( self ): super (Child, self ).__init__() self .name_b = "zhangsan" def funcB( self ): return "function B: %s" % self .name_b mc = Child() print mc.name_b print mc.funcB() print mc.funcA() # python test.py zhangsan function B: zhangsan function A: xiaoming |
6.8 多重继承
每个类可以拥有多个父类,如果调用的属性或方法在子类中没有,就会从父类中查找。多重继承中,是依次按顺序执行。
类简单的继承:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#!/usr/bin/python # -*- coding: utf-8 -*- class A: def __init__( self ): self .var1 = "var1" self .var2 = "var2" def a( self ): print "a..." class B: def b( self ): print "b..." class C(A,B): pass c = C() c.a() c.b() print c.var1 print c.var2 # python test.py a... b... var1 var2 |
类C继承了A和B的属性和方法,就可以像使用父类一样使用它。
子类扩展方法,直接在子类中定义即可:
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
|
#!/usr/bin/python # -*- coding: utf-8 -*- class A: def __init__( self ): self .var1 = "var1" self .var2 = "var2" def a( self ): print "a..." class B: def b( self ): print "b..." class C(A,B): def test( self ): print "test..." c = C() c.a() c.b() c.test() print c.var1 print c.var2 # python test.py a... b... test... var1 var2 |
在这说明下经典类和新式类。
经典类:默认没有父类,也就是没继承类。
新式类:有继承的类,如果没有,可以继承object。在Python3中已经默认继承object类。
经典类在多重继承时,采用从左到右深度优先原则匹配,而新式类是采用C3算法(不同于广度优先)进行匹配。两者主要区别在于遍历父类算法不同,具体些请在网上查资料。
6.9 方法重载
直接定义和父类同名的方法,子类就修改了父类的动作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#!/usr/bin/python # -*- coding: utf-8 -*- class Parent(): def __init__( self , name = 'xiaoming' ): self .name = name def func( self , age): return "Name: %s, Age: %s" % ( self .name, age) class Child(Parent): def func( self , age = 22 ): return "Name: %s, Age: %s" % ( self .name, age) mc = Child() print mc.func() # python test.py Name: xiaoming, Age: 22 |
6.10 修改父类方法
在方法重载中调用父类的方法,实现添加功能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#!/usr/bin/python # -*- coding: utf-8 -*- class Parent(): def __init__( self , name = 'xiaoming' ): self .name = name def func( self , age): return "Name: %s, Age: %s" % ( self .name, age) class Child(Parent): def func( self , age): print "------" print Parent.func( self , age) # 调用父类方法 print "------" mc = Child() mc.func( '22' ) # python test.py - - - - - - Name: xiaoming, Age: 22 - - - - - - |
还有一种方式通过super函数调用父类方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#!/usr/bin/python # -*- coding: utf-8 -*- class Parent(): def __init__( self , name = 'xiaoming' ): self .name = name def func( self , age): return "Name: %s, Age: %s" % ( self .name, age) class Child(Parent): def func( self , age): print "------" print super (Child, self ).func(age) print "------" mc = Child() mc.func( '22' ) # python test.py - - - - - - Traceback (most recent call last): File "test2.py" , line 15 , in <module> mc.func( '22' ) File "test2.py" , line 11 , in func print super (Child, self ).func(age) TypeError: must be type , not classobj |
抛出错误,因为super继承只能用于新式类,用于经典类就会报错。
那我们就让父类继承object就可以使用super函数了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#!/usr/bin/python # -*- coding: utf-8 -*- class Parent( object ): def __init__( self , name = 'xiaoming' ): self .name = name def func( self , age): return "Name: %s, Age: %s" % ( self .name, age) class Child(Parent): def func( self , age): print "------" print super (Child, self ).func(age) # 调用父类方法。在Python3中super参数可不用写。 print "------" mc = Child() mc.func( '22' ) # python test.py - - - - - - Name: xiaoming, Age: 22 - - - - - - |
6.11 属性访问的特殊方法
有四个可对类对象增删改查的内建函数,分别是getattr()、hasattr()、setattr()、delattr()。
6.11.1 getattr()
返回一个对象属性或方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
>>> class A: ... def __init__( self ): ... self .name = 'xiaoming' ... def method( self ): ... print "method..." ... >>> c = A() >>> getattr (c, 'name' , 'Not find name!' ) 'xiaoming' >>> getattr (c, 'namea' , 'Not find name!' ) >>> getattr (c, 'method' , 'Not find method!' ) <bound method A.method of <__main__.A instance at 0x93fa70 >> >>> getattr (c, 'methoda' , 'Not find method!' ) 'Not find method!' |
6.11.2 hasattr()
判断一个对象是否具有属性或方法。返回一个布尔值。
1
2
3
4
5
6
7
8
|
>>> hasattr (c, 'name' ) True >>> hasattr (c, 'namea' ) False >>> hasattr (c, 'method' ) True >>> hasattr (c, 'methoda' ) False |
6.11.3 setattr()
给对象属性重新赋值或添加。如果属性不存在则添加,否则重新赋值。
1
2
3
4
5
6
7
|
>>> hasattr (c, 'age' ) False >>> setattr (c, 'age' , 22 ) >>> c.age 22 >>> hasattr (c, 'age' ) True |
6.11.4 delattr()
删除对象属性。
1
2
3
|
>>> delattr (c, 'age' ) >>> hasattr (c, 'age' ) False |
6.12 类装饰器
与函数装饰器类似,不同的是类要当做函数一样调用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#!/usr/bin/python # -*- coding: utf-8 -*- class Deco: def __init__( self , func): self ._func = func self ._func_name = func.__name__ def __call__( self ): return self ._func(), self ._func_name @Deco def f1(): return "Hello world!" print f1() # python test.py ( 'Hello world!' , 'f1' ) |
6.13 类内置装饰器
下面介绍类函数装饰器,在实际开发中,感觉不是很常用。
6.10.1 @property
@property属性装饰器的基本功能是把类中的方法当做属性来访问。
在没使用属性装饰器时,类方法是这样被调用的:
1
2
3
4
5
6
7
8
9
10
11
12
|
>>> class A: ... def __init__( self , a, b): ... self .a = a ... self .b = b ... def func( self ): ... print self .a + self .b ... >>> c = A( 2 , 2 ) >>> c.func() 4 >>> c.func <bound method A.func of <__main__.A instance at 0x7f6d962b1878 >> |
使用属性装饰器就可以像属性那样访问了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
>>> class A: ... def __init__( self , a, b): ... self .a = a ... self .b = b ... @ property ... def func( self ): ... print self .a + self .b ... >>> c = A( 2 , 2 ) >>> c.func 4 >>> c.func() 4 Traceback (most recent call last): File "<stdin>" , line 1 , in <module> TypeError: 'NoneType' object is not callable |
6.10.2 @staticmethod
@staticmethod是静态方法装饰器,可以通过类对象访问,也可以通过实例化后类对象实例访问。
实例方法的第一个参数是self,表示是该类的一个实例,称为类对象实例。
而使用静态方法装饰器,第一个参数就不用传入实例本身(self),那么这个方法当做类对象,由Python自身处理。
看看普通方法的用法:
1
2
3
4
5
6
7
|
>>> class A: ... def staticMethod ( self ): ... print "not static method..." ... >>> c = A() >>> c. staticMethod () not static method... |
使用静态方法则是这么用:
1
2
3
4
5
6
7
8
9
10
|
>>> class A: ... @ staticmethod ... def staticMethod (): ... print "static method..." ... >>> A. staticMethod () # 可以通过类调用静态方法 static method... >>> c = A() >>> c. staticMethod () # 还可以使用普通方法调用 static method... |
静态方法和普通的非类方法作用一样,只不过命名空间是在类里面,必须通过类来调用。一般与类相关的操作使用静态方法。
6.10.3 @classmethod
@classmethod是类方法装饰器,与静态方法装饰器类似,也可以通过类对象访问。主要区别在于类方法的第一个参数要传入类对象(cls)。
1
2
3
4
5
6
7
8
9
|
>>> class A: ... @ classmethod ... def classMethod ( cls ): ... print "class method..." ... print cls .__name__ ... >>> A. classMethod () class method... A |
6.14 __call__方法
可以让类中的方法像函数一样调用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
>>> class A: ... def __call__( self , x): ... print "call..." ... print x ... >>> c = A() >>> c( 123 ) call... 123 >>> class A: ... def __call__( self , * args, * * kwargs): ... print args ... print kwargs ... >>> c = A() >>> c( 1 , 2 , 3 ,a = 1 ,b = 2 ,c = 3 ) ( 1 , 2 , 3 ) { 'a' : 1 , 'c' : 3 , 'b' : 2 } |