python -- 面向对象

Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。

在python中,一切皆对象。在学习python的面向对象程序设计之前,先来看看面向对象的基本特征。

面向对象技术简介

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • 类变量:类变量属于类本身,不属于任何一个实例。实例可以访问其对应类的类变量,但不能修改。
  • 成员变量:成员变量定义在类的构造方法里面,在实例化对象是生成,属于某个特定对象,不属于类。
  • 方法重载:子类从父类继承的方法不满足子类的需要时,可以先重载,再继承,这样来进行扩展或修改。
  • 继承:子类继承自父类,这样子类就能拥有从父类继承过来的东西。通常用子类来对父类进行扩展。(父类更多的是公同拥有的,子类就是进行个性化)
  • 实例化:创建一个类的实例,类的具体对象。
  • 方法:类中定义的函数。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

面向对象思想

  1、面向对象特点:封装、继承、多态
  2、面向对象程序设计思想:
    先整体构想,规划多个对象,再由对象特性分别设计类
    由类实例化不同的对象
    由多个对象组合完成整个程序
  3、python中的子类可以继承多个父类(一般就1-2个,python3新式类、经典类继承都是广度优先,python2中新式类采用广度优先,经典类采用深度优先)
  4、封装,继承都是为了代码重用
  5、多态:(一个接口,多重实现)接口重用 (注:python自身不支持多态,但可以用代码实现类似效果)

Python中的面向对象

一、类的详解

  

 1 例如:
 2 class Role(object):
 3     ac = None    #类的变量,随着类的创建,存在与内存中
 4     
 5     def __init__(self,name,role,weapon,life_value):
 6         self.name = name
 7         self.role = role     #这都是成员变量(实例化的对象的变量)
 8         self.weapon = weapon
 9         self.life_value = life_value
10         
11     def buy_weapon(self,weapon):
12         print('%s is buying [%s]' %(self.name,weapon))
13         self.weapon = weapon
14 
15 在这个类里面,有一个类的变量ac,可以理解为静态变量,要修改ac的值,需要通过' Role.ac = xxx ',即 类名.类变量名
16 
17 类变量与成员变量区别:
18      1、类变量在定义类时就存在于内存中了,而成员变量只有在实例化时才被构造方法创造
19      2、定义时,成员变量前面都有self,而类变量没有。因为self时指向的不同对象,而类变量只
20         能由‘类名.类变量’来修改,可以通过‘对象.类变量’来访问,但是不能修改
21 
22 类不能直接调用实例变量(实例变量存储在对象中,不在类中)
23      
24 __init__() 是构造方法,在实例化对象时自动调用,就是用来初始化对象属性等
25 
26 在实例化对象时,根据构造参数传递参数
27 
28 定义类时,里面属性前面都有一个self,方法的第一个参数默认是self,这个self是指向实例化的对象,不是指向的类
29     
30 
31 内存详解:
32     在类定义时,就在系统内存里面生成了一块内存来存放类的内容,包括 类变量、类方法 等
33     即:类变量存储在类里面,类里面的方法也是存储在类这块内存里面的
34     
35     构造函数是在实例化对象才会调用,所以构造函数里面的属性都是存在于实例化的对象的内存里面(是特定对象的属性)
36 
37 对象调用类的方法:
38     在实例化对象时,并没有把类里面的方法都copy到对象内存空间里面,所以对象的内存空间里面只有属性,并没有方法
39   方法都是存在于类的内存中(这样就算是实例化了无数个对象,方法在内存中还是只有类空间里面这一份,节约空间)
40   方法都是类的方法,实例化对象在调用方法时,都会去类空间里面找。

  类里面有共有属性和私有属性

 1 '''
 2  私有属性:只能在类里面通过类自己的方法调用,对象不能直接调用(可以通过方法)
 3  要把一个属性变为私有属性,只需要在属性名前面加两个下划线'__'
 4  
 5  (特例,尽量别用)从外部直接访问私有变量方法: t._Human__life
 6 
 7 '''
 8 
 9 class Human(object):
10     __num = 10
11     def __init__(self,name):
12         self.name = name
13         self.__life = 100
14         
15     def interface1(self):
16         print('血量 self.__life:',self.__life)
17     
18     def interface2(self):
19         print('__num:',self.__num)
20         
21         
22 t = Human('Tom')
23 print(t.name)
24 #print(t.__life)
25 '''
26 builtins.AttributeError: 'Human' object has no attribute '__life'
27 因为__life 是对象里面的私有属性,在外部不能直接调用,但可以通过方法调用
28 '''
29 t.interface1()  #血量: 100
30 #print(Human.__num)
31 '''
32 builtins.AttributeError: type object 'Human' has no attribute '__num'
33 '''
34 t.interface2()
35 
36 print("特例访问私有变量方法 t._Human__life :",t._Human__life) 

  类里面不常用的特殊方法

 1 #!/usr/bin/env python
 2 #coding:utf-8
 3 
 4 class A(object):
 5     '''Test class'''
 6     num = 10
 7     
 8     #类里面的__init__()是由__new__()触发执行的
 9     #def __new__(self):
