目录
析构函数__del__()
释放对象时自动调用
析构函数手动释放对象,对象释放以后就不能再访问了
class Preson(object):
def say(self):
print(self.__class__)
def __del__(self):
print("析构函数")
a = Preson()
a.say()
#释放对象
del a
a.say()
在函数里定义的对象,会在函数结束时释放,这样可以用来减少内存空间的内存
def fun():
a = Preson()
fun()
垃圾回收机制
Python的GC模块主要运用了引用计数来跟踪和回收垃圾。在引用计数的基础上,还可以通过“标记-清除”解决容器对象可能产生的循环引用的问题。通过分代回收以空间换取时间进一步提高垃圾回收的效率。
引用计数
原理:当一个对象的引用被创建或者复制时,对象的引用计数加1;当一个对象的引用被销毁时,对象的引用计数减1,当对象的引用计数减少为0时,就意味着对象已经再没有被使用了,可以将其内存释放掉。
优点:引用计数有一个很大的优点,即实时性,任何内存,一旦没有指向它的引用,就会被立即回收,而其他的垃圾收集技术必须在某种特殊条件下才能进行无效内存的回收。
缺点:但是它也有弱点,引用计数机制所带来的维护引用计数的额外操作与Python运行中所进行的内存分配和释放,引用赋值的次数是成正比的,这显然比其它那些垃圾收集技术所带来的额外操作只是与待回收的内存数量有关的效率要低。同时,引用技术还存在另外一个很大的问题-循环引用,因为对象之间相互引用,每个对象的引用都不会为0,所以这些对象所占用的内存始终都不会被释放掉。
标记-清除
标记-清除只关注那些可能会产生循环引用的对象,显然,像是PyIntObject、PyStringObject这些不可变对象是不可能产生循环引用的,因为它们内部不可能持有其它对象的引用。Python中的循环引用总是发生在container对象之间,也就是能够在内部持有其它对象的对象,比如list、dict、class等等。这也使得该方法带来的开销只依赖于container对象的的数量???
原理:1. 寻找跟对象(root object)的集合作为垃圾检测动作的起点,跟对象也就是一些全局引用和函数栈中的引用,这些引用所指向的对象是不可被删除的;2. 从root object集合出发,沿着root object集合中的每一个引用,如果能够到达某个对象,则说明这个对象是可达的,那么就不会被删除,这个过程就是垃圾检测阶段;3. 当检测阶段结束以后,所有的对象就分成可达和不可达两部分,所有的可达对象都进行保留,其它的不可达对象所占用的内存将会被回收,这就是垃圾回收阶段。(底层采用的是链表将这些集合的对象连接在一起)
缺点:标记和清除的过程效率不高。
分代回收
原理:将系统中的所有内存块根据其存活时间划分为不同的集合,每一个集合就成为一个“代”,Python默认定义了三代对象集合,垃圾收集的频率随着“代”的存活时间的增大而减小。也就是说,活得越长的对象,就越不可能是垃圾,就应该减少对它的垃圾收集频率。那么如何来衡量这个存活时间:通常是利用几次垃圾收集动作来衡量,如果一个对象经过的垃圾收集次数越多,可以得出:该对象存活时间就越长。
重写__repr__()与__str__()函数
重写:将函数重新定义写一遍
__str__():在调用print打印对象时自动调用,str给用户用的,描述对象的方法
__repr__():是给机器用的,在python解释器里直接敲对象名再回车调用的方法
注意:在没有str时且有repr,str = repr
class Preson(object):
def __init__(self,name,age,sex,height):
self.name = name
self.age = age
self.sex = sex
self.height =height
def __str__(self):
return "%s-%d-%s-%d" % (self.name,self.age,self.sex,self.height)
a = Preson("kkk",18,"男",170)
print(a)
访问限制 __XX 变量
如果要让内部的属性不被外部直接访问,就在属性前加两个下划线__
在python中,在属性前加两个下划线,那么这个属性就变成了私有属性(private)
属性不能在外部直接访问
class Preson(object):
def __init__(self,name,age,sex,height):
self.name = name
self.__age = age
self.__sex = sex
self.__height =height
a = Preson("kkk",18,"男",170)
print(a.__age)
不能直接访问__age是因为python解释器把__money变成了_Preson__money,仍然可以用_Preson__money去访问,但是不建议这样做。不同版本解释器解释的变量名不同
class Preson(object):
def __init__(self,name,age,sex,height):
self.name = name
self.__age = age #_Preson__age
self.__sex = sex
self.__height =height
a = Preson("kkk",18,"男",170)
print(a._Preson__age)
在python中 __XXX__ 这样的变量(属性)叫做特殊变量,不是私有变量,可以直接访问
在python中 _XXX 这样的变量可以直接被访问,但是按照约定的规则,当我们看到这样的变量时,意思是“虽然可以被直接访问,但是请视作私有变量,不要直接访问”
用中文写人开枪射击子弹的代码
"""
类:人
属性:枪
行为:开枪
类:枪
属性:弹夹
行为:射击
类:弹夹
属性:子弹个数
行为:
"""
class 弹夹(object):
def __init__(self,子弹个数):
self.子弹个数 = 子弹个数
class 枪(object):
def __init__(self,弹夹):
self.弹夹 = 弹夹
def 射击(self):
if self.弹夹 == 0:
print("没有子弹")
else:
self.弹夹 -= 1
print("剩余子弹为:%d发" % self.弹夹)
class 人(object):
def __init__(self,枪):
self.枪 = 枪
def 开枪(self):
self.枪.射击()
#给弹夹赋5发子弹
bulletbox = 弹夹(5).子弹个数
#枪,把弹夹给枪
gun = 枪(bulletbox)
#人,把枪给人
person = 人(gun)
person.开枪()
person.开枪()
person.开枪()
person.开枪()
person.开枪()
person.开枪()
继承
有两个类A类和B类,当B类继承自A类时,就是B类拥有A类的所有属性和方法
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
兔子和羊属于食草动物类,狮子和豹属于食肉动物类。
食草动物和食肉动物又是属于动物类。
所以继承需要符合的关系是:is-a,父类更通用,子类更具体。
虽然食草动物和食肉动物都是属于动物,但是两者的属性和行为上有差别,所以子类会具有父类的一般特性也会具有自身的特性。
继承的作用
简化了代码,减少了冗余。继承简化了人们对事物的认识和描述,能清晰体现相关类间的层次结构关系。
提高了代码的健壮性
提高了代码的安全性
继承是在一些比较一般的类的基础上构造、建立和扩充新类的最有效的手段。
是多态的前提,然而使用继承的同时也提高了类的耦合度。
Student类继承Person类
class Student(Preson)
class Preson(object):
def run(self):
print("run")
def eat(self,food):
print("eat "+food)
def __init__(self,name,age):
self.name = name
self.age = age
class Student(Preson):
pass
a = Student("wangming",18)
print(a.name)
a.run()
a.eat("orange")
子类不能继承父类的私有属性
class Preson(object):
def run(self):
print("run")
def eat(self,food):
print("eat "+food)
def __init__(self,name,age,height):
self.name = name
self.age = age
self.__height = height
class Student(Preson):
pass
a = Student("wangming",18,20)
print(a.name)
print(a.height)
多继承的实现
child类继承了Father类和Mother类
注意:父类中方法名相同,默认调用的是括号中排前面的父类的方法
class Father(object):
def __init__(self,money):
self.money = money
def play(self):
print("play")
def fun(self):
print("fun1")
class Mother(object):
def __init__(self,face):
self.face = face
def eat(self):
print("eat")
def fun(self):
print("fun2")
class Child(Father,Mother):
def __init__(self,money,face):
Father.__init__(self,money)
Mother.__init__(self,face)
def main():
a = Child(1000, "good")
print(a.money, a.face)
a.play()
a.eat()
#注意:父类中方法名相同,默认调用的是括号中排前面的父类的方法
a.fun()
if __name__ == '__main__':
main()
多态
继承是多态的前提
多态:一种事务的多种形态,同一个行为具有多个不同表现形式或形态的能力
多态的优点
- 1. 消除类型之间的耦合关系
- 2. 可替换性
- 3. 可扩充性
- 4. 接口性
- 5. 灵活性
- 6. 简化性
多态存在的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象
Animal这种事务有多种形态,人喂各种动物
class Animal(object):
def __init__(self,name):
self.name = name
def eat(self):
print(self.name+" 吃")
class Mouse(Animal):
def __init__(self, name):
super(Mouse,self).__init__(name)
class Cat(Animal):
def __init__(self, name):
super(Cat, self).__init__(name)
class Person(object):
#一个方法,一百种动物都可以吃,前提是动物都继承自Animal
def feed(self,animal):
print("拿来食物")
animal.eat()
def main():
tom = Mouse("tom")
jerry = Cat("jerry")
a = Person()
a.feed(tom)
a.feed(jerry)
if __name__ == '__main__':
main()
一起学习,一起进步 -.- ,如有错误,可以发评论