当前位置: 首页 > news >正文

内存管理及内建函数

元类

类也是对象(属于元类的对象)

#打印字符串(字符串是对象)
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,原因在于 selfcls 在语义和用途上有本质的区别。以下详细解释为什么不能将 cls 改为 self

1. self 和 cls 的含义

  • self

    • self 是一个实例方法的参数,它代表类的实例对象。

    • 在实例方法中,self 是调用该方法的实例对象的引用。

    • 例如:

      Python复制

      class MyClass:
          def my_method(self):
              print(self)  # self 是当前实例对象
      obj = MyClass()
      obj.my_method()  # 输出 obj 的内存地址

      在这里,selfobj 的引用。

  • 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

相关文章:

  • AI芯片混战:GPU vs TPU vs NPU的算力与能效博弈
  • 嵌入式软硬件开发,常见通信总线
  • Spring启示录、概述、入门程序以及Spring对IoC的实现
  • Spring Boot 框架注解:@ConfigurationProperties
  • Java文件流操作 - 【Guava】IO工具
  • React 列表与 Keys 的深入探讨
  • 聊聊Spring AI的PgVectorStore
  • OpenCV 图形API(17)计算输入矩阵 src 中每个元素的平方根函数sqrt()
  • oklink js逆向(入口定位)
  • 1.2 测试设计阶段:打造高质量的测试用例
  • c++ 函数后面加const 作用
  • kaggle竞赛——房价预测
  • 轨迹预测Physical Plausibility-aware Trajectory Prediction via Locomotion Embodiment
  • 基于 Vue 3 + html2canvas 实现网页任意区域截图组件
  • 抓wifi无线空口包之Ubuntu抓包(二)
  • Linux-CentOS-7—— 安装MySQL 8
  • Kafka 中的幂等机制
  • SQLI打靶
  • 【嵌入式学习6】多任务版TCP服务器
  • 玄机-第六章-哥斯拉4.0流量分析的测试报告