10         #print("=======new======")
11     '''
12     =======new======
13     None
14     报错:builtins.AttributeError: 'NoneType' object has no attribute '__module__'
15     说明在这里重载__new__()方法后,没有再执行__init__()
16     '''
17     def __init__(self,name,age):
18         self.name = name
19         self.age = age
20         print('__init__')
21     
22     def __call__(self):
23         print("__call__")
24     
25     def test(self):
26         print("=====test=====")
27     #重载析构函数
28     def __del__(self):
29         print('deleting the ...')
30 
31 a = A('root',20)
32 print(a.__doc__)   
33 '''
34 Test class
35 __doc__ 获取类的说明(即:注释)
36 在定义类的函数时,最好在注释里面对其作用、功能、参数等做个说明
37 '''
38 '''
39 __module__ 表示当前操作的对象或类在那个模块
40 
41 __class__     表示当前操作的对象的类是什么
42 '''
43 print(a.__module__)
44 '''
45 __main__ 在这里代表的是当前模块。如果对象a在其他模块,则会打印a所在的模块名
46 '''
47 #import test.Human
48 from test import Human
49 #from test import h
50 h1 = Human()
51 #print(h.__module__)   #test
52 print(h1.__module__)   #test
53 print(h1.__class__)   #<class 'test.Human'>
54 
55 #python中,析构函数是: __del__()   析构函数会自己在程序执行结束自动调用
56 
57 '''
58  __call__  对象后面加括号,触发执行。
59 注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;
60 而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
61 '''
62 #执行__call__ 方法
63 a()  #__call__
64 #A()()   #__call__
65 
66 '''
67  __dict__    只能显示对象中的所有成员变量,不能显示类变量
68 
69 我们知道:实例变量(成员变量)属于对象;类中的静态变量和方法等属于类,
70 '''
71 print(a.__dict__)
72 '''
73 {'name': 'root', 'age': 20}
74 '''
75 print(type(a))   #<class '__main__.A'>
76 print(a)  #<__main__.A object at 0x000001BA3967D128>
77 
78 #类是由'type'创造出来的
79 print(type(A))    #<class 'type'>

  类的方法

 1 #!/usr/bin/env python
 2 #coding:utf-8
 3 
 4 '''
 5 @classmethod  类方法装饰器(不能访问实例变量)
 6   作用:把装饰的方法变为类方法(相似于类变量,只能通过类来访问,对象不能访问类方法)
 7 
 8 @staticmethod  静态方法装饰器(不能访问类变量和实例变量)
 9   作用:类的工具箱,与类直接相互独立,要调用类的东西只有传参(一般不用)
10   
11 @property 类属性装饰器
12   作用:把装饰的方法变为一个属性(能调用,不可执行)
13 
14 '''
15 class Animal(object):
16     hobbie = "meat"
17     def __init__(self,name):
18         self.name = name
19         self.num = None
20      
21     @classmethod    #类方法,不能访问实例变量
22     def talk(self):
23         print('%s is talking...' %self.hobbie)    #可以直接调用,但不能修改
24         #print('%s is talking...' %self.name)
25     '''
26     builtins.AttributeError: type object 'Animal' has no 
27     attribute 'name'
28     '''
29      
30     @staticmethod
31     def walk(self):
32         print('%s is walking...' %self.name)
33     '''
34     builtins.TypeError: walk() missing 1 required positional 
35     argument: 'self'
36     不知道self是谁,在调用时应该把self当参数传进来
37     '''   
38        
39     @property
40     def habit(self):
41         print("%s habit is xxoo" %self.name)
42     '''
43     builtins.TypeError: 'NoneType' object is not callable
44     ''' 
45     
46     #property 用法补充
47     #1、直接调用(此时不能传值,否则报错)
48     @property
49     def total_player(self):
50         print("this is a property")
51         return self.num
52     
53     #2、经过1后,total_player变成了属性,因此可以用setter
54     @total_player.setter
55     def total_player(self,num):
56         self.num = num
57         print("self.num:",self.num)
58         
59     #3、相对于2可以给属性传值,那么也可以用删除属性值
60     @total_player.deleter
61     def total_player(self):
62         print("total player got deleted")
63         del self.num
64     
65 d = Animal('zhaolin')
66 d.talk()
67 d.walk(d)
68 d.habit
69 #1:
70 d.total_player
71 #2:
72 d.total_player = 20
73 #3:
74 del d.total_player    #用deleter时,要这样调用
75 
76 '''
77 meat is talking...
78 zhaolin is walking...
79 zhaolin habit is xxoo
80 
81 this is a property
82 self.num: 20
83 total player got deleted
84 
85 '''

   

