iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Python基础之元编程知识总结
  • 921
分享到

Python基础之元编程知识总结

2024-04-02 19:04:59 921人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

目录一、前言二、ImportTime vs RunTime三、元类四、装饰器五、对数据的抽象–描述符六、控制子类的创建——代替元类的方法一、前言 首先说,python中一切皆对象,老

一、前言

首先说,python中一切皆对象,老生常谈。还有,Python提供了许多特殊方法、元类等等这样的“元编程”机制。像给对象动态添加属性方法之类的,在Python中根本谈不上是“元编程”,但在某些静态语言中却是需要一定技巧的东西。我们来谈些Python程序员也容易被搞糊涂的东西。

我们先来把对象分分层次,通常我们知道一个对象有它的类型,老早以前Python就将类型也实现为对象。这样我们就有了实例对象和类对象。这是两个层次。稍有基础的读者就会知道还有元类这个东西的存在,简言之,元类就是“类”的“类”,也就是比类更高层次的东西。这又有了一个层次。还有吗?

二、ImportTime vs RunTime

如果我们换个角度,不用非得和之前的三个层次使用同样的标准。我们再来区分两个东西:ImportTime和RunTime,它们之间也并非界限分明,顾名思义,就是两个时刻,导入时和运行时。

当一个模块被导入时,会发生什么?在全局作用域的语句(非定义性语句)被执行。函数定义呢?一个函数对象被创建,但其中的代码不会被执行。类定义呢?一个类对象被创建,类定义域的代码被执行,类的方法中的代码自然也不会被执行。

执行时呢?函数和方法中的代码会被执行。当然你要先调用它们。

三、元类

所以我们可以说元类和类是属于ImportTime的,import一个模块之后,它们就会被创建。实例对象属于RunTime,单import是不会创建实例对象的。不过话不能说的太绝对,因为如果你要是在模块作用域实例化类,实例对象也是会被创建的。只不过我们通常把它们写在函数里面,所以这样划分。

如果你想控制产生的实例对象的特性该怎么做?太简单了,在类定义中重写__init__方法。那么我们要控制类的一些性质呢?有这种需求吗?当然有!

经典的单例模式,大家都知道有很多种实现方式。要求就是,一个类只能有一个实例。

最简单的实现方法是这样的


class _Spam:
    def __init__(self):
        print("Spam!!!")

_spam_singleton =None

def Spam():
    global _spam_singleton
    if _spam_singleton is not None:
        return _spam_singleton
    else:
        _spam_singleton = _Spam()
        return _spam_singleton

工厂模式,不太优雅。我们再来审视一下需求,要一个类只能有一个实例。我们在类中定义的方法都是实例对象的行为,那么要想改变类的行为,就需要更高层次的东西。元类在这个时候登场在合适不过了。前面说过,元类是类的类。也就是说,元类的__init__方法就是类的初始化方法。 我们知道还有__call__这个东西,它能让实例像函数那样被调用,那么元类的这个方法就是类在被实例化时调用的方法。

代码就可以写出来了:


class Singleton(type):
    def __init__(self, *args, **kwargs):
        self._instance = None
        super().__init__(*args, **kwargs)

    def __call__(self, *args, **kwargs):
        if self._instance is None:
            self._instance = super().__call__(*args, **kwargs)
            return self._instance
        else:
            return self._instance


class Spam(metaclass=Singleton):
    def __init__(self):
        print("Spam!!!")

主要有两个地方和一般的类定义不同,一是Singleton的基类是type,一是Spam定义的地方有一个metaclass=Singleton。type是什么?它是object的子类,object是它的实例。也就是说,type是所有类的类,也就是最基本的元类,它规定了一些所有类在产生时需要的一些操作。所以我们的自定义元类需要子类化type。同时type也是一个对象,所以它又是object的子类。有点不太好理解,大概知道就可以了。

四、装饰器

我们再来说说装饰器。大多数人认为装饰器是Python里面最难理解的概念之一。其实它不过就是一个语法糖,理解了函数也是对象之后。就可以很轻易的写出自己的装饰器了。


from functools import wraps

def print_result(func):

    @wraps(func)
    def wrappper(*args, **kwargs):
        result = func(*args, **kwargs)
        print(result)
        return result

    return wrappper

@print_result
def add(x, y):
    return x + y
#相当于:
#add = print_result(add)

add(1, 3)

这里我们还用到了一个装饰器@wraps,它是用来让我们返回的内部函数wrapper和原来的函数拥有相同的函数签名的,基本上我们在写装饰器时都要加上它。

