python中面向对象元类的自定义用法
面向对象中的常用方法
1.instance 和 issubclass
instance :判断两个对象是不是一类
issubclass :判断某个类是不是另一个类的子类
#两个常用方法的使用
class Person:
pass
class Student(Person):
pass
stu = Student()
print(isinstance(stu, Student))
print(issubclass(Student,Person))
True
True ##输出的结果是布尔值。
2.反射
反射,其实就是反省。简单来讲就是对象要具备一种修正错误的能力。
#四种方法:
hasattr #判断是否存在属性
getattr #获取某个属性的值
setattr #设置某个属性的值
delattr #删除某个属性
#这四种方法的共同点,都是通过字符串来操作属性,通过字符串操作。
#示例:反射属性
class Student:
def __init__(self, name, sex, age):
self.name = name
self.age = age
self.sex = sex
def study(self):
print('student is studying')
deng = Student('deng', 'male', 25)
#当我们获取一个对象,但是不清楚对象内部细节,就需要用反射。
def test(obj):
if hasattr(obj, 'name'):
print(getattr(obj, 'name', "no 'name' attribute"))
test(deng)
#示例:反射方法
#通过反射方法的方式为对象增加一个方法,但是注意,这样增加的方法就是一个普通函数,不会自动传值。
res = getattr(deng, 'study', None)
print(res)
res()
def run(obj):
print('student is running')
setattr(deng,'run',None)
res1 = getattr(deng, 'run',None)
run(deng)
#deng
#<bound method Student.study of <__main__.Student object at 0x00000272D8DB8C50>>
#student is studying
#student is running
3._ _str _ _内置方法
当我们需要自定义显示内容时,就需要实现 _ _str _ _方法
#该方法必须返回一个字符串,返回是什么,打印出来就是什么。
class Test:
def __init__(self,name):
self.name = name
def __str__(self):
print('str run...')
return self.name
t = Test('ming')
print(t)
其实,在我们将一个对象转换为字符串时,本质就是在调用这个对象的_ str _ _方法。
4. _ _del _ _内置方法
该方法在对象(程序,文件,等等)被从内存中删除时会自动执行该方法。
class Student:
def __del__(self):
print('对象被删除。。。')
stu = Student() #创建stu对象
#当该stu对象创建完成后该程序就运行结束,就会运行del方法。
#触发__del__有两种:
1.程序自动运行结束
2.手动删除,会立即执行__del__
#示例:
class Student:
def __del__(self):
print('对象被删除。。。')
stu = Student()
del stu #在这就会打印,但这是程序并未结束
import time
time.sleep(5)
什么时候使用它
在python中 有自动内存管理机制 所以 python自己创建的数据 不需要我们做任何操作
但是有一种情况 我们使用python打开了一个不属于python管理的数据
比如打开了一个文件 这个文件一定是操作系统在打开 会占用系统内存 而python解释器无法操作系统内存的
所以 当你的python解释器运行结束后 文件依然处于打开状态 这时候就需要使用__del__来关闭系统资源
简单地说 当程序运行结束时 需要做一些清理操作 就使用__del__
__del__也称之为 析构函数
分析构造 并拆除这个对象
5.exec方法
该方法是解析执行python代码(字符串类型) 并且将得到的名称 存储到制定的名称空间 解释器内部也是调用它来执行代码。解释器内部也是将代码看做字符串。
该方法有三个参数:
参数一 需要一个字符串对象, 表示需要被执行的python语句
参数二 是一个字典,表示全局名称空间
参数三 是一个字典,表示局部名称空间
#示例:
globals_dic = {}
locals_dic = {}
exec('''
a = 1
if a >1:
print('ming')
else:
print('deng')''', globals_dic, locals_dic)
#注意:
1.如果同时制定了全局和局部的,则会将字符串中包含的名称解析后存到局部名称空间。
2.如果只传了一个传参数 则 将字符串中包含名称 解析后存到全局中。
6.元类
使用class可以发现,类其实是type类型的实例(对象)。
一切皆对象
元类是指 用于产生类的类 type就是元类
class Student:
def study(self):
print('studying')
print(type(Student))
总结:
1.类由type实例化产生
2.我们可以使用type产生一个类
3.一个类由类名,类的父类,类的名称空间组成。
type类实例化可以得到类,类实例化可以得到对象。
7._ _ call _ _ 内置方法
_ _ call _ _调用的意思,在对象被调用的时候执行该方法(执行该对象所属的类)
#示例:
class Person:
def __call__(self, *args, **kwargs):
print('call running')
p = Person() #创建对象不会执行call内置方法
p() # call running 对象被调用时会自动执行该方法。
自定义元类 的目的
1.可以通过call 来控制对象的创建过程
2.可用控制类的创建过程
自定义一个元类(元类也是一个类),但该类需继承元类type。
#1.通过__call__来控制对象的创建过程
#1.创建一个元类(需要继承type)
#2.覆盖__call__方法,会将正在实例化对象的类转化为传入的参数
#3.在新的__call__方法中,需要按下面编写,然后再加你需要的控制逻辑即可。
class MyMeta(type):
#self表示创建对象的那个类,*args, **kwargs参数
def __call__(self, *args, **kwargs):
print('MyMeta中的call')
#下面三步是固定的
#1.创建对象
obj = object.__new__(self)
#2.调用初始化方法
self.__init__(obj,*args,**kwargs)
#3.得到一个完整的对象
return obj
#先修改Person的元类为MyMeta
class Person(metaclass=MyMeta):
def __init__(self,name ,age):
self.name = name
self.age = age
def __call__(self, *args, **kwargs):
print('call is running...')
deng = Person('deng', 26)
print(deng)
deng()
####
MyMeta中的call
<__main__.Person object at 0x00000251588D89B0>
call is running...
#2.通过元类控制类的创建过程:
#1.创建一个元类(需要继承type)
#2.覆盖__init__方法,该方法会新建类的对象,类名,父类名,名称空间,可以利用这些信息做处理
#3.对于需要控制的类,需要指定metaclass为上面元类
class MyMeta(type):
def __init__(self, class_name, bases, namespace):
print('=======')
#控制类名必须大写
if not class_name.istitle():
print('类名必须大写开头。。。')
#该代码主动抛出异常
raise TypeError('类名,开头必须大写开头。。。')
if not self.__doc__:
raise TypeError
pass
class Student(metaclass=MyMeta):
'''
这是文档注释,可以通过__doc__获取
'''
#在类的__init__中可以控制该类对象的创建过程
def __init__(self, name):
print('+++++++++++++')
print(self.__doc__)
self.name = name
print(Student.__doc__)
8.单例模式
单例 一种设计模式
单个对象,一个类如果只有一个实例,那么该类称之为单例
为什么需要单例?
class MyMeta(type):
obj = None
def __call__(self, *args, **kwargs):
if not MyMeta.obj:
obj = object.__new__(self)
self.__init__(obj, *args, **kwargs)
MyMeta.obj = obj
return MyMeta.obj
class Printer(metaclass=MyMeta):
'''
这是一个单例类,请不要直接实例化,使用get方法获取实例
'''
obj = None
def __init__(self, name, type):
self.name = name
self.type = type
def printing(self, text):
print('正在打印%s' % text)
@classmethod
def get_printer(cls):
if not cls.obj:
obj = cls('ec001', 'sharp')
cls.obj = obj
print('创建新对象')
return cls.obj
p = Printer.get_printer()
print(p.name)
print(p)
p1 = Printer('ming','')
print(p1.name)
print(p1)
总结:
单例的优点:就是可以优化内存,减少重复对象的产生占用内存。
python中面向对象元类的自定义用法的更多相关文章
- [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式
使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...
- Python之面向对象元类
Python之面向对象元类 call方法: class People: def __init__(self,name): self.name=name # def __call__(self, *ar ...
- Python中的元类(metaclass)
推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...
- 深刻理解Python中的元类metaclass(转)
本文由 伯乐在线 - bigship 翻译 英文出处:stackoverflow 译文:http://blog.jobbole.com/21351/ 译注:这是一篇在Stack overflow上很热 ...
- 深刻理解Python中的元类(metaclass)
译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...
- [转] 深刻理解Python中的元类(metaclass)
非常详细的一篇深入讲解Python中metaclass的文章,感谢伯乐在线-bigship翻译及作者,转载收藏. 本文由 伯乐在线 - bigship 翻译.未经许可,禁止转载!英文出处:stacko ...
- 深刻理解Python中的元类(metaclass)【转】
译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...
- 深刻理解Python中的元类(metaclass)以及元类实现单例模式
在理解元类之前,你需要先掌握Python中的类.Python中类的概念借鉴于Smalltalk,这显得有些奇特.在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍 ...
- 深入理解Python中的元类(metaclass)
原文 译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍 ...
随机推荐
- restful规范整理
restful的十条规范 restful一共有十条规范,但其并不是规定.可以不去遵守,是一种软件风格 1.API与客户端交互,通常使用https协议 2.域名:https://api.baidu.co ...
- 3070 Fibonacci
Fibonacci Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 21048 Accepted: 14416 Descr ...
- Ubuntu16.04上添加用户以及修改用户所属的组
我的问题是这样的,我的本地的电脑上有一个用户以及一个用户组,我还想添加其他的用户,并且这个用户属于这个已有的用户组 <鸟哥的linux私房菜>针对的是centos系统,还是有一些不一样 实 ...
- linux基础之LSB定义的常用目录详解
Linux基础之LSB定义的基本目录详解 1.LSB中FHS(Filesystem Hierarchy Standard)定义的一些文件 /boot:主要是存放引导文件的目录,比如内核文件(vmlin ...
- 《从Lucene到Elasticsearch:全文检索实战》学习笔记四
今天我给大家讲讲布尔检索模型基本概念 布尔检索模型: 检索模型是判断文档内容与用户相关性的核心技术,以大规模网页搜索为例,在海量网页中与用户查询关键词相关的网页可能会有成千上万个,甚至耕读哦.那么信息 ...
- 学习笔记TF046:TensoFlow开发环境,Mac、Ubuntu/Linux、Windows,CPU版本、GPU版本
下载TensorFlow https://github.com/tensorflow/tensorflow/tree/v1.1.0 .Tags选择版本,下载解压. pip安装.pip,Python包管 ...
- JavaScript 快速排序详解
使用的是<JavaScript数据结构与算法>一书中的快速排序,并加上自己的理解. 经测试,此算法的速度比内置的 sort 更快!而阮一峰的那个快排更像是归并排序,虽然写法简单很多,但是性 ...
- 使用deb 打包开发的postgres extension
昨天写过一个使用rpm 打包分发pg 扩展的demo,今天使用deb 进行打包分发,同时使用checkinstall 生成我们的deb包 安装deb 依赖 sudo apt-get install c ...
- php 多线程
windows下安装php真正的多线程扩展pthreads教程 http://www.thinkphp.cn/topic/22676.html PHP 安装 Pthreads (解决 class Th ...
- kafka-producer partitioner.class的使用
partitioner.class的说明 在API客户端中封装好的partition( )方法会为消息选择一个分区编号.为了保证消息负载均衡到每个分区,可以通过使用默认方式或者 手动配置这个参数的 ...