面向对象编程(Object Oriented Programming,OOP)
- 面向过程编程最易被初学者接受,其往往用一长段代码来实现指定功能,开发过程中最常见的操作就是粘贴复制,即:将之前实现的代码块复制到现需功能处。
- Java和C#只支持面向对象编程,而python比较灵活,即支持面向对象编程也支持函数式编程。
- 面向对象三大特性:封装、继承、多态。
一、封装
封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
调用被封装的内容时,有两种情况:
- 通过对象直接调用
- 通过self间接调用
#1. 通过对象直接调用
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age
obj1 = Foo('morra', 18)
print obj1.name # 直接调用obj1对象的name属性
print obj1.age # 直接调用obj1对象的age属性
#2. 通过self间接调用
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age
def detail(self):
print self.name
print self.age
obj1 = Foo('morra', 18)
obj1.detail() # Python默认会将obj1传给self参数,所以,此时方法内部的 self = obj1
综上所述,对于面向对象的封装来说,其实就是使用__init__方法将内容封装到对象中,然后通过对象直接或者self间接获取被封装的内容。
二、继承
继承,就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法。父类也叫基类,子类也叫派生类。
class Animals: #基类
def __init__(self, name):
self.name = name
def eat(self):
pass
def drink(self):
pass
class Dog(Animals): #派生类
def __init__(self, name):
self.name = name
def bark(self):
print('汪')
obj_dog = Dog('morra')
obj_dog.eat()
obj_dog.bark()
(1) 单继承
优先级是,先子类后父类
(2) 多继承
python可以同时继承多个类(C# java是不可以的)。
优先级是,先子类后父类,父类里面先左再右,广度优先。
#新式类的广度优先查找
class D(object):
def bar1(self):
print 'D.bar'
class C(D):
def bar(self):
print 'C.bar'
class B(D):
def bar(self):
print 'B.bar'
class A(B, C):
def bar(self):
print 'A.bar'
a = A()
# 执行bar方法时
# 查找顺序:A --> B --> C --> D
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()
(3) 执行父类的构造方法
#方法一:super,通过python多继承的原则查找
class Animal:
def __init__(self):
print('A构造方法')
self.ty = "动物"
class Cat(Animal):
def __init__(self):
print('B构造方法')
self.n = "猫"
super(Cat,self).__init__() #执行父类的构造方法,推荐用super()
c = Cat()
print(c.__dict__)
# ---------
# B构造方法
# A构造方法
# {'n': '猫', 'ty': '动物'}
#方法二:Animal,直接指定基类(不建议使用)
class Animal:
def __init__(self):
print('A构造方法')
self.ty = "动物"
class Cat(Animal):
def __init__(self):
print('B构造方法')
self.n = "猫"
Animal.__init__(self) #不推荐
c = Cat()
print(c.__dict__)
# ---------
# B构造方法
# A构造方法
# {'n': '猫', 'ty': '动物'}
三、多态
Pyhon不支持Java和C#这一类强类型语言中多态的写法,但是原生多态,其Python崇尚“鸭子类型”。
python的“鸭子类型”:
class F1:
pass
class S1(F1):
def show(self):
print 'S1.show'
class S2(F1):
def show(self):
print 'S2.show'
def Func(obj):
print obj.show()
s1_obj = S1()
Func(s1_obj)
s2_obj = S2()
Func(s2_obj)
四、反射在面向对象里的应用
class Foo:
def __init__(self,name):
self.name = name 对象.属性=变量
pass
def show(self):
pass
obj = Foo('morra')
r = hasattr(Foo, 'show') #只能找类里的成员
print(r) # True
r = hasattr(obj, 'name') #在对象中可以找自己的属性,就是self.name中的name属性
print(r) # True
r = hasattr(obj, 'show') #对象中也可以找类的成员,是通过python里的类对象指针来实现的
print(r) # True
m = __import__('s1',fromlist=True) #通过反射获取模块
class_name = getattr(m,"Foo") #在模块中获取Foo类
obj = class_name('morra') #实例化
val = getattr(obj,'name') #获取类中的name属性
print(val)
五、旧式类与新式类
旧式类与新式类区别总结:
- 在python2.x的版本才有新式类和旧式类之分
- 新式类的存在是为了统一类(class)和类型(type)
- 旧式类定义class AA,新式类class AA(object)
- 在多重继承的查找和调用方法上,旧式类是深度优先,新式类是广度优先
- 在python2.x版本中为了确保自己使用的是新式类,有以下方法:
(a)_metaclass_ = type
(b)自己的类都从内建类object直接或者间接地继承 - 在Python3里面,不存在这些问题了,因为所有的类都是object类的子类(隐式),python3中都是新式类,即使用广度优先的查找方法
(1) 定义形式
#python2.7中的旧式类
class AA():
pass
a = AA()
print(type(a)) #<type 'instance'>
print(type(AA)) #<type 'classobj'>
#python2.7中的新式类
class AA(object):
pass
a = AA()
print(type(a)) #<class '__main__.AA'>
print(type(AA)) #<type 'type'>
#python3中的新式类
class AA(object):
pass
a = AA()
print(type(a)) ## <class '__main__.AA'>
print(type(AA)) # <class 'type'>
(2) 多重继承时的查找规则
#旧式类的深度优先查找
class D:
def bar1(self):
print 'D.bar'
class C(D):
def bar(self):
print 'C.bar'
class B(D):
def bar(self):
print 'B.bar'
class A(B, C):
def bar(self):
print 'A.bar'
a = A()
# 执行bar方法时
# 查找顺序:A --> B --> D --> C
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()
#新式类的广度优先查找
class D(object):
def bar1(self):
print 'D.bar'
class C(D):
def bar(self):
print 'C.bar'
class B(D):
def bar(self):
print 'B.bar'
class A(B, C):
def bar(self):
print 'A.bar'
a = A()
# 执行bar方法时
# 查找顺序:A --> B --> C --> D
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()
六、补充
(1) isinstance(obj, cls)
检查是否obj是否是类 cls 的对象
class Foo(object):
pass
obj = Foo()
isinstance(obj, Foo)
(2) issubclass(sub, super)
检查sub类是否是 super 类的派生类
class Foo(object):
pass
class Bar(Foo):
pass
issubclass(Bar, Foo)
(3) __base__父类查询
用 _base_ 属性来查询某个类的父类
class father:
pass
class child(father):
pass
print(father) #<class '__main__.father'>
print(child.__base__) #<class '__main__.father'>
(4) __class__查询对象所属的类和类名
a = [1, 2, 3]
print(a.__class__) #<class 'list'>,查询对象所属的类
print(type(a)) #<class 'list'>
print(a.__class__.__name__) #list,查询对象所属类的类名
(5) 查询对象的属性
除了使用dir()来查询对象的属性之外,我们可以使用下面内置(built-in)函数来确认一个对象是否具有某个属性:
hasattr(obj, attr_name) # attr_name是一个字符串
例如:
a = [1,2,3]
print(hasattr(a,'append'))
(6) 查询函数的参数
import inspect
print(inspect.getargspec(func))