在注释里写了,@decorator这样的形式等价于func=decorator(func),理解了这一点,我们就可以写出更多种类的装饰器。比如类装饰器,以及将装饰器写成一个类。


def attr_upper(cls):
    for attrname,value in cls.__dict__.items():
        if isinstance(value,str):
            if not value.startswith('__'):
                setattr(cls,attrname,bytes.decode(str.encode(value).upper()))
    return cls    

@attr_upper
class Person:
    sex = 'man'

print(Person.sex) # MAN

注意普通的装饰器和类装饰器实现的不同点。

五、对数据的抽象–描述符

如果我们想让某一些类拥有某些相同的特性,或者说可以实现在类定义对其的控制,我们可以自定义一个元类,然后让它成为这些类的元类。如果我们想让某一些函数拥有某些相同的功能,又不想把代码复制粘贴一遍,我们可以定义一个装饰器。那么,假如我们想让实例的属性拥有某些共同的特点呢?有人可能会说可以用property,当然可以。但是这些逻辑必须在每个类定义的时候都写一遍。如果我们想让这些类的实例的某些属性都有相同的特点的话,就可以自定义一个描述符类。

这里我们给出一些例子


class TypedField:
    def __init__(self, _type):
        self._type = _type

    def __get__(self, instance, cls):
        if instance is None:
            return self
        else:
            return getattr(instance, self.name)

    def __set_name__(self, cls, name):
        self.name = name

    def __set__(self, instance, value):
        if not isinstance(value, self._type):
            raise TypeError('Expected' + str(self._type))
        instance.__dict__[self.name] = value

class Person:
    age = TypedField(int)
    name = TypedField(str)

    def __init__(self, age, name):
        self.age = age
        self.name = name

jack = Person(15, 'Jack')
jack.age = '15'  # 会报错

在这里面有几个角色,TypedField是一个描述符类,的属性Person是描述符类的实例,看似描述符是作为Person,也就是类的属性而不是实例属性存在的。但实际上,一旦Person的实例访问了同名的属性,描述符就会起作用。需要注意的是,在python3.5及之前的版本中,是没有__set_name__这个特殊方法的,这意味着如果你想要知道在类定义中描述符被起了一个什么样的名字,是需要在描述符实例化时显式传递给它的,也就是需要多一个参数。不过在Python3.6中,这个问题得到了解决,只需要在描述符类定义中重写__set_name__这个方法就好了。还需要注意的是__get__的写法,基本上对instance的判断是必需的,不然会报错。原因也不难理解,就不细说了。

六、控制子类的创建——代替元类的方法

在Python3.6中,我们可以通过实现__init_subclass__特殊方法,来自定义子类的创建,这样我们就可以在某些情况下摆脱元类这个讨厌的东西。


class PluginBase:
    subclasses = []

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        cls.subclasses.append(cls)

class Plugin1(PluginBase):
    pass

class Plugin2(PluginBase):
    pass

小结诸如元类等元编程对于大多数人来说有些晦涩难懂,大多数时候也无需用到它们。但是大多数框架背后的实现都使用到了这些技巧,这样才能让使用者写出来的代码简洁易懂。如果你想更深入的了解这些技巧,可以参看一些书籍例如《Fluent Python》、《Python Cookbook》(这篇文章有的内容就是参考了它们),或者看官方文档中的某些章节例如上文说的描述符HowTo,还有Data Model一节等等。或者直接看Python的源码,包括用Python写的以及CPython的源码。

记住,只有在充分理解了它们之后再去使用,也不要是个地方就想着使用这些技巧。

到此这篇关于Python基础之元编程知识总结的文章就介绍到这了,更多相关Python元编程内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Python基础之元编程知识总结