二、类的使用

  继承:由一般(很多类都具有的共性)到特殊(不同的类有不同的特性)

  子类继承父类时,构造方法需要 【先重写,再继承】
 1 #!/usr/bin/env python
 2 #coding:utf-8
 3 
 4 '''
 5 继承:由一般(很多类都具有的共性)到特殊(不同的类有不同的特性)
 6 
 7 子类继承父类时,构造方法需要 【先重写,再继承】
 8 '''
 9 
10 class SchoolMember(object):
11     def __init__(self,name,age,sex):
12         self.name = name
13         self.age = age
14         self.sex = sex
15         self.enroll()
16         
17     def enroll(self):
18         print('[%s] was enrolled!' %self.name)
19         
20     def tell(self):
21         print('[%s] is telling!' %self.name)
22         
23 class Teacher(SchoolMember):
24     def __init__(self, name, age, sex,course,salary):   #先重写
25         super(Teacher,self).__init__(name,age,sex)    #再继承
26         self.course = course
27         self.salary = salary
28     
29     def teaching(self):
30         print('Teacher [%s] is teaching [%s]' %(self.name,self.course))
31         
32     def get_salary(self):
33         print('Teacher [%s] is saving salary [%s]' %(self.name,self.salary))
34         
35 class Student(SchoolMember):
36     student_nums = 0
37     def __init__(self, name, age, sex,course,tuition):   #先重写
38         super(Student,self).__init__(name,age,sex)     #再继承
39         self.course = course
40         self.tuition = tuition
41         Student.student_nums += 1
42     
43     def enroll(self):            
44         #super(Student,self).enroll()   #在子类里面重写enroll(),不继承    
45         print('The [%s] student [%s] is enrolled!' %(self.student_nums,self.name))
46         #这里可以用self.student_nums,是因为只是访问student_nums,而没有修改它
47         
48     def studying(self):
49         print('Student [%s] is studying!' %self.name)
50     
51     def pay_tuition(self):
52         print('The tuition of Student [%s] is [%s]' %(self.name,self.tuition))
53  
54 #实例化对象        
55 t1 = Teacher('txowner', 22, 'male', 'python', 3000)
56 t2 = Teacher('xtsec', 24, 'male', 'php', 2500)
57 '''
58 实例化对象的过程:
59     eg:t2 = Teacher('xtsec', 24, 'male', 'php', 2500)
60         1、t2 = Teacher() 在内存中开辟一块内存,让t2指向该内存
61         2、Teacher(t2)  把t2这块内存与类Teacher相关联(这也是为什么self是指向对象的而不是类)
62         3、把各个参数传递给类的构造方法,在对象t2空间里面创建各个成员变量
63         
64 '''
65 
66 s1 = Student('root', 20, 'male', 'python', 15000)
67 s2 = Student('lucy', 18, 'female', 'php', 12000)
68 
69 t1.teaching()
70 t2.teaching()
71 s1.studying()
72 s2.studying()
73 print('t1老师的salary:',t1.salary)
74 print('s2同学的tuition:',s2.tuition)
继承
 1 #!/usr/bin/env python
 2 #coding:utf-8
 3 
 4 '''先实验老式类(经典类)的写法'''
 5 
 6 #class A(object):   #新式类
 7 class A:   #经典类
 8     def f2(self):
 9         print('f2 from A')
