内存管理及内建函数
元类
类也是对象(属于元类的对象)
#打印字符串(字符串是对象)
print("HelloWorld")
#打印类名,类同样为一个对象
print(Person)
使用动态创建类:
语法:
type(类名,由父类名称组成的元组(可以为空),包含属性的字典(名称和值))
案例1:使用type创建类
Myclass = type("MyClass", (), {})
m1 = Myclass()
print(type(m1))
案例2:使用type创建带有属性(方法)的类
def show(self):
print("---num---%d" % self.num)
# 使用元类(type)创建类
Test = type("Test", (), {"show": show})
t = Test()
t.num = 100
t.show()
案例3:使用type动态创建一个继承指定类的类
class Animal(object):
def __init__(self, color="Yellow"):
self.color = color
def eat(self):
print("吃掉你")
Dog = type("Dog", (Animal,), {})
dog=Dog()
dog.eat()
print(dog.color)
类装饰器
class Test(object):
def __init__(self, func):
print("---初始化---")
print("func name is %s" % func.__name__)
self.__func = func
# 重写该方法后,对象可以直接进行调用
def __call__(self, *args, **kwargs):
print("--装饰器中的功能--")
self.__func()
# @Test等价于test=Test(test)装饰器的特性
@Test
def test():
print('--test函数--')
test()
class AAA(object):
def __init__(self, func):
self.__func = func
def __call__(self, *args, **kwargs):
self.addFunc()
self.__func()
def addFunc(self):
print("用户权限验证")
print("日志系统处理")
@AAA
def text1():
print("我是功能1")
对象池
1.数值类型
小整数池:[-5,256]
程序开始时,一次性加载到内存
LEGB(局部变量,闭包中的变量,全局变量,内建变量)全局都是同一个地址
可以用id():或者is 来判断
超过小整数的范围,内存就发生改变了。
大整数池
大整数池默认创建出来,池内为空的,创建一个就会往池中存储一个
字符串
intern机制
每个单词(字符串),不夹杂空格或者其他符号,默认开启intern机制,共享内存,靠引用计数决定是否销毁
垃圾收集
概述:
现在的高级语言如java,c#等,都采用了垃圾收集机制,而不再是c,c++里用户自己管理维护内存的方式。自己管理内存极其自由,可以任意申请内存,但如同一把双刃剑,为大量内存泄漏,悬空指针等bug埋下隐患。
python里一同java一样采用了垃圾收集机制,不过不一样的是:
python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的策略。
垃圾回收机制:GC机制
python:
1.引用计数机制为主
如何获取一个对象的引用计数?
sys.getrefcount(a)
刚创建对象引用计数为2
a.增加引用计数操作
1.如果有新的对象使用该对象,+1
2.装进列表+1
3.作为函数参数
b.减少引用计数操作
1.如果有新的对象使用该对象,新对象不在使用-1
2.从列表中移除-1
3.函数调用结束-1
4 del 显示销毁
2.隔代回收为辅助
# -*- coding: utf-8 -*-
import sys
class AA(object):
# 创建对象开辟内存时调用
def __new__(cls, *args, **kwargs):
print("开辟内存空间")
print("静态方法类at :%s" % hex(id(cls)))
return super(AA, cls).__new__(cls)
# 初始化方法
def __init__(self):
print("创建对象at :%s" % hex(id(self)))
# 对象被系统回收之前,会调用该方法
def __del__(self):
print("%s say bye bye" % hex(id(self)))
aa = AA()
print('a的引用计数为:%d' % sys.getrefcount(aa))
b = aa
print('a的引用计数为:%d' % sys.getrefcount(aa))
list1 = [aa]
print('a的引用计数为:%d' % sys.getrefcount(aa))
b = 100
print('a的引用计数为:%d' % sys.getrefcount(aa))
list1.remove(aa)
print('a的引用计数为:%d' % sys.getrefcount(aa))
在 Python 的 __new__
方法中,不能将 cls
改为 self
,原因在于 self
和 cls
在语义和用途上有本质的区别。以下详细解释为什么不能将 cls
改为 self
:
1. self
和 cls
的含义
-
self
:-
self
是一个实例方法的参数,它代表类的实例对象。 -
在实例方法中,
self
是调用该方法的实例对象的引用。 -
例如:
Python复制
class MyClass: def my_method(self): print(self) # self 是当前实例对象 obj = MyClass() obj.my_method() # 输出 obj 的内存地址
在这里,
self
是obj
的引用。
-
-
cls
:-
cls
是一个类方法或静态方法的参数,它代表类本身。 -
在类方法中,
cls
是调用该方法的类的引用。 -
在
__new__
方法中,cls
是正在被实例化的类的引用。 -
例如:
Python复制
class MyClass: def __new__(cls): print(cls) # cls 是 MyClass 类本身 return super(MyClass, cls).__new__(cls) obj = MyClass() # 输出 MyClass 的内存地址
-
2. __new__
方法的特殊性
-
__new__
是一个静态方法(虽然没有显式地使用@staticmethod
装饰器,但它本质上是静态方法)。 -
它的目的是创建类的实例,而不是操作类的实例。
-
在
__new__
方法被调用时,类的实例还没有被创建,因此不存在self
。 -
cls
是__new__
方法的第一个参数,它代表正在被实例化的类。
3. 为什么不能将 cls
改为 self
-
语义错误:
-
self
代表实例对象,而__new__
方法的作用是创建实例对象。在实例对象还没有被创建之前,self
是不存在的。 -
如果将
cls
改为self
,会导致代码的语义混乱,无法正确表达__new__
方法的意图。
-
-
运行时错误:
-
Python 的
__new__
方法的签名是固定的,它必须接受cls
作为第一个参数。 -
如果将
cls
改为self
,Python 解释器会抛出错误,因为它无法正确调用__new__
方法。 -
例如:
Python复制
class MyClass: def __new__(self): # 错误:应该使用 cls return super(MyClass, self).__new__(self) obj = MyClass()
这将导致以下错误:
TypeError: __new__() takes 1 positional argument but 2 were given
因为 Python 会将类本身作为第一个参数传递给
__new__
方法,而你定义的__new__
方法只接受一个参数self
,导致参数数量不匹配。
-
4. 正确的用法
-
__new__
方法的正确签名是:Python复制
def __new__(cls, *args, **kwargs): # 创建实例的逻辑 return super(cls).__new__(cls)
-
cls
是类的引用,用于调用父类的__new__
方法来完成实例的创建。
5. 总结
-
self
用于实例方法,代表类的实例对象。 -
cls
用于类方法和__new__
方法,代表类本身。 -
在
__new__
方法中,必须使用cls
,因为此时实例对象还没有被创建,不存在self
。 -
将
cls
改为self
会导致语义错误和运行时错误。
类方法或静态方法和实例方法的区别是什么
类方法、静态方法和实例方法是 Python 中类的三种不同类型的成员方法,它们在定义、调用方式和用途上都有显著的区别。以下是它们的详细对比:
1. 定义方式
-
实例方法:
-
定义时不需要任何特殊装饰器。
-
第一个参数必须是
self
,表示类的实例对象。 -
示例:
Python复制
class MyClass: def instance_method(self): print("This is an instance method")
-
-
类方法:
-
使用
@classmethod
装饰器定义。 -
第一个参数必须是
cls
,表示类本身。 -
示例:
Python复制
class MyClass: @classmethod def class_method(cls): print("This is a class method")
-
-
静态方法:
-
使用
@staticmethod
装饰器定义。 -
不需要任何特殊的第一个参数(既不是
self
也不是cls
)。 -
示例:
Python复制
class MyClass: @staticmethod def static_method(): print("This is a static method")
-
2. 调用方式
-
实例方法:
-
必须通过类的实例对象调用。
-
示例:
Python复制
obj = MyClass() obj.instance_method() # 正确 MyClass.instance_method() # 错误,需要实例对象
-
-
类方法:
-
可以通过类本身调用,也可以通过类的实例对象调用。
-
示例:
Python复制
MyClass.class_method() # 正确 obj = MyClass() obj.class_method() # 也正确
-
-
静态方法:
-
可以通过类本身调用,也可以通过类的实例对象调用。
-
示例:
Python复制
MyClass.static_method() # 正确 obj = MyClass() obj.static_method() # 也正确
-
3. 参数传递
-
实例方法:
-
第一个参数
self
是类的实例对象。 -
示例:
Python复制
class MyClass: def instance_method(self): print(self) # 输出实例对象的内存地址 obj = MyClass() obj.instance_method() # 输出 obj 的内存地址
-
-
类方法:
-
第一个参数
cls
是类本身。 -
示例:
Python复制
class MyClass: @classmethod def class_method(cls): print(cls) # 输出类的内存地址 MyClass.class_method() # 输出 MyClass 的内存地址
-
-
静态方法:
-
不需要任何特殊的第一个参数。
-
示例:
Python复制
class MyClass: @staticmethod def static_method(): print("No special first parameter") MyClass.static_method() # 输出 "No special first parameter"
-
4. 用途
-
实例方法:
-
主要用于操作类的实例对象的属性和方法。
-
通常用于实现类的业务逻辑。
-
示例:
Python复制
class MyClass: def __init__(self, value): self.value = value def instance_method(self): print(f"The value is {self.value}") obj = MyClass(10) obj.instance_method() # 输出 "The value is 10"
-
-
类方法:
-
主要用于操作类本身,而不是类的实例对象。
-
常用于实现类级别的逻辑,例如工厂方法、类属性的访问等。
-
示例:
Python复制
class MyClass: count = 0 @classmethod def class_method(cls): cls.count += 1 print(f"Class count is {cls.count}") MyClass.class_method() # 输出 "Class count is 1" MyClass.class_method() # 输出 "Class count is 2"
-
-
静态方法:
-
不依赖于类或实例对象的状态。
-
常用于实现与类相关的工具函数或辅助方法。
-
示例:
Python复制
class MyClass: @staticmethod def static_method(x, y): return x + y print(MyClass.static_method(3, 4)) # 输出 7
-
5. 总结
特性 | 实例方法 | 类方法 | 静态方法 |
---|---|---|---|
定义方式 | 不需要装饰器,第一个参数是 self | 使用 @classmethod ,第一个参数是 cls | 使用 @staticmethod ,无特殊参数 |
调用方式 | 必须通过实例对象调用 | 可以通过类或实例对象调用 | 可以通过类或实例对象调用 |
参数传递 | self 是实例对象 | cls 是类本身 | 无特殊参数 |
用途 | 操作实例对象的属性和方法 | 操作类本身,实现类级别的逻辑 | 实现与类相关的工具函数 |
通过理解这些区别,你可以根据实际需求选择合适的类型的方法来实现类的功能。
隔代回收机制
原理:
随着时间的推进,程序冗余对象逐渐增多,达到一定数量(阈值),系统进行回收
(0代,1代,2代)
代码
# -*- coding: utf-8 -*-
import gc
import time
class AA(object):
def __new__(cls, *args, **kwargs):
print("new")
return super(AA, cls).__new__(cls)
def __init__(self):
print("object :born at %s" % hex(id(self)))
def __del__(self):
print("%s 被系统回收" % hex(id(self)))
def start():
while True:
a = AA()
b = AA()
a.v = b
b.v = a
del a
del b
print(gc.get_threshold())
print(gc.get_count())
time.sleep(0.1)
start()
在这段代码中,a.v
是对类 AA
的实例对象 a
的一个属性赋值操作。具体来说,a.v
是将实例对象 b
赋值给实例对象 a
的一个属性 v
。