面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)
一、编程类型
面向过程编程:根据业务逻辑从上到下写垒代码,分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
函数式编程:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
面向对象编程:对函数进行分类和封装,把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
二、类和对象
面向对象编程需要使用 “类” 和 “对象” 来实现
类就是一个模板,模板里可以包含多个函数,函数里实现一些功能
对象则是根据模板创建的实例,通过实例对象可以执行类中的函数
1 class role(object): #创建一个类,类名role,(object)新式类的写法 2 ac = None 3 def __init__(self,name,role,weapon,life_value=100): #初始化函数,在生成一个角色时要初始化的一些属性就填写在这里 4 self.name = name 5 self.role = role 6 self.weapon = weapon 7 self.life_value = life_value 8 def buy_weapon(self,weapon): 9 print("%s is buying [%s]" %(self.name,weapon)) 10 self.weapon = weapon 11 12 p1 = role("nima",'police',"B11",90) #创建对象,自动把参数传给Role下面的__init__(...)方法 13 t1 = role("nimei",'terrorist',"B10",100) #生成一个角色,相当于 t1, role(t1,'nimei
','
terrorist
','
B10',100)
14 p1.buy_weapon("AK47") #python 会自动帮你转成 role.buy_weapon(p1,”B21"
)
15 t1.buy_weapon("B51") 16 17 p1.ac = "china brand" 18 role.ac = "us brand" 19 print("p1:",p1.life_value,p1.ac) 20 print("t1:",t1.weapon,t1.ac)
__init__()叫做初始化方法(或构造方法), 在类被调用时,这个方法(虽然它是函数形式,但在类中就不叫函数了,叫方法)会自动执行,进行一些初始化的动作,所以我们这里写的__init__(self,name,role,weapon,life_value=100)就是要在创建一个角色时给它设置这些属性
三、面向对象三大特性
1.封装
封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
将内容封装到某处
1 class foo: 2 def __init__(self,name,age): 3 self.name = name 4 self.age = age 5 6 obj = foo('haha',22) #将haha和22分别封装到obj的name和age属性中
调用被封装的内容
1 class foo: 2 def __init__(self,name,age): 3 self.name = name 4 self.age = age 5 6 obj = foo('haha',22) 7 print(obj.name) #通过“对象.属性名”调用被封装的内容
1 class foo: 2 def __init__(self,name,age): 3 self.name = name 4 self.age = age 5 6 def detail(self): 7 print(self.name) #通过“self.name”调用被封装的内容 8 print(self.age) 9 10 obj = foo('haha',22) 11 obj.detail()
2.继承
继承可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法。
通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”,继承的过程,就是从一般到特殊的过程。
一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
1 class SchoolMember(object): #父类 2 member_nums = 0 3 def __init__(self,name,age,sex): 4 self.name = name 5 self.age = age 6 self.sex = sex 7 self.enroll() 8 9 def enroll(self): 10 SchoolMember.member_nums +=1 11 print("the [%s] SchoolMember [%s] is enrolled!" %(self.member_nums,self.name)) 12 13 def tell(self): 14 print("hello my name is %s" %self.name) 15 16 class Teacher(SchoolMember): #子类,继承父类 17 def __init__(self,name,age,sex,course,salary): 18 super(Teacher,self).__init__(name,age,sex) 19 self.course = course 20 self.salary = salary 21 #SchoolMember.__init__(self,name,age,sex) 旧的写法 22 def teaching(self): 23 print("Teacher [%s] is teaching [%s]" %(self.name,self.course)) 24 25 class Student(SchoolMember): 26 def __init__(self,name,age,sex,course,tuition): 27 super(Student,self).__init__(name,age,sex) #继承 28 self.course = course 29 self.tuition = tuition 30 def pay_tution(self): 31 print("cao,student [%s] paying tution [%s]" %(self.name,self.tuition)) 32 33 t1 = Teacher("haha",50,"男","PY",250) 34 t2 = Teacher("hehe",60,"女","PY",741) 35 36 s1 = Student("nima",24,"男","python",1000) 37 s2 = Student("nimei",23,"女","python",1200) 38 t1.tell() 39 t2.teaching() 40 s1.tell() 41 s2.pay_tution() 42 43 #输出结果 44 #the [1] SchoolMember [haha] is enrolled! 45 #the [2] SchoolMember [hehe] is enrolled! 46 #the [3] SchoolMember [nima] is enrolled! 47 #the [4] SchoolMember [nimei] is enrolled! 48 #hello my name is haha 49 #Teacher [hehe] is teaching [PY] 50 #hello my name is nima 51 #cao,student [nimei] paying tution [1200]
继承多个类
继承多个类,寻找方法的方式,深度优先和广度优先,Python3.0不管新式类还是经典类都是广度优先
深度优先:当类是经典类时,多继承情况下,会按照深度优先方式查找
广度优先:当类是新式类时,多继承情况下,会按照广度优先方式查找
1 class A: 2 n = 'A' 3 def f2(self): 4 print("f2 from A") 5 class B(A): #继承A 6 n = 'B' 7 def f1(self): 8 print("from B") 9 def f2(self): 10 print("f2 from B") 11 class C(A): 12 n = 'C' 13 def f2(self): 14 print("from C") 15 16 class D(B,C): #多继承,先找B,C,A 广度优先 17 '''test class''' 18 def __del__(self): 19 print("deleteing the...") 20 21 #经典类,深度优先,Python3.0不管新式类还是经典类都是广度优先 22 23 d = D() 24 d.f1() 25 d.f2() 26 print(d.__doc__) #打印类的介绍
1 from multi_inheritance import D 2 3 a = D() 4 print(a.__module__) #打印从哪个文件导入
3.多态
多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。多态是为了实现另一个目的——接口重用!多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。
Pyhon不支持多态并且也用不到多态,多态的概念是应用于Java和C#这一类强类型语言中
1 class Animal: 2 def __init__(self, name): # Constructor of the class 3 self.name = name 4 def talk(self): # Abstract method, defined by convention only 5 raise NotImplementedError("Subclass must implement abstract method") 6 7 class Cat(Animal): 8 def talk(self): 9 return 'Meow!' 10 11 class Dog(Animal): 12 def talk(self): 13 return 'Woof! Woof!' 14 15 def animal_talk(obj): #python不需要指定类型,所以没有多态 16 print(obj.talk()) 17 #========================================== 18 c = Cat("nima") 19 d = Dog("nimei") 20 animal_talk(c) 21 animal_talk(d)
其他类型的语言
1 def animal_talk(万能类型,obj): #必须指定类型Dog或者Cat,使用万能类型为多态,接口重用 2 print(obj.talk()) 3 #========================================== 4 c = Cat("nima") 5 d = Dog("nimei") 6 animal_talk(c) 7 animal_talk(d)
四、类的方法与属性
1.类方法
1 class Animal: 2 def __init__(self,name): 3 self.name = name 4 hobbie = "meat" 5 6 @classmethod #类方法,不能访问实例变量 7 def talk(self): 8 print("%s is talking..." % self.name) #不能访问实例变量name 9 print("%s is talking..." % self.hobbie) #类变量可以访问 10 11 d = Animal("yoyo") 12 d.talk()
2.静态方法
1 class Animal: 2 def __init__(self,name): 3 self.name = name 4 hobbie = "meat" 5 6 @staticmethod #静态方法,不能访问类变量及实例变量 7 def walk(self): 8 print(" %s is talking..." % self.hobbie) #不可以 9 10 def walk(): 11 print(" is talking..." ) #正确方法 12 13 d = Animal("yoyo") 14 d.walk()
3.属性
1 @property #把方法变成属性 2 def habit(self): 3 print("%s habit is football" %self.name) 4 d.habit #调用
私有属性,属性的修改和删除
1 class Animal: 2 def __init__(self,name): 3 self.name = name 4 self.__num = None #私有属性 5 6 @property 7 def total_players(self): 8 return self.__num #私有属性,只能在里面自己用,对外面隐藏 9 10 @total_players.setter #修改属性 11 def total_players(self,num): 12 self.__num = num 13 print("total players:",self.__num) 14 @total_players.deleter #删除属性 15 def total_players(self): 16 print("total players got deleted.") 17 del self.__num 18 19 d = Animal("yoyo") 20 print(d.total_players) #None 21 d.total_players = 3 #赋值 22 print(d.__num) #无法访问私有属性 23 d.__num = 9 #外部修改为9,内部还是3 24 print(d.__num) 25 print("OUT:",d._Animal__num) #特例访问私有变量 26 print(d.total_players) #结果为3 27 del d.total_players #删除属性
4.类的特殊成员
(1)__doc__:显示类的描述信息
1 class Foo: 2 """ test class """ #类的介绍 3 def func(self): 4 pass 5 print(d.__doc__) #打印类的介绍
(2)__module__:表示当前操作的对象在那个模块
1 from multi_inheritance import D 2 3 a = D() 4 print(a.__module__) #打印从哪个文件导入
(3)__init__:构造方法,通过类创建对象时,自动触发执行
1 class Foo: 2 3 def __init__(self, name,age): 4 self.name = name 5 self.age = age 6 7 a = Foo("wu",22)
(4)__del__:析构方法,当对象在内存中被释放时,自动触发执行
1 def __del__(self): 2 print("deleteing the...")
(5)__call__:对象后面加括号,触发执行
1 class Foo: 2 3 def __init__(self): 4 pass 5 6 def __call__(self, *args, **kwargs): 7 8 print '__call__' 9 10 11 obj = Foo() # 执行 __init__ 12 obj() # 执行 __call__
(6)__dict__:获取类或对象中的所有成员
1 class Foo: 2 def __init__(self): 3 print('__init__') 4 self.n =4 5 print(obj.__dict__) #以字典的形式显示,可以查看所有变量
6 MyShinyClass = type('MyShinyClass',(),{"test":123}) #一句话定义一个类 7 print(type(MyShinyClass)) #类是由type创建 8 a = MyShinyClass() 9 print(MyShinyClass.test)
五、反射
#反射.py import sys class WebServer(object): def __init__(self,host,port): self.host = host self.port = port def start(self): print("Server is starting...") def stop(self): print("Server is stopping...") def restart(self): self.stop() self.start() if __name__ == "__main__": server = WebServer('localhost',333) #传统解决方法 cmd_dic = { 'start':server.start, 'stop':server.stop } if sys.argv[1] in cmd_dic: cmd_dic[sys.argv[1]]() #输入python 反射.py restart #输出Server is stopping... # Server is starting...
利用反射
import sys class WebServer(object): def __init__(self,host,port): self.host = host self.port = port def start(self): print("Server is starting...") def stop(self): print("Server is stopping...") def restart(self): self.stop() self.start() def test_run(name): print("running...",name) if __name__ == "__main__": server = WebServer('localhost',333) #print(sys.argv[1]) if hasattr(server,sys.argv[1]): #判断 func = getattr(server,sys.argv[1]) #获取server.start 内存地址 func() #server.start() setattr(server,'run',test_run) #设置,把test_run添加到实例 server.run("alex") delattr(server,'host') #删除host delattr(WebServer,'start') #删除start print(server.host) print(server.restart())