本文链接: https://www.lsjlt.com/news/126622.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Python基础之元编程知识总结
    目录一、前言二、ImportTime vs RunTime三、元类四、装饰器五、对数据的抽象–描述符六、控制子类的创建——代替元类的方法一、前言 首先说,Python中一切皆对象,老...
    99+
    2022-11-12
  • Python基础之元组与文件知识总结
    目录大纲Python文件类型及汇总一、元组二、文件三、pickle存储和读取python对象四、类型汇总大纲 Python文件类型及汇总 一、元组 1 特征 1.任意对象的有序集...
    99+
    2022-11-12
  • python基础知识总结
    ...
    99+
    2023-01-31
    基础知识 python
  • Python基础之logging模块知识总结
    目录前言一、日志级别二、basicConfig三、日志写文件四、traceback记录前言 logging模块是Python内置的标准模块,主要用于输出脚本运行日志,可以设置输出日志的等级、日志保存路径等。 ...
    99+
    2022-06-02
    Python logging模块 python常用模块
  • java基础之String知识总结
    目录一、概念二、特点三、三种构造方式:四、字符串常量池一、概念 String代表字符串,java语言中所有双引号的字符串都是String的对象,不管是否是new出来的对象。 二、特点...
    99+
    2022-11-12
  • Python基础知识点总结
       学了一年多的Python,去年做了一段时间的爬虫项目,近来在做数据分析和机器学习的东西,抽空整理一下以前学的Python基础知识点,有借鉴与总结。具体知识点后续会分段展开深入。     1.到底什么是Python?你可以在回答中与...
    99+
    2023-01-31
    知识点 基础 Python
  • python基础之文件处理知识总结
    目录一、open()方法二、read()方法三、readlines()方法四、seek()方法五、tell()函数  一、open()方法 python open...
    99+
    2022-11-12
  • Python基础之函数嵌套知识总结
    内部/内嵌函数 1、定义:在一个函数的函数体内使用关键字def关键字定义一个新的函数,这个新的函数就叫做内部/内嵌函数。 2、注意点:内部函数的整个函数体都在外部函数的作用域内,如...
    99+
    2022-11-12
  • Python基础之模块相关知识总结
    目录一、什么是模块二、导入模块三、name=‘main'四、搜索路径一、什么是模块 容器 -> 数据的封装 函数 -> 语句的封装 类 ->...
    99+
    2022-11-12
  • Spring5学习之基础知识总结
    目录1.概述2.入门Demo3.源码1.概述 1、Spring 是轻量级的开源的 JavaEE 框架 2、 Spring 可以解决企业应用开发的复杂性 3、Spring 有两个核心部...
    99+
    2022-11-12
  • Java基础知识总结之继承
    目录一、继承的基本概念二、继承的好处和弊端三、继承中变量访问的特点四、super关键字五、继承中构造方法的访问特点六、继承中成员方法的访问特点七、方法重写八、包九、修饰符十、stat...
    99+
    2022-11-12
  • Python入门基础知识总结
    目录 一:简介: 二:Python基础语法 2.1.字面量 2.2.注释 2.3.数据类型转换 2.4.标识符 2.5.运算符 2.6.字符串 2.6.1.字符串的三种定义方式 2.6.2.字符串拼接 2.6.3.字符串格式化 2.6.4....
    99+
    2023-09-01
    python 开发语言
  • Python基础之变量的相关知识总结
    变量全都是引用 跟其他编程语言不同,Python的变量不是盒子,不会存储数据,它们只是引用,就像标签一样,贴在对象上面。 比如: >>> a = [1, 2, ...
    99+
    2022-11-12
  • 总结CSS基础知识
    本篇内容主要讲解“总结CSS基础知识”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“总结CSS基础知识”吧!一、CSS简介css:层叠样式表 英文全名:casca...
    99+
    2022-10-19
  • canvas基础知识总结
    本篇内容主要讲解“canvas基础知识总结”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“canvas基础知识总结”吧!1、填充矩形 fillRect(x,y,w...
    99+
    2022-10-19
  • nodejs基础知识总结
    这篇文章主要讲解了“nodejs基础知识总结”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“nodejs基础知识总结”吧!什么是nodejsnode.js是基...
    99+
    2022-10-19
  • react基础知识总结
    目录前言 开始 React 生命周期 React Fiber React setState React 事件机制 前言 最近在准备面试。复习了一些react的知识点,特此总结。 开...
    99+
    2022-11-12
  • HTML基础知识总结
    目录标签分类常用标签表单框架 常用的布局组合标签HTML4和HTML5的区别:HTML5 中新增的语义标签 - 了解HTML5 新的表单属性 form 新属性input 新...
    99+
    2022-11-12
  • C#基础知识总结
    这篇文章主要讲解了“C#基础知识总结”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C#基础知识总结”吧!C#基础知识之new 修饰符是起什么作用?new 修饰符与 new 操作符是两个概念,...
    99+
    2023-06-18
  • jsp 基础知识总结
    这篇文章主要介绍jsp 基础知识总结,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一.Servlet知识及常见错误和规律.桌面运行程序与WEB应用程序在过程实质是一样的---基于请求与响应的过程.2.http协议(超...
    99+
    2023-06-03
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作