ThankNeko's Blog ThankNeko's Blog
首页
  • 操作系统

    • Linux基础
    • Linux服务
    • WindowsServer笔记
    • Ansible笔记
    • Shell笔记
  • 容器服务

    • Docker笔记
    • Kubernetes笔记
    • Git笔记
  • 数据库服务

    • MySQL笔记
    • ELK笔记
    • Redis笔记
  • 监控服务

    • Zabbix笔记
  • Web服务

    • Nginx笔记
    • Tomcat笔记
  • 数据处理

    • Kettle笔记
  • Python笔记
  • Bootstrap笔记
  • C笔记
  • C++笔记
  • Arduino笔记
  • 分类
  • 标签
  • 归档
  • 随笔
  • 关于
GitHub (opens new window)

Hoshinozora

尽人事,听天命。
首页
  • 操作系统

    • Linux基础
    • Linux服务
    • WindowsServer笔记
    • Ansible笔记
    • Shell笔记
  • 容器服务

    • Docker笔记
    • Kubernetes笔记
    • Git笔记
  • 数据库服务

    • MySQL笔记
    • ELK笔记
    • Redis笔记
  • 监控服务

    • Zabbix笔记
  • Web服务

    • Nginx笔记
    • Tomcat笔记
  • 数据处理

    • Kettle笔记
  • Python笔记
  • Bootstrap笔记
  • C笔记
  • C++笔记
  • Arduino笔记
  • 分类
  • 标签
  • 归档
  • 随笔
  • 关于
GitHub (opens new window)
  • Python笔记

    • 基础知识

    • 类与面向对象

      • 面向对象与类
      • 封装与继承
      • 反射与元类
        • 反射机制
        • 类的内置方法
        • 元类
        • exec函数
        • _call_()方法
        • 单例模式
        • 三层架构设计(MVC)
    • 并发编程

    • Web编程

    • 模块笔记

    • 其他

  • C笔记

  • C++笔记

  • Arduino笔记

  • Dev
  • Python笔记
  • 类与面向对象
Hoshinozora
2023-02-25
目录

反射与元类

# 反射机制

# Python是一个开源的强类型的动态语言

  • 反射是被视为动态语言的关键
  • 动态语言
    • 在给变量指定数据的时候,不需要指定数据类型
  • 静态语言
    • 所有变量都是一开始就定义好的,比如类型等,需要用到时则直接拿来使用。

# 反射介绍

  • 反射是一种能力
  • 指的是在程序运行过程中,可以"动态"地获取对象地信息(数据属性、函数属性)
    • 动态指的是事先不知道,只在最后要用到时才会去获取其属性
  • 动态获取程序信息以及动态调用对象的功能称为反射机制
    • 对于任意一个类,都可以知道这个类的所有属性和方法
    • 对于任意一个对象,都能够调用他的任意方法和属性

# 反射作用

  • 可以通过字符串去操作对象的属性,或者判断一个对象有没有某个属性
  • 反射可以十分灵活地操作对象的属性,比如将用户交互的结果反射到具体的功能执行
    • 如用户输入get命令,则去调用get方法
    • 输入pull命令,则去调用pull方法

# 实现反射机制的步骤

  • 不仅是对象,类和函数也可以
  • 通过4个函数实现(建议)
    • hasattr(obj, ‘字符串属性名’, 默认返回值)
      • 判断一个对象是否有某个属性
      • 默认返回值会在没有这个属性时返回
    • getattr(obj, ‘字符串属性名’, 默认返回值)
      • 通过字符串来获取对象的属性值
      • 默认返回值会在没有这个属性时返回
    • setattr(obj, ‘字符串属性名’, 要设置的值)
      • 通过字符串设置对象的属性的值
    • delattr(obj, ‘字符串属性名’)
      • 通过字符串删除对象的属性
  • 直接通过dict实现(不建议)
      1. 先通过dir()查看一个对象下,有哪些属性
      • dir(obj) 可以查看一个对象下有哪些属性
      • 就是显示.能显示的属性
      1. 通过字符串反射到真正的属性上,得到属性值
      • obj.__dict__['字符串属性名']
      • 但是有局限性


# 类的内置方法

# 内置方法介绍

  • 定义在类的内部,以__开头,并以__结尾的方法
  • 特点是会在某种情况下自动触发执行

# 内置方法的作用

  • 可以定制化我们的类或对象,以在某些情况下,自动执行某些代码

# 常用内置方法的使用

  • __str__() 打印对象时会触发
    • 类中定义__str__后 print(实例化的对象) 时会执行__str__方法下的代码,并将其返回值打印
class App:
    def __str__(self):
        print('你在打印我!')
        return '必须返回字符串类型'
a = App()
print(a)
1
2
3
4
5
6
  • __del__() 在删除对象时会触发
    • 包括程序结束时的清理回收也会触发,会在被删除前执行
    • 如果类中打开调用了系统资源,可以在 __del__() 中执行系统资源的回收操作
      • 防止程序资源回收了,打开的系统资源还占着


# 元类

# 元类介绍

  • class关键字创建的类,都是基于元类而来的,也就是类的类就是元类
  • 元类 —-实例化-—> 类 —-实例化-—> 对象