10 
11 class B(A):
12     def f1(self):
13         print('f1 from B')
14         
15     def f2(self):
16         print('f2 from B')
17         
18 class C(A):
19     def f2(self):
20         print('f2 from C')
21         
22 class D(B,C):
23     pass
24 
25 d = D()
26 d.f1()
27 d.f2()
28 '''
29 f1 from B
30 f2 from B
31 
32 由以上结果可知:在多继承时,若多个父类都有相同方法或属性,则按照广度优先方式继承
33 即:继承父类的方法时,若都有相同方法名的方法,则按照继承时的顺序从左至右继承一个
34 '''
35 '''
36 在python2.x版本:
37 
38     深度优先:同一条线上优先,比如上面如果按照深度优先的话,D在调用f2时,先去找
39 父类B,如果B里
40 面没有f2,那么D就会去调用A里面的f2,而不会调用C里面的f2,老式类就是这样
41 
42     广度优先:同一水平层次优先,比如上面如果按照广度优先的话,D在调用f2时,先去找
43 父类B,如果B里面没有f2,那么D就会去调用C里面的f2,而不会调用A里面的f2,新式类就是
44 这样
45 
46 在python3.x版本:
47     不管是新式类还是经典类,在继承时,都采用广度优先
48 '''
多继承

  python实现多态调用

 1 #!/usr/bin/env python
 2 #coding:utf-8
 3 
 4 '''
 5 python没有多态。多态是java、c#、c++这类强类型语言特有的
 6 
 7 python可以利用函数等方式来实现多态现象。
 8 
 9 '''
10 class Animal(object):
11     def __init__(self):
12         print('Animal Class')
13     
14     def talk(self):
15         pass
16 
17 class Dog(Animal):
18     def __init__(self):
19         print('Dog Class')
20         
21     def talk(self):
22         return ('woof!woof!') 
23         
24 class Cat(Animal):
25     def __init__(self):
26         print('Cat Class')    
27     
28     def talk(self):
29         return ('muaao~')
30         
31 dog = Dog()
32 cat = Cat()
33 dog.talk()
34 cat.talk()
35 
36 #利用函数实现统一接口
37 def animal_talk(obj):
38     print(obj.talk())
39     
40 animal_talk(dog)
41 print('=====')
42 animal_talk(cat)
多态调用

三、反射的妙用

 1 #!/usr/bin/env python
 2 #coding:utf-8
 3 
 4 '''
 5 反射是非常非常重要的!
 6 反射的作用:通过一个字符串来去调用一个对象中名字跟字符串值相同的方法(属性)的内存地址
 7 '''
 8 
 9 import sys
10 
11 class WebServer(object):
12     def __init__(self,host,port):
13         self.host = host
14         self.port = port
15         
16     def start(self):
17         print("Server is starting...")
18     def stop(self):
19         print("Server is stoped...")
20     def restart(self):
21         self.stop()
22         self.start()
23         
24 def test_run(ins,name):
25     print("test_run",name,ins.host)
26     
27         
28 if __name__ == '__main__':
29     #print(sys.argv[0],sys.argv[1])
30     '''
31     sys.argv是一个获取文件名后面参数的数组,sys.argv[0]是当前文件路径,
32     后面依次为传递的参数
33     '''
34     server = WebServer('localhost', 8080)
35     if hasattr(server, sys.argv[1]): 
36     #if hasattr(WebServer, sys.argv[1]):   #对象或类名都可以   
37         func = getattr(server,sys.argv[1])   #得到对象server中名字与传入字符串相等的函数(方法)
38         func()
39     else:
40         print("your input incorrect!")    
41      
42     #server1 = WebServer('localhost1', 80)
43     #setattr(server1,'run',test_run)
44     #server1.run(server1,'admin')
45     
46     #delattr(server1,'port')
47     #print(server1.port)   
48     #AttributeError: 'WebServer' object has no attribute 'port'
49     
50     '''
51     以下的obj可以是类,也可以是实例化的对象
52     
53     hasattr(obj,attr)  判断对象中有没有指定属性(方法)
54     
55     getattr(obj,attr)  获取对象中的属性(方法)的内存地址
56     
57     setattr(obj,attr,method)  把方法(属性)method添加到对象中,并改名为attr
58         通过对象调用method:obj.attr
59        
60         这样把方法(属性)添加到对象中与原生方法区别:
61           不会自动把self传进去,若要调用obj原生属性,只有先把obj当成参数传进去
62     
63     delattr(obj,attr)  把对象obj里面的attr属性(方法)删除掉
64          注意:因为实例化对象的方法是存在于类中,对象只是能访问类中的方法,不能
65            更改,但是对象可以更改自己的成员变量。所以这里的attr是对象自身的属性
66            或方法,不是类里面的。
67          
68          可以通过delattr(classname,attr)来删除类的属性(方法)
69     
70     '''
71     '''
72     #方式比较low
73     cmd_dict = {
74         'start':server.start,
75         'stop':server.stop,
76         'restart':server.restart
77     }
78     if sys.argv[1] in cmd_dict:
79         cmd_dict[sys.argv[1]]()
80     else:
81         print("your input incorrect!")
82    
83     '''
84     
原文地址:https://www.cnblogs.com/xtsec/p/6963638.html