一、补充内置函数isinstance和issubclass

1、isinstance是判断一个对象是不是由一个对象产生的

 class Foo:
pass obj=Foo() print(isinstance(obj,Foo)) #判断一个对象是否是由某个类调用产生 # 在python3中统一类与类型的概念
d={'x':1} #d=dict({'x':1} #) #类即类型,d是一个对象,dict是一个类,d是由调用dict产生的对象 print(type(d) is dict) #type也可以判断数据类型,但这并不是type的的主要功能,其实type是一个元类
print(isinstance(d,dict))

2、issubclass是判断一个l类是不是另外一个类的子类

# issubclass()
class Parent:
pass class Sub(Parent):
pass print(issubclass(Sub,Parent)) #判断类Sub是不是Parent是不是的子类,是布尔值为True
print(issubclass(Parent,object))

二、反射

'''
1、什么是反射
通过字符串来操作类或者对象的属性 2、如何用
hasattr
getattr
setattr
delattr ''' class People:
country='China'
def __init__(self,name):
self.name=name def eat(self):
print('%s is eating' %self.name) peo1=People('egon')
# hasattr:判断-------(对象)---------中有没有一个------(字符串形式的属性)-------对应的数据属性或函数属性,结果是一个bool值
print(hasattr(peo1,'eat')) #效果等价:peo1.eat # # getattr:判断-------(对象)---------中有没有一个------(字符串形式的属性)-------对应的数据属性或函数属性,如果有对应的数据属性,返回的是数据属性对应的值,如果有对应的函数属性返回的是一个内存地址
print(getattr(peo1,'eat')) #peo1.eat #类中有这个属性,返回的是一个内存地址
print(getattr(People,'country')) #类中有数据属性,返回的是数据属性对应的属性值
print(getattr(peo1,'xxxxx',None)) #None是一个默认值,如果类中没有这个数据属性、函数属性就会将默认值返回,如果没有默认值,类中也没有字符串对应的属性,就会报错 # setattr:判断-------(对象)---------中有没有一个------(字符串)-------对应的数据属性,有可以对其属性值进行修改,没有添加新的属性
setattr(peo1,'age',18) #peo1.age=18 #可以给对象添加新的属性
setattr(peo1,'name','alex') #可以修改对象的属性值
print(peo1.age)
print(peo1.name) # print(peo1.__dict__)
# delattr:判断-------(对象)---------中有没有一个------(字符串形式的属性)-------对应的数据属性或函数属性,有可以将其删除
delattr(peo1,'name') #del peo1.name
print(peo1.__dict__)
delattr(peo1,'eat') #-----会报错,setattr和delattr只会对自己名称空间的名字做修改和删除,并不能改变类名称空间中的属性名 '''重点'''
# 反射的应用:
class Ftp:
def __init__(self,ip,port):
self.ip=ip
self.port=port def get(self):
print('GET function') def put(self):
print('PUT function') def run(self):
while True:
choice=input('>>>: ').strip() #模拟用户实际输入对应的命令是一个字符串,所以此时就要用到映射
'''方法一'''
# # print(choice,type(choice))
# if hasattr(self,choice): #判断用户输入的字符串形式的属性名是否存在,拿到一个返回的bool值
# method=getattr(self,choice) #输入的字符串形式的属性名存在,通过属性名拿到绑定方法的内存地址
# method() #绑定方法加括号即调用
# else:
# print('输入的命令不存在') '''方法二'''
method=getattr(self,choice,None) #如果用户输入的字符串形式的属性值存在,则直接拿到该属性的绑定方法的内存地址返回,属性是不存在,返回None
if method is None:
print('输入的命令不存在')
else:
method() #函数属性的内存地址加括号直接调用 conn=Ftp('1.1.1.1',23) #类加括号,产生一个空对象,并对对象通过__init__进行初始化
conn.run() #将对象绑定给方法,会将对象当做第一个参数自动传入

三、自定义方法来定义类的功能

1、__str__方法-------会在打印对象的时候自动触发
class People:
def __init__(self,name,age):
self.name=name
self.age=age #在对象被打印时,自动触发,应该在该方法内采集与对象self有关的信息,然后拼成字符串返回
def __str__(self):
# print('======>')
return '<name:%s age:%s>' %(self.name,self.age) #返回的必须是字符串,否则就会报错
obj=People('egon',18)
obj1=People('alex',18)
print(obj) #obj.__str__() #没有__str__打印对象的结果就是一个内存地址,
# 但是有了__str__我们就可以拼接任意我们想要的样式,此时在打印对象就会得到我们拼接的结果
print(obj) #obj.__str__()
print(obj) #obj.__str__()
print(obj1) #obj1.__str__() """ 默认就有str,只是返回的是内存地址,我们可以通过设置str,可以通过打印对象打印出好看的格式,而不是只是单纯的打印出一个内存地址""" d={'x':1} #d=dict({'x':1})
print(d) #打印d这个对象是一个字典,而不是像上面一样是一个内存地址,是因为dict内一定自带了一个__str__,在打印对象的时候自动触发

