名词:
OOP编程是利用“类”和“对象”来创建各种模型来实现对真实世界的描述,使用面向对象编程的原因一方面是因为它可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。
面向对象的几个核心特性如下
Class 类
一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法, 例如人类,蛇类,猫科类
Object 对象
一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同,比如类(人类)----》对象(隔壁老王)
Encapsulation 封装
在类中对数据的赋值、内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里面包含着类的数据和方法
Inheritance 继承
一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承
Polymorphism 多态
多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,指一个基类中派生出了不同的子类,且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现,这就是同一种事物表现出的多种形态。
编程其实就是一个将具体世界进行抽象化的过程,多态就是抽象化的一种体现,把一系列具体事物的共同点抽象出来, 再通过这个抽象的事物, 与不同的具体事物进行对话。
对不同类的对象发出相同的消息将会有不同的行为。比如,你的老板让所有员工在九点钟开始工作,
他只要在九点钟的时候说:“开始工作”即可,而不需要对销售人员说:“开始销售工作”,对技术人员说:“开始技术工作”,
因为“员工”是一个抽象的事物, 只要是员工就可以开始工作,他知道这一点就行了。至于每个员工,当然会各司其职,做各自的工作。
多态允许将子类的对象当作父类的对象使用,某父类型的引用指向其子类型的对象,调用的方法是该子类型的方法。这里引用和调用方法的代码编译前就已经决定了,而引用所指向的对象可以在运行期间动态绑定
类的变量和实例变量
类变量:大家共用的属性,在实例化不会创建在实例的内存中,可以节省开销。
实例变量:描述每个实例的属性
class Dog:#创建一个Dog类 n=123#类变量 name='page' #类变量 def __init__(self,name,age): #类属性 self.name=name self.age=age def wang(self,name):类方法 print("%s is wang"%name) Dog.n="nihaho" d1=Dog("index",12) d1.n=12345 print(d1.n) d2=Dog("home",13) print(d2.n)
打印结果
12345
nihaho
当实例调用类变量,并且给类变量赋值时,类变量会在实例的内存拷贝一份。修改类变量,实例调用的类变量不会变。12345
当实例仅调用类变量,这时类变量在类的内存中,修改类变量,实例调用的类变量会变。nihao
封装:
上面程序生成实例d1=Dog("index",12),只需传入参数,实例也可以调用很多方法。但是内部是怎么实现的是看不见的,所以类起到了一个封装的作用。
继承:
单继承
#class People:经典类 class People(object):#新式类 def __init__(self,name,age): self.name=name self.age=age def eat(self): print("%s is eating..."%self.name) def talk(self): print("%s is talking..."%self.name) def sleep(self): print("%s is sleeping..."%self.name) class Man(People):#继承父类 def __init__(self,name,age,money): People.__init__(self,name,age) #重构父类属性 经典类继承写法 #super(Man,self).__init__(name,age) super方法也可以 新式类继承写法 self.money=money print("%s一出生就有%s钱"%(self.name,self.money)) def see(self): print("%s is see...."%self.name) # def sleep(self): # print("man is sleepiong...") 这是完全覆盖父类方法 def sleep(self): People.sleep(self) #重构父类方法 print("man is sleeping...") class Women(People): def drunk(self): print("%s is drunk ...."%self.name) m1=Man("bob",22,10) m1.eat() m1.see() m1.sleep() w1=Women("alice",21) w1.drunk()
多继承
class People(object): def __init__(self,name,age): self.name=name self.age=age def eat(self): print("%s is eating..."%self.name) def talk(self): print("%s is talking..."%self.name) def sleep(self): print("%s is sleeping..."%self.name) class Relation(object): def make_friends(self,obj): print("%s is make friends with %s"%(self.name,obj.name)) class Man(People,Relation): def __init__(self,name,age,money): #People.__init__(self,name,age) #重构父类属性 经典类继承写法 super(Man,self).__init__(name,age) #super方法也可以 新式类继承写法 self.money=money print("%s一出生就有%s钱"%(self.name,self.money)) def see(self): print("%s is see...."%self.name) def sleep(self): People.sleep(self) print("man is sleeping...") class Women(People,Relation): def drunk(self): print("%s is drunk ...."%self.name) m1=Man("bob",22,10) # m1.eat() # m1.see() # m1.sleep() w1=Women("alice",21) # w1.drunk() m1.make_friends(w1)
python 支持多继承,但对与经典类和新式类来说,多继承查找的顺序是不一样的。
py2 经典类是按深度优先来继承的,新式类是按广度优先来继承的
py3 经典类和新式类都是统一按广度优先来继承的
深度优先
class P1: def foo(self): print 'p1-foo' class P2 : def foo(self): print 'p2-foo' def bar(self): print 'p2-bar' class C1 (P1,P2): pass class C2 (P1,P2): def bar(self): print 'C2-bar' class D(C1,C2): pass
执行结果
d = D()
d.foo() # 输出 p1-foo
d.bar() # 输出 p2-bar
实例d调用foo()时,搜索顺序是 D => C1 => P1
实例d调用bar()时,搜索顺序是 D => C1 => P1 => P2
换句话说,经典类的搜索方式是按照“从左至右,深度优先”的方式去查找属性。d先查找自身是否有foo方法,没有则查找最近的父类C1里是否有该方法,如果没有则继续向上查找,直到在P1中找到该方法,查找结束。
广度优先
class P1(object): def foo(self): print 'p1-foo' class P2(object): def foo(self): print 'p2-foo' def bar(self): print 'p2-bar' class C1 (P1,P2): pass class C2 (P1,P2): def bar(self): print 'C2-bar' class D(C1,C2): pass
执行结果 d=D() d.foo() # 输出 p1-foo d.bar() # 输出 c2-bar
实例d调用foo()时,搜索顺序是 D => C1 => C2 => P1
实例d调用bar()时,搜索顺序是 D => C1 => C2
可以看出,新式类的搜索方式是采用“广度优先”的方式去查找属性。
多态:
class Animal(object): def __init__(self, name): # Constructor of the class self.name = name def talk(self): # Abstract method, defined by convention only raise NotImplementedError("Subclass must implement abstract method") class Cat(Animal): def talk(self): print('%s: miao miao!' %self.name) class Dog(Animal): def talk(self): print('%s: wang wang' %self.name) def func(obj): #一个接口,多种形态 obj.talk() c1 = Cat('index') d1 = Dog('home') func(c1) func(d1)
执行结果
index: miao miao!
home: wang wang
func这是一个接口,输入不同的对象,输出结果不同,一个接口多种形态.
类的静态方法:
静态方法 只是名义上归类管理, 实际上在静态方法里访问不了类或实例中的任何属性
class Dog(object): def __init__(self,name): self.name=name @staticmethod #类的静态 def eat(self): print("%s is eating %s"%(self.name,'baozi')) d1=Dog("alice") d1.eat(d1)#把实例传进去
类方法:
只能访问类变量,不能访问实例变量
class Dog(object): name="bob" #如果吧name注释 程序出错 def __init__(self,name): self.name=name #@staticmethod #类的静态方法 @classmethod #类方法 def eat(self): print("%s is eating %s"%(self.name,'baozi')) d1=Dog("alice") # d1.eat(d1)#把实例传进去 d1.eat()
打印结果
bob is eating baozi
属性方法:
把一个方法变成一个静态属性
class Flight(object): def __init__(self,name): self.flight_name = name def checking_status(self): print("checking flight %s status " % self.flight_name) return 0 @property def flight_status(self): status = self.checking_status() if status == 0 : print("flight got canceled...") elif status == 1 : print("flight is arrived...") elif status == 2: print("flight has departured already...") else: print("cannot confirm the flight status...,please check later") @flight_status.setter def flight_status(self,status): print("flight %s has changed status to %s" %(self.flight_name,status)) f = Flight("CA980") f.flight_status
属性方法的用途如上
反射:
通过字符串映射或修改程序运行时的状态、属性、方法, 有以下4个方
hasattr(obj,name)判断object中有没有一个name字符串对应的方法或属性
getattr(obj,name)根据字符串去获取obj对象里的对应的方法的内存地址
举例
class Dog(object): def __init__(self,name): self.name=name def eat(self): print("%s is eating...",self.name) d=Dog("alice") choice=input(">>:").strip() # print(hasattr(d,choice)) # # print(getattr(d,choice)) # getattr(d,choice)() if hasattr(d,choice): 判断object中有没有一个name字符串对应的方法或属性 func=getattr(d,choice)根据字符串去获取obj对象里的对应的方法的内存地址
func()调用
输入字符串调用实例的方法.
setattr(obj,name)# real signature unknown; restored from __doc__
""" Sets the named attribute on the given object to the specified value. setattr(x, 'y', v) is equivalent to ``x.y = v''
delattr(x,y)#real signature unknown; restored from __doc__
"""
Deletes the named attribute from the given object.
delattr(x, 'y') is equivalent to ``del x.y''
"""
def bulk(self): print(" %s is jiao ...",self.name) class Dog(object): def __init__(self,name): self.name=name def eat(self): print("%s is eating...",self.name) d=Dog("alice") choice=input(">>:").strip() # print(hasattr(d,choice)) # # print(getattr(d,choice)) # getattr(d,choice)() if hasattr(d,choice): func=getattr(d,choice) func() else: setattr(d,choice,bulk) 给类增加一个属性 d.talk(d)
注: 参考 http://www.cnblogs.com/alex3714/articles/5213184.html