底层与方法
文章目录
1. 与函数的区别
调用方式不同
2. 方法的划分
- 实例方法:第一个参数是实例
- 类方法:第一个参数是类
- 静态方法:第一个参数没有要求
- 注意:
- 区分依据:观察第一个参数的默认类型
- 所有类型的方法都存储在类当中
- 不同方法调用方式不同,保证不同类型的方法第一个参数收 到的数据是其期望的类型
- 使用:
- 语法
- 不同类型的方法规则以及调用
- 根据不同的问题,自主决定,适合设计什么样的方法解决问题
3. 实例方法
#定义
class ClassName:
def funcname(self):
pass
#实例化并调用
c = ClassName()
c.funcname()
- 调用:
- 标准调用:使用实例调用实例方法,解释器自动把调用对象本身传递过去;如果实例方法没有接受到任何参数,就会报错
4. 类方法
#定义
class ClassName:
#装饰器
@classmethod
def func(cls):
print("this is a classmethod",cls)
#类调用
ClassName.func()
c = ClassName()
#会找到实例的类,用类调用,实例会被忽略
c.func()
class A:
pass
#使用延伸类调用类方法的话,会把延伸类本身作为第一个参数传递给类方法
A.func()
- 注意:
- 装饰器的作用:在保证原本函数不改变的前提下,直接给这个函数增加一些功能
5. 静态方法
class Person:
#装饰器
@staticmethod
def jingtai():
pass
- 注意:
- 既可以通过实例调用也可以用类调用
6. 不同类型的方法访问不同类型的属性规律
- 实例可以访问类的属性
- 类不能访问实例的属性
- 实例的属性可以在类外定义后,调用实例方法也依然能访问到该属性
7.Python对象的生命周期及方法
- 一个对象从诞生到消亡的过程
- 当一个对象被创建,会在内存中分配相应的内存空间进行存储
- 当这个对象不再使用,为了节约内存,就会把对象释放
- 监听对象的生命周期
- __new__方法:新建一个对象时,给对象分配内存的方法,拦截调用,即可修改对象创建过程
- __init__方法:对一个对象进行初始化
- __del__方法:当一个对象被释放时,自动调用
一个代码案例
# Person, 打印一下, 当前这个时刻, 由Person类, 产生的实例, 由多少个
# 创建了一个实例, 计数 + 1, 如果, 删除了一个实例, 计数 - 1
class Person:
#类的私有属性
__personCount = 0
def __init__(self):
print("计数 + 1")
#类名调用
Person.__personCount += 1
def __del__(self):
print("计数 - 1")
#实例的类的调用
self.__class__.__personCount -= 1
@classmethod
def log(cls):
#类对象调用
print("当前的人的个数是%d个" % cls.__personCount)
p = Person() #输出:计数+1
p2 = Person() #输出: 计数+1
Person.log() #输出:当前的人的个数是2个
del p #输出:计数-1
del p2 #输出:计数-1
Person.log() #输出:当前的人的个数是0个
- python中万物皆对象,所有对象,都会在内存中开辟一块空间进行存储
- 会根据不同类型和内容,开辟不同的空间大小进行存储,返回该空间地址给外界接收(“引用”)
- 可以同过
id()
获取内存地址;或者hex()
查看对应的16进制地址 - 对于整数和短小字符,python会进行缓存,不会创建多个相同的对象【此处结合python的
可变不可变数据类型
进行学习,可以参考我另一笔记】 - 容器对象,存储的其他对象,仅仅是其他对象的引用,而非其他对象本身
python的 内存管理机制 = 引用计数器机制 +垃圾回收机制
- 引用计数器:一个对象,会记录自身被引用的个数
- 查看引用计数
import sys
#注意会比实际大1,但结束后会自动减1的
sys.getrefcount(对象)
- 引用计数器 + 1 场景:
- 被创建:p1 = Person()
- 被引用:p2 = p1
- 作为参数传入一个函数
- 作为一个元素存储在容器中:l = [p1]
- 引用计数器 - 1 场景:
- 被显示销毁: del p1
- 别名被赋予新的对象: p1 = 123
- 一个对象离开它的作用域:函数执行完毕时;
- 对象所在容器被销毁,或从容器中删除对象
-
垃圾回收:从经历过“引用计数器机制”仍未被释放的对象中,找到“循环引用”,干掉相关对象。【即,主要解决循环引用问题】
-
“循环引用”查找【较难,了解即可】:
- 收集所有的容器对象[可以引用其他对象的对象,如列表、元组、字典、自定义对象等]
- 对每个容器对象,通过变量gc_refs来记录当前对应的引用计数;
- 对每个容器对象,找到它引用的容器对象,并将这个容器对象的引用计数-1
- 经过上述步骤后,若一个容器对象的引用计数为0,就表示被回收了,肯定是循环引用致使其存活到现在
-
分代回收【提升循环引用回收的性能】
- 默认一个对象被创建出来后,属于0代
- 如果经过这一代的“垃圾回收”后,依然存活,则划分到下一代
- 其周期顺序为:
- 0代“垃圾回收”一定次数,会触发0代和1代回收
- 1代“垃圾回收”一定次数,会触发0代、1代、二代回收
- 查看和设置相关参数
import gc print(gc.get_threshold) #参数详解 #700:新增数-消亡数 = 700触发检测 #10: 0代检测十次触发0&1代检测 #5: 1代检测5次触发0&1&2的检测 gc.set_threshold(700,10,5)
-
注意:垃圾回收器中,新增的对象个数-消亡的对象个数,达到一定的阈值时,才会触发垃圾检测
-
垃圾回收时机
- 自动回收:开启垃圾回收机制且打到了垃圾回收阈值
import gc gc.enable() #开启垃圾回收机制(默认开启) gc.disable() #关闭垃圾回收机制 gc.isenbaled() #判断是否开启
- 手动回收:
- 利用弱引用
weakref.ref(对象)
;或者自己将引用指向None - 多个弱引用可以使用
weakref.WeakValueDictionary(字典对象)
- 利用弱引用