2、__del__会在对象被删除时自动触发
# """1、__del__析构方法"""
# # __del__会在对象被删除时自动触发
class People:
def __init__(self,name,age):
self.name=name
self.age=age
self.f=open('a.txt','rt',encoding='utf-8') #打开该文件占用两方面的资源,一是应用程序即Python解释器,Python会自动回收,另一方面是系统资源,要手动关闭 def __del__(self): #删除对象是自动触发
print('run=-====>')
# 做回收系统资源相关的事情
self.f.close() #删除应用程序资源要在关闭系统资源之后,要不就会出现系统资源无法关闭,白白占用资源 obj=People('egon',18) print('主') #系统程序运行完毕,回收资源,会自动触发__del__的执行,所以先打印:'主',再打印:'run=-====>'

四、元类

'''
1、什么是元类
在python中一切皆对象,那么我们用class关键字定义的类本身也是一个对象
负责产生该对象的类称之为元类,即元类可以简称为类的类 class Foo: # Foo=元类() #一切皆对象,类加括号产生对象
pass
2、为何要用元类
元类是负责产生类的,所以我们学习元类或者自定义元类的目的
是为了控制类的产生过程,还可以控制对象的产生过程 3、如何用元类 '''
#1、储备知识:内置函数exec的用法
cmd="""
x=1
def func(self):
pass
"""
class_dic={}
exec(cmd,{},class_dic) #exec会将cmd字符串中的代码拿出来执行一次,将产生的名字丢掉事先定义好的class_dic空字典中 print(class_dic) #{'x': 1, 'func': <function func at 0x00000267165F92F0>} #2、创建类的方法有两种
# 大前提:如果说类也是对象的话,那么用class关键字去创建类的过程也是一个实例化的过程
# 该实例化的目的是为了得到一个类,调用的是元类
#2.1 方式一:用的默认的元类type
class People: #People=type(...)--------默认的元类type实例化出一个对象Pelple,实例化的结果也是一个对象
country='China'
def __init__(self,name,age):
self.name=name
self.age=age def eat(self):
print('%s is eating' %self.name)
peo=People('EGON',18)
print(peo) #------------<__main__.People object at 0x000001F635282E10>*********调用类实例化出对象
print(type(People)) #------------<class 'type'>*****************************************调用元类实例化出类 """重点"""
#2.1.1 创建类的3个要素:类名,基类,类的名称空间
class_name='People' #类名,是一个字符串,---------由上面的class定义类我们知道,创建类的三要素:类名,基类,类的名称空间
class_bases=(object,) #基类,----------------------我们通过__bases__,知道基类是一个元组的形式
class_dic={} #类的名称空间,---------------通过__dict__,知道类的名称空间的是一个字典
class_body="""
country='China'
def __init__(self,name,age):
self.name=name
self.age=age def eat(self):
print('%s is eating' %self.name)
""" #--------将类体代码放到一个字符串中
exec(class_body,{},class_dic)#执行字符传中的代码,将产生的名字方到class_dic的名称空间中,即之前定义类将产生的名字放到类的名称空间中 # 准备好创建类的三要素
# print(class_name) #-------People
# print(class_bases) #-------(<class 'object'>,)
# print(class_dic) #-------{'country': 'China', '__init__': <function __init__ at 0x00000222D55F92F0>, 'eat': <function eat at 0x00000222DC618BF8>} # People=type(类名,基类,类的名称空间) #调用元类就可以产生一个类这个对象
People1=type(class_name,class_bases,class_dic) #将事先定义好的类的三要素放到当做参数传给元类,调用元类即产生对象
print(People1) #--------<class '__main__.People'>自定义类产生的结果
obj1=People1('egon',18)
print(People) #--------<class '__main__.People'>,class定义类产生的结果
obj=People('egon',18) obj1.eat()
obj.eat() """----------------------------------------重点----------------------------------------"""
#2.2 方式二:用的自定义的元类
class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
def __init__(self,class_name,class_bases,class_dic):
print(self) #现在是People
print(class_name)
print(class_bases)
print(class_dic)
super(Mymeta,self).__init__(class_name,class_bases,class_dic) #重用父类的功能 # 分析用class自定义类的运行原理(而非元类的的运行原理):
#1、拿到一个字符串格式的类名class_name='People'
#2、拿到一个类的基类们class_bases=(obejct,)
#3、执行类体代码,拿到一个类的名称空间class_dic={...}------------------前三步就是造类的三要素
#4、调用People=type(class_name,class_bases,class_dic)----------------调用元类(类)产生类(对象)------------调用类产生对象
class People(object,metaclass=Mymeta): #People=Mymeta(类名,基类们,类的名称空间)------metaclass=Mymeta是自定义的元类名
country='China'
def __init__(self,name,age):
self.name=name
self.age=age def eat(self):
print('%s is eating' %self.name)
"""----------------------------------------重点----------------------------------------""" """应用:自定义元类控制类的产生过程,类的产生过程其实就是元类的调用过程------(对象的产生过程就是调用类的过程)"""
class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类---------------必须要继承type类
def __init__(self,class_name,class_bases,class_dic): #在自定义类之上添加逻辑判断
if class_dic.get('__doc__') is None or len(class_dic.get('__doc__').strip()) == 0: #必须有文档注释,且不为空
raise TypeError('类中必须有文档注释,并且文档注释不能为空')
if not class_name.istitle(): #类的首字母必须大写
raise TypeError('类名首字母必须大写')
super(Mymeta,self).__init__(class_name,class_bases,class_dic) #重用父类的功能 class People(object,metaclass=Mymeta): #People=Mymeta('People',(object,),{....})
"""这是People类"""
country='China'
def __init__(self,name,age):
self.name=name
self.age=age def eat(self):
print('%s is eating' %self.name) #3 储备知识:__call__
class Foo:
def __call__(self, *args, **kwargs):
print(self) #<__main__.Foo object at 0x000002193E892E10>
print(args) #(1, 2, 3)----------------*args接收位置参数,存成元组的形式
print(kwargs) #{'x': 1, 'y': 2}---------**kwargs接收关键字参数,存成字典的形式 obj=Foo() #调用类不会自动触发,会在调用对象时自动触发,通过self也可以看出,是调用对象时自动触发 # # 要想让obj这个对象变成一个可调用的对象,需要在该对象的类中定义一个方法__call__方法
# # 该方法会在调用对象时自动触发
# obj(1,2,3,x=1,y=2) #调用对象时自动触发__call__方法,并将对象自动传入 """-----------------------------------------------重点---------------------------------------------"""
# 4、自定义元类来控制类的调用的过程,即类的实例化过程
class Mymeta(type): def __call__(self, *args, **kwargs): #会在调用对象时自动触发,此时的对象时一个类,即People
# print(self) # self是People
# print(args)
# print(kwargs)
# return 123
"""调用类产生一个对象,发生两件事""" #和class定义类,调用类一样发生两件事
# 1、先造出一个People的空对象
obj=self.__new__(self) #造出了一个自定义类People的空对象
# 2、为该对空对象初始化独有的属性
# print(args,kwargs)
self.__init__(obj,*args,**kwargs) #对空对象进行初始化,空对象传入,以及参数原封不动的传入 # 3、返回一个初始好的对象
return obj #将造出的对象返回, '''**********************************看成一个对象************************************************'''
class People(object,metaclass=Mymeta): #自定义类People,元类是Mymeta,元类必须继承type类,否则就不是元类
country='China'
def __init__(self,name,age):
self.name=name
self.age=age def eat(self):
print('%s is eating' %self.name) def __new__(cls, *args, **kwargs): #对象自己中有__new__属性,先从对象自己的名称空间中找,自己没有在到自己的类中找
print(cls)
# cls.__new__(cls) # 错误 #自己有调用了自己的__new__,这样就出现无线递归,所以会报错
obj=super(People,cls).__new__(cls) #自己中有,我们任然让其取继承父类中的__new__属性,来产生一个空对象,然后将对象初始化,拿到一个返回值
return obj
'''**********************************看成一个对象************************************************''' """-----------------------------------------------重点---------------------------------------------""" # 分析:调用Pepole的目的
#1、先造出一个People的空对象
#2、为该对空对象初始化独有的属性
# obj1=People('egon1',age=18)
# obj2=People('egon2',age=18)
# print(obj1)
# print(obj2) # obj=People('egon',age=18)
# print(obj.__dict__)
# print(obj.name)
# obj.eat()