# 元类作用

  • 自定义元类,对类进行控制
  • 比如规定类的属性名或类名必须大写等

# 查看元类

  • print(type(类名))

# class创造类机制分析

    1. 拿到类名
    1. 拿到类的父类(基类)
    1. 执行类体代码拿到的类的名称空间字典
    • 通过exec函数
    1. 将以上作为参数调用元类 type()
    • type(类名, 父类, 名称空间字典)
    • 会得到一个类 (和用class关键字创建的一样)

# 自定义元类

  • 创建自定义元类
    • 只有继承了type类的类才是元类
class 元类名(type):
    def __init__(self, a, b, c):
        pass # 可在此处写控制代码
1
2
3
  • 调用自定义元类
    • metaclass是指定元类,默认是type
    • 自定义时可以修改为自己的元类
    • 同等于
      • 类名 = type(类名, 父类, 名称空间字典)
class 类名(metaclass=type):
    pass
1
2
  • 调用元类过程
      1. 先通过元类中的__new__()方法造一个空对象
      • 会自动传入当前所在类,和调用类时传入的参数
      1. 调用元类中的__init__()方法,完成初始化的操作
      • 会自动传入__new__()造好的对象
      • 可在此处进行类的控制
      1. 返回初始化好的对象
      • 以上1和2都是通过type.call()方法调用的
      • 初始化好的对象也是通过type.call()返回的
def __new__(cls, *args, **kwargs):
    # 必须返回一个对象
    # 可以问父类要,或者调用type.__new__()
    # return type.__new__(cls, *args, **kwargs)
    return super().__new__(cls, *args, **kwargs)
1
2
3
4
5

# 元类下的属性查找

  • 对象 —> 类 —> 父类 —> object类
    • 不会找到元类


# exec函数

  • exec('字符串代码', {}, namespace_dict)
  • 会将字符串代码执行产生的名称,作为字典,丢到namespace_dict变量里


# call()方法

# 介绍

  • 定义的是 "名称()" 时执行的操作
  • 如果想让一个对象可以加括号调用,需要在该对象的类中添加__call__()方法

# 注意

  • 元类的 __call__() 是定制不了的
  • 自定义元类中定义的__call__实际是控制生成的类的调用操作的
  • 正常的 __call__()
      1. 调用__new__()并传入参数获得对象
      1. 将调用__new__()返回的对象作为参数,传入__init__()
    • 例如
class MyMeta(type):
    def __call__(self, *args, **kwargs):
        obj = self.__new__(self)
        self.__init__(obj, *args, **kwargs)
        return obj
1
2
3
4
5

# 例如

class Foo:
    def __call__(self, name):
        print(name)
obj = Foo()
obj('Nanni')
1
2
3
4
5


# 单例模式

# 介绍

  • 单例模式就是,一个类最多只会有1个对象,这种设计模式可以节省资源消耗

# 实现方式

  • 装饰器方式实现
    • 通过装饰器来判断,每次创造实例时,首先查看该类是否存在实例
    • 存在的话直接返回该实例即可,否则新建一个实例并存放在字典中,然后再返回
def singleton(cls):
    _instance = {}
    def wrapper():
        if cls not in _instance:
            _instance[cls] = cls()
        return _instance[cls]
    return wrapper
@singleton
class Single:
    pass
a = Single()
b = Single()
print(a is b)
1
2
3
4
5
6
7
8
9
10
11
12
13
  • 使用__new__()实现
    • 使用__new__方法在创造实例时进行干预,达到实现单例模式的目的
    • 在每次创建实例时,查看该类是否被实例化过
    • 如果_instance为None,则创建一个实例并将其赋值给_instance,然后再返回它(实例对象)
    • 如果_instance不为None则直接返回它(实例对象)
class Single():
    _instance = None
    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = object.__new__(cls, *args, **kwargs)
        return cls._instance
single1 = Single()
single2 = Single()
print(id(single1) == id(single2))
1
2
3
4
5
6
7
8
9


# 三层架构设计(MVC)

# 用户视图层

  • 用于与用户进行交互,并且接受用户输入的数据,然后调用对应的接口层函数进行处理
  • 例如:登录功能(输入用户名、密码、登录)、注册功能等

# 逻辑接口层

  • 逻辑接口层(最核心的层,应当在此层记录日志)
  • 相当于用户视图层与数据处理层的桥梁,用于接收用户视图层传来的数据,并进行'核心的逻辑'校验
  • 校验过程中,会去访问'数据处理层',并接收其处理结果,然后返回给用户视图层展示
  • 如:登录功能,用户名是否存在、如果存在则校验密码等等

# 数据处理层

  • 用于专门接受接口层传递过来的请求,并进行响应的处理,增删改查等,并放回结果给逻辑接口层
  • 如:查询用户名,有则返回用户数据,没有则返回None
#反射机制#类的内置方法#元类#单例模式#三层架构设计
封装与继承
并发相关介绍

← 封装与继承 并发相关介绍→

最近更新
01
二〇二五年四月十七日随笔
04-17
02
二〇二五年四月十六日随笔
04-16
03
二〇二五年四月九日随笔
04-09
更多文章>
Theme by Vdoing | Copyright © 2022-2025 Hoshinozora | MIT License
湘ICP备2022022820号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式