面向对象的三大特征
面向对象(Object Oriented),对象=属性+方法
-
封装
对象封装了属性、方法的函数,成为一个独立性的模块(信息隐蔽),使得对象更安全。 -
继承
面向对象的一个重要特性是复用性,继承是实现复用性的一个重要手段,继承就是子对象可以继承父对象的属性和行为,亦即父对象拥有的属性和行为,其子对象也就拥有了这些属性和行为。 -
多态
多态性是指不同对象对同一方法响应不同的行动。
self、_init_(self)、公有&私有
- self
相当于其他语言的this,每次实例化一个对象都保存了不同的self,当进行该对象的操作时,接受到第一个参数self,python则知道是哪一个实例的对象。class Ball: def setName(self, name): self.name = name def kick(self): print('这是%s' % self.name) ball = Ball() ball.setName('足球') ball.kick()
- _init_(self)
类似与其他语言的构造方法,是在实例化对象的时候执行的函数。class Ball: def __init__(self, name): # 可以对name进行参数的默认设置 self.name = name def kick(self): print('这是%s' % self.name) ball = Ball('足球') ball.kick()
- 公有&私有
python的属性和方法默认都是公有的。可以通过 name manging(名字改编)也就是在属性前加上“__”两个下划线就可以变为私有,但是也不是绝对的私有。class Person: __name = 'lz' def getName(self): return self.__name p = Person() # print(p.__name) # 报错AttributeError: 'Person' object has no attribute '__name' print(p.getName()) # lz print(p._Person__name) # lz
##继承的一些特性
继承对象的时候,子类会继承父类的属性和方法,但是前提是子类没有自己的构造函数(__init(self)),若有自己的构造方法(子类会覆盖父类的同名方法)。
- __init__继承父类
子类在使用了自己的__init__的时候,想要继承父类的属性,可以通过以下两种方法- 调用未绑定的父类方法
- 使用super函数
class Fish: def __init__(self, x, y): self.x = x self.y = y class Shark(Fish): def __init__(self, x, y, z): # Fish.__init__(self, x, y) # 方法一:调用未绑定的父类方法,此时的self是子类的实例对象,所以称为未绑定父类的方法。因此容易想到调用的时候可以使用Fish.__init__(shark) super(Shark, self).__init__(x, y) # 方法二:使用super函数,python推荐使用的方法 self.z = z
- python可以实现多重继承,但是python并不推荐。
class Ball(Ball1, Ball2)
- 组合
如果要求定义一个类:水池类,里面有鱼、乌龟。这种情况,可以使用组合的方式。class Turtle: def __init__(self, x): self.num = x class Fish: def __init__(self, x): self.num = x class Pool: def __init__(self, x, y): self.turtle = Turtle(x) self.fish = Fish(y) def print_num(self): print('水池内有乌龟%d条,鱼%d条' % (self.turtle.num, self.fish.num)) pool = Pool(1, 10) pool.print_num()
Mixin编程机制
- 简介
Mixin 编程是一种开发模式,是一种将多个类中的功能单元的进行组合的利用的方式,这听起来就像是有类的继承机制就可以实现,然而这与传统的类继承有所不同。通常 Mixin 并不作为任何类的基类,也不关心与什么类一起使用,而是在运行时动态的同其他零散的类一起组合使用。 - 特点
- 可以在不修改任何源代码的情况下,对已有类进行扩展;
- 可以保证组件的划分;
- 可以根据需要,使用已有的功能进行组合,来实现“新”类;
- 很好的避免了类继承的局限性,因为新的业务需要可能就需要创建新的子类。
- 实现
- 多继承
Python支持多继承,即一个类可以继承多个子类。可以利用该特性,可以方便的实现mixin继承。如下代码,类A,B分别表示不同的功能单元,C为A,B功能的组合,这样类C就拥有了类A, B的功能。
class A: def get_a(self): print 'a' class B: def get_b(self): print 'b' class C(A, B): pass c = C() c.get_a() c.get_b()
- __bases__属性
多继承的实现就会创建新类,有时,我们在运行时,希望给类A添加类B的功能时,也可以利用python的元编程特性,__bases__属性便在运行时轻松给类A添加类B的特性,如下代码:A.__bases__ += (B,) a.get_b() # 其实__bases__也是继承的机制,因为__bases__属性存储了类的基类。因此多继承的方法也可以这样实现: class C: pass C.__bases__ += (A, B, )
- 插件方式
以上两种方式,都是基于多继承和python的元编程特性,然而在业务需求变化时,就需要新的功能组合,那么就需要重新修改A的基类,这回带来同步的问题,因为我们改的是类的特性,而不是对象的。因此以上修改会对所有引用该类的模块都收到影响,这是相当危险的。通常我们希望修改对象的行为,而不是修改类的。同样的我们可以利用__dict__来扩展对象的方法。class PlugIn(object): def __init__(self): self._exported_methods = [] def plugin(self, owner): for f in self._exported_methods: owner.__dict__[f.__name__] = f def plugout(self, owner): for f in self._exported_methods: del owner.__dict__[f.__name__] class AFeature(PlugIn): def __init__(self): super(AFeature, self).__init__() self._exported_methods.append(self.get_a_value) def get_a_value(self): print 'a feature.' class BFeature(PlugIn): def __init__(self): super(BFeature, self).__init__() self._exported_methods.append(self.get_b_value) def get_b_value(self): print 'b feature.' class Combine:pass c = Combine() AFeature().plugin(c) BFeature().plugin(c) c.get_a_value() c.get_b_value()
- 多继承
类、类对象和实例对象
三者是什么:定义的时候是类;在写完类之后就变成类对象;实例化一个类对象的时候,就是实例对象
class Ball:
name = '球'
-
三者的相互影响
类定义 -> 类对象 -> 实例对象。类定义中定义的属性都是静态属性,类属性和类对象相互绑定,不会依赖实例化对象。所以当实例对象的属性改变时,只是实例属性覆盖了类属型。反之,当实例对象的属性没改变,那就是还受类属型的影响class Fish: size = 10 a = Fish() b = Fish() c = Fish() print(a.size, b.size, c.size) # 10 10 10 c.size += 10 print(a.size, b.size, c.size) # 10 10 20 Fish.size += 100 print(a.size, b.size, c.size) # 110 110 20
-
类属性名和方法同名时,方法会被覆盖
-
绑定
python严格要求方法需要实例才能调用,这其实就是python的绑定概念。class BB: def setXY(self, x, y): self.x = x self.y = y def printXY(self): print(self.x, self.y) bb = BB() print(bb.__dict__) print(BB.__dict__) bb.setXY(5, 10) # 这里其实相当于bb.setXY(bb, 5, 10) print(bb.__dict__) print(BB.__dict__) del BB # cc = BB() # 报错 bb.printXY() # 5 10。因为实例化之后,就成为了静态属性,所以不会受影响
对象的内置方法
下面介绍对象的一些内置方法(本身具备有的)。
- issubclass(class, classinfo)
如果class是classinfo的子类就返回True,其他情况则返回False,有些特殊情况:- 一个类是自身的子类
- classinfo可以是类对象组成的元组,只要与其中一个匹配,则返回True
- issubclass(className, object) # True
- isinstance(obecjt, classinfo)
检查一个实例对象obecjt,是否属于classinfo类,同样classinfo可以是元组的格式。- 如果第一个参数object不是对象,则永远返回False
- 如果第二个参数classinfo不是类或者类对象组成的元组,会抛出“TypeError”的异常
- hasattr(object, name)
查看实例对象object,是否有参数name,其中name是字符串的格式。 - getattr(object, name[, default])
返回对象object指定的属性值name,如果指定的属性不存在,则返回定义的default,如果没有定义默认值,则抛出异常NameError…not defined - setattr(object, name, value)
设置对象object指定的属性值name,如果属性不存在,则会新建该指定属性,值为value - delattr(object, name)
删除对象object指定的属性值name,如果属性不存在,则抛出异常AttributeError
class A:
def __init__(self, x=1):
self.x = x
class B(A):
def __init__(self, x, y=-1):
super(B, self).__init__(x)
self.y = y
b1 = B(2, -2)
print(issubclass(B, B)) # True
print(issubclass(B, (A, object))) # True
print(isinstance(b1, (A, object))) # True
print(hasattr(b1, 'x'), b1.x) # True 2
print(hasattr(b1, 'y'), b1.y) # True -2
print(getattr(b1, 'x', 10)) # 2
print(getattr(b1, 'z', 'z参数不存在')) # z参数不存在
print(setattr(b1, 'x', 10), b1.x) # None 10
print(setattr(b1, 'z', 'z参数不存在'), b1.z) # None z参数不存在
print(delattr(b1, 'x')) # None delattr
- property(fget=None, fset=None, fdel=None, doc=None)
通过类定义的属性设置属性。
class C:
def __init__(self, size = 10):
self.size = size
def getSize(self):
return self.size
def setSize(self, value):
self.size = value
def delSize(self):
del self.size
x = property(getSize, setSize, delSize)
c1 = C(20)
# 获取
print(c1.getSize()) # 20
print(c1.x) # 20
# 设置
c1.x = 30
print(c1.x) # 30
# 删除
del c1.x
# print(c1.x) # 报错
文章参照小甲鱼
个人博客:Loak 正 - 关注人工智能及互联网的个人博客
文章地址:Python基础(十)—面向对象的深入讲解(继承、Mixin编程机制等)