深入理解 python 元类
一、什么的元类
# 思考:
# Python 中对象是由实例化类得来的,那么类又是怎么得到的呢?
# 疑问:
# python 中一切皆对象,那么类是否也是对象?如果是,那么它又是那个类实例化而来的呢?
class student(object):
def __init__(self):
pass jmz = student() print(type(jmz)) # <class '__main__.student'> 实例化student 得来的
print(type(student)) # <class 'type'>
# 说明student类 是实例化type得来的。但任然是类
# 总结: 元类即类的类。 type 就是Python中的默认元类
# 元类===》类====》对象 (对象是实例化类得来的,类是实例化元类得来的)
二、类的产生过程
2.1 类的三大关键组成部分
1、类名
2、类的基类们
3、类的名称空间
2.2 type讲解
在Python中type 函数有两种完全不同 的用法,一个是用来返回对象的类,一个则是动态的创建类。(我知道,根据传入参数的不同,同一个函数拥有两种完全不同的用法是一件很傻的事情,但这在Python中是为了保持向后兼容性)
2.3 type的两种用法
# type用法一: 查看对象的类
class dog(object):
def __init__(self):
pass
def eat(self):
print('dog eating...') dog1 = dog()
dog1.eat() # dog eating...
print(type(dog1)) # <class '__main__.dog'>
print(dog.__dict__)
# {'__module__': '__main__', '__init__': <function dog.__init__ at 0x00000000021B9950>, 'eat': <function dog.eat at 0x00000000021B99D8>, '__dict__': <attribute '__dict__' of 'dog' objects>, '__weakref__': <attribute '__weakref__' of 'dog' objects>, '__doc__': None} # type 用法二: 创建动态类
def __init__(self):
pass
def eat(self):
print("cat eating...")
cat = type('cat',(object,),{"__init__":__init__,"eat":eat}) cat1 = cat()
cat1.eat() # cat eating...
print(type(cat1)) # <class '__main__.cat'>
print(cat.__dict__)
# {'__init__': <function __init__ at 0x00000000004D1EA0>, 'eat': <function eat at 0x00000000022D9A60>, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'cat' objects>, '__weakref__': <attribute '__weakref__' of 'cat' objects>, '__doc__': None}
# 分析:
# 1、dog 类 与cat类功能基本一致,只是实现方式不同,一个使用了class 定义了类,一个使用了type产生了一个类
# 2、dog类与cat类实例化方式一样,
# 3、产生对象后的调用对象方法一样
# 4、__dict__ 类的内容基本一致 # 总结:
# class 关键字的底层实现就是做了与type方法一样的事
2.4、 class关键字底层实现
#1 拿到类名class_name="cat"
#2 拿到基类们class_bases=(object,)
#3 拿到名称空间 class_dic={...}
#4 调用元类产生cat类,
cat=type(class_name,class_bases,class_dic)
三、元类的使用
3.1 自定义元类
Python 中默认元类就是type,所以要自定义元类就需要继承元类,继承元类的类任然是元类
#! /usr/bin/env python
# -*- coding:utf-8 -*-
# Author Jmz class Mymeta(type): # 继承type元类
def __init__(self,class_name,class_bases,class_dict):
if not class_name.istitle():
raise TypeError('类的名称首字母必须大写')
if not class_dict.get('__doc__'):
raise TypeError('类的定义必须要有参数')
super(Mymeta, self).__init__(class_name, class_bases, class_dict) # 使用mateclass
class People(object,metaclass=Mymeta): # ===》 People = type("People",(object,),{名称空间})
'''
这是一个关于人的类
'''
def __init__(self,name,sex):
self.name = name
self.sex = sex
def do(self,thing):
print("%s 正在做%s"%self.name,thing)
3.2 自定义元类产生类
通过对于元类的创建,我们可以做到控制元类,约束类的创造。
#! /usr/bin/env python
# -*- coding:utf-8 -*-
# Author Jmz class Mymeta(type): # 继承type元类
def __init__(self,class_name,class_bases,class_dict): # class_name="People",class_bases=(object,),class_dict={名称空间}
if not class_name.istitle():
raise TypeError('类的名称首字母必须大写')
if not class_dict.get('__doc__'):
raise TypeError('类的定义必须要有参数')
super(Mymeta, self).__init__(class_name, class_bases, class_dict) # 使用mateclass
class People(object,metaclass=Mymeta): # ===》 People = type("People",(object,),{名称空间})
'''
这是一个关于人的类
'''
def __init__(self,name,sex):
self.name = name
self.sex = sex
def do(self,thing):
print("%s 正在做%s"%self.name,thing)
3.3 __call__ 方法
对象是由类调用产生的,对象被当成方法调用,会触发类的__call__方法
class teacher(object):
__addr ="上海校区"
def __init__(self,name):
self.name = name
def select_class(self):
pass
def __call__(self, *args, **kwargs): # 对象当成方法调用时会触发类的__call__ 方法执行
print("对象调用触发")
print(args)
print(kwargs) egon = teacher('egon')
egon(23,"男",school = "oldboy")
# 对象调用触发
# (23, '男')
# {'school': 'oldboy'}
类是由元类调用产生的,那么类被当成方法调用也应该触发元类的__call__方法
class Mymeta(type):
def __call__(self, *args, **kwargs):
print("我是元类的__call__ 方法,类被调用时触发")
print(args)
print(kwargs) class Student(object,metaclass=Mymeta): # Student = type("Student",(object,),{})
pass Student('jmz',18,school="交大")
# 我是元类的__call__ 方法,类被调用时触发
# ('jmz', 18)
# {'school': '交大'}
从上面的代码我们可以看出,对象的产生其实就是,调用了类,进而触发了元类的__call__ 方法,
但是调用类产生的是对象,说明元类的__call__ 方法是用来产生对象的。
说明元类的__call__ 方法就做了下面的几件事
1、创造了一个空对象
2、调用了类的__init__ 方法
3、将参入传入__init__方法中
3.4 自定义元类产生对象
#! /usr/bin/env python
# -*- coding:utf-8 -*-
# Author Jmz class Mymeta(type):
def __init__(self,class_name,class_bases,class_dict):
if not class_name.istitle:
raise TypeError("类的首字母必须大写")
if not class_dict.get("__doc__"):
raise TypeError("类的创建需写入注释说明") super(Mymeta,self).__init__(class_name,class_bases,class_dict) def __call__(self, *args, **kwargs): # __call__ 是由类调用的,所以self 就是类本身
# 1、 产生一个空对象
# 2、 将参数传入类的__init___方法中 obj = object.__new__(self) # 产生一个空对象,, __new__ 是object 的静态方法
self.__init__(obj,*args,**kwargs) # 调用类的__init__ 方法,self 就是类 return obj class Student(object,metaclass=Mymeta):
'''
这是学生类
'''
__school = "上海交大"
def __init__(self,name,age):
self.name = name
self.age = age
def get_school(self):
return self.__school jmz = Student("jmz",24)
print(jmz.__dict__)
print(jmz.get_school())
# {'name': 'jmz', 'age': 24}
# 上海交大
# 上文解释:
1、元类的__call__ 方法是由类被调用触发的(即类(),就会触发),
2、类是实例化元类产生的,也可以说是元类产生的对象就是类,触发元类的__call__ 方法就是由类这个对象调用触发的,所以元类中的self 就是类。
3、将参数传入类的__init__ 方法其实就是将参数传入元类中self的__init__方法。
4、调用类的__init__ 方法与调用静态方法相同,该传的参数都要传
四、为什么要使用元类
从上面的如何使用元类中,我们可以看出,通过对于元类的定义,我们可以控制类的产生,和对象的产生。
五、单例模式
5.1 类实现单例模式
单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。
#! /usr/bin/env python
# -*- coding:utf-8 -*-
# Author Jmz class mysql(object):
__instance = None
def __init__(self):
pass @classmethod
def get_instance(cls,*args,**kwargs):
if not cls.__instance:
cls.__instance = cls(*args,**kwargs)
return cls.__instance mysql = mysql.get_instance()
print(mysql)
# <__main__.mysql object at 0x00000000022D7BE0>
mysql = mysql.get_instance()
print(mysql)
# <__main__.mysql object at 0x00000000022D7BE0> # 说明两个返回的内容地址是一样的,说明只实例化了一次。
5.2 元类实现单例模式
#! /usr/bin/env python
# -*- coding:utf-8 -*-
# Author Jmz class Mymeta(type):
__instance = None
def __init__(self,class_name,class_bases,class_dict):
if not class_name.istitle:
raise TypeError("类的首字母必须大写")
if not class_dict.get("__doc__"):
raise TypeError("类的创建需写入注释说明") super(Mymeta,self).__init__(class_name,class_bases,class_dict) def __call__(self, *args, **kwargs): # __call__ 是由类调用的,所以self 就是类本身
# 1、 产生一个空对象
# 2、 将参数传入类的__init___方法中
if not self.__instance:
obj = object.__new__(self) # 产生一个空对象,, __new__ 是object 的静态方法
self.__init__(obj,*args,**kwargs) # 调用类的__init__ 方法,self 就是类
self.__instance = obj
return self.__instance class Student(object,metaclass=Mymeta):
'''
学生类
'''
def __init__(self,name,age,school):
self.name = name
self.age = age
self.school = school def learn(self,thing):
print("%s 正在学习%s"%(self.name,thing)) class Teacher(object,metaclass=Mymeta):
'''
老师类
'''
def __init__(self,name,age):
self.name = name
self.age = age
def teach(self,):
print("%s 正在教书中。。。"%self.name) jmz = Student("jmz",23,"北大")
jmz1 = Student("jmz1",23,"北大") print(id(jmz),id(jmz1))
# 38853264 38853264 egon = Teacher("egon",24)
egon1 = Teacher("egon1",24)
print(id(egon),id(egon1))
# 31578992 31578992 # 解释
# 1、student 类和 teacher类都是调用元类产生的,不同的类调用元类就好产生不同的内容地址。不同的类也只会定义一次(正常的)
# 2、 对象的产生是有调用了元类的__call__ 方法产生的,所以每次调用都返回相同的对象(单例)。
元类,单例实现
深入理解 python 元类的更多相关文章
- 深入理解python元类
类也是对象 在理解元类之前,你需要先掌握Python中的类.Python 中的类概念借鉴 Smalltalk,这显得有些奇特.在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.当然在 P ...
- 理解Python元类(转)
add by zhj:先收藏了,有时间看,图倒是不少,可以配合stackover flow上那篇文章一起看 原文:http://blog.ionelmc.ro/2015/02/09/understan ...
- [TimLinux] Python 元类
1. type函数 name = "This is a string" print(type(name)) # <class 'str'> print("*& ...
- Python元类实战,通过元类实现数据库ORM框架
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题的第19篇文章,我们一起来用元类实现一个简易的ORM数据库框架. 本文主要是受到了廖雪峰老师Python3入门教程的启 ...
- Python进阶丨如何创建你的第一个Python元类?
摘要:通过本文,将深入讨论Python元类,其属性,如何以及何时在Python中使用元类. Python元类设置类的行为和规则.元类有助于修改类的实例,并且相当复杂,是Python编程的高级功能之一. ...
- python元类:type和metaclass
python元类:type和metaclass python中一切皆对象,所以类本身也是对象.类有创建对象的能力,那谁来创建类的呢?答案是type. 1.用tpye函数创建一个类 class A(ob ...
- Python 元类 - Metaclasses
Python 元类 - Metaclasses 默认情况下儿, classes 是有 type() 构造的. 类的结构体在一个新的 namespace 被执行, 类的名字 class name 绑定( ...
- python元类理解2
恩,对元类理解又有新的收获,其实类似于装饰器,只不过装饰器是修饰函数,元类用来定制一个类. 代码如下,这是一个使用了函数做元类传递给类: input: def upper_attr(class_nam ...
- python 元类理解
原文来自:https://segmentfault.com/a/1190000011447445 学懂元类,你只需要知道两句话: 道生一,一生二,二生三,三生万物 我是谁?我从哪来里?我要到哪里去? ...
随机推荐
- DNN结构演进History—CNN( 优化,LeNet, AlexNet )
本文相对于摘抄的文章已经有大量的修改,如有阅读不适,请移步原文. 以下摘抄转自于维基:基于深度学习的图像识别进展百度的若干实践 从没有感知域(receptive field) 的深度神经网络,到固定感 ...
- VS2013配置编译Caffe-Win10_X64
原文链接:http://blog.csdn.net/joshua_1988/article/details/45036993 有少量修改................ 2014年4月的时候自己在公司 ...
- handyJson的技术内核
1.swift对象内存模型: 2.指针操作: 3.协议.泛型.扩展: 4.kvc: 1是所有实现的基础,没有内存对象(类)模型,后面的一切都我从谈起. 在1的基础上使用2进行对象模型信息的提取和转换. ...
- H5网页涂鸦canvas
最近做了个播放页面,标题和一个iframe;需要对这个iframe可以进行网页涂鸦.网页涂鸦肯定是canvas了.网上找了个差不多的,实验下来问题很多,干脆自己一步步修改,学习. 效果: 本项目没有引 ...
- 【转】在VMware中为Linux系统安装VM-Tools的详解教程
在VMware中为Linux系统安装VM-Tools的详解教程 如果大家打算在VMware虚拟机中安装Linux的话,那么在完成Linux的安装后,如果没有安装Vm-Tools的话,一部分功能将得不到 ...
- python tkinter模块小工具界面
代码 #-*-coding:utf-8-*- import os from tkinter import * root=Tk() root.title('小工具') #清空文本框内容 def clea ...
- Python基础练级攻略:day01
如果你有足够长时间做某事,一定会更擅长. 知识点: 计算机基础 变量 运算符 if语句 for-in循环 函数 列表.元组.字典.字符串.集合 ascii.unicode.utf-8.gbk 区别 A ...
- tp5 权限设置
============================== <?php/** * Created by PhpStorm. * User: 14155 * Date: 2018/11/10 * ...
- 淘宝的开源分布式文件系统TFS
TFS(Taobao FileSystem)是淘宝团队开源的海量非结构化数据存储设计的分布式系统.构筑在普通的Linux机器集群上,可为外部提供高可靠和高并发的存储访问.高可扩展.高可用.高性能.面向 ...
- n!最末尾非0数
最小周期串:如果s是ss的周期串,那么ss就可以表示成几个周期的s,如果s是ss的最小周期串,那么s就是ss的周期串中最小的一个.例,ZgxZgxZgxZgx的最小周期串是Zgx.{很好理解} 给你一 ...