Python之元类详细解析的更多相关文章

  1. Python 的元类设计起源自哪里?

    一个元老级的 Python 核心开发者曾建议我们( 点击阅读),应该广泛学习其它编程语言的优秀特性,从而提升 Python 在相关领域的能力.在关于元编程方面,他的建议是学习 Hy 和 Ruby.但是 ...

  2. python 通过元类控制类的创建

    一.python中如何创建类? 1. 直接定义类 class A: a = 'a' 2. 通过type对象创建 在python中一切都是对象 在上面这张图中,A是我们平常在python中写的类,它可以 ...

  3. python元类深入解析

    元类 什么是元类 元类是类的类,是类的模板(就如对象的模板是类一样) 元类的实例为类,类的实例为对象 元类是用来产生类的 动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,是运行时动 ...

  4. 谈谈Python中元类Metaclass(一):什么是元类

    简单的讲,元类创建了Python中所有的对象. 我们说Python是一种动态语言,而动态语言和静态语言最大的不同,就是函数和类不是编译时定义的,而是运行时动态创建的. 比方说我们要定义一个HelloW ...

  5. 关于python的元类

    当你创建一个类时: class Foo(Bar): pass Python做了如下的操作: Foo中有__metaclass__这个属性吗?如果是,Python会在内存中通过__metaclass__ ...

  6. Python的元类

    1.用元类验证子类 每当我们定义新类的时候,元类就会运行雅正代码,以确保这个新类符合规定的规范. Python系统把子类的class语句处理完毕,就会调用元类的 __new__ 方法.元类可以通过 _ ...

  7. 理解python的元类

    看了一篇文档,借鉴一下!写下自己对python元类的理解,欢迎各位大神给出意见. 我的理解就是 type用来创建元类,元类用来创建类,类用来创建实例 这样一想,是不是可以认为元类创建类的过程等同于类创 ...

  8. 【转】Python 之 元类

    原文链接: https://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python      http://python.jo ...

  9. Python中元类

    元类(metaclass) 简单地说,元类就是一个能创建类的类,而类class 是由type创建的,class可以创建对象 type与object的关系详见:python中type和object 1. ...

随机推荐

  1. Linux为grub菜单加密码

    为grub菜单加密码 加入密码后,再次进入单用户或者给下次管理grub需要输入密码 加密操作 /sbin/grub-md5-crypt # 之后输入2次密码会生成加密后字符串 编辑grub加载文件 v ...

  2. CSS学习摘要-引入样式

    CSS学习摘要-引入样式 注:主要是摘录自MDN 网络开发者这个网站的. CSS 实际上如何工作? 当浏览器显示文档时,它必须将文档的内容与其样式信息结合.它分两个阶段处理文档: 浏览器将 HTML和 ...

  3. pt1000测温度

    本设计使用的PT1000热电阻铂热电阻,它的阻值会随着温度的变化而改变.PT后的1000即表示它在0℃时阻值为1000欧姆,在300℃时它的阻值约为2120.515欧姆.它的工业原理:当PT1000在 ...

  4. jenkins 安卓打包生成二维码下载

    先来张图看看吧 构思 jenkins gradle 打包apk文件,python myqr 模块生成二维码 放入nginx 访问图片的路径,apk安装包放在 nginx 下载目录. 环境 centos ...

  5. Flex布局及其应用

    什么是弹性盒子? 弹性盒子是 CSS3 的一种新的布局模式.相对于传统的依赖于display+position+float的布局方式,弹性盒子更加以有效的方式来对一个容器中的子元素进行排列.对齐和分配 ...

  6. DNS Brand

    1) You must add glue records (child nameservers) to your-domain.com from your domain's registrar con ...

  7. screen 命令基本操作教程

    sreen 命令提供的基本功能与 tmux 较为相似( 关于 tmux 基本操作可参见笔者的博文 终端复用工具 tmux 基本操作教程 ).screen 命令以会话( session )为基础为用户提 ...

  8. VMware常见错误故障排查

    1. VMware安装失败 “Failed to create the requested registry key Key:installer Error:1021" 1.1. windo ...

  9. python multiprocessing 使用

    如何在Pool中使用Queue,Stack Overflow的回答,戳这里 其实吧官方文档看一遍应该就大部分都懂了. 需要注意的是:在使用多进程的时候,我们的进程函数的传入参数必须是pickle-ab ...

  10. UVa 10213 - How Many Pieces of Land ?(欧拉公式)

    链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...