面向对象基础

面向对象编程(Object Oriented Programming,OOP)

  1. 面向过程编程最易被初学者接受,其往往用一长段代码来实现指定功能,开发过程中最常见的操作就是粘贴复制,即:将之前实现的代码块复制到现需功能处。
  2. Java和C#只支持面向对象编程,而python比较灵活,即支持面向对象编程也支持函数式编程。
  3. 面向对象三大特性:封装继承多态

一、封装

封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
调用被封装的内容时,有两种情况:

  1. 通过对象直接调用
  2. 通过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)

五、旧式类与新式类

旧式类与新式类区别总结:

  1. 在python2.x的版本才有新式类和旧式类之分
  2. 新式类的存在是为了统一类(class)和类型(type)
  3. 旧式类定义class AA,新式类class AA(object)
  4. 在多重继承的查找和调用方法上,旧式类是深度优先,新式类是广度优先
  5. 在python2.x版本中为了确保自己使用的是新式类,有以下方法:
    (a)_metaclass_ = type
    (b)自己的类都从内建类object直接或者间接地继承
  6. 在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))
posted @ 2016-11-07 01:08  morra  阅读(418)  评论(0)    收藏  举报