一、补充内置函数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. [C++] 用Xcode来写C++程序[4] 函数

    用Xcode来写C++程序[4] 函数 此节包括引用函数,内联函数,防止修改函数入参,函数自身带有默认值. 引用函数:防止复制对象,减少系统开销 内联函数:编译的时候根据具体情形将代码嵌入进去,成不成 ...

  2. 使用FBTweak

    使用FBTweak https://github.com/facebook/Tweaks FBTweak是Facebook的一款开源库,用于微调数据而无需我们重复编译跑真机用的,它支持4种类型的cel ...

  3. django 实用工具dj-database-url 快速配置数据库

    dj-database-url Github>>> django快速配置多种数据库 $ pip install dj-database-url Configure your data ...

  4. September 25th 2017 Week 39th Monday

    No man is rich enough to buy back his own past. 没有人富有到可以赎回自己的过去. Those rich are not willing to buy b ...

  5. 【转】【Flex】#010 操作XML文件(E4X)

    该教程转载来自于:http://blog.chinaunix.net/uid-14767524-id-2785506.html    [看到这边文章的位置,具体原作者未知] 经过一些排版的修改,其他内 ...

  6. PHP Redis 全部操作方法 转载

    PHP Redis 全部操作方法   Classes and methods Usage Class Redis Class RedisException Predefined constants C ...

  7. grep命令.md

    grep命令 简介 Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来.grep全称是Global Regular Expression Prin ...

  8. Objective-C 与命名空间

    http://blog.csdn.net/michelle__/article/details/52528172 Objective-C 在Objective-C应用中的所有类名都必须是全局唯一的.命 ...

  9. Laravel中如何将单个routes.php分割成多个子文件

    随着业务逻辑越来越复杂,routes.php文件也会变得越来越庞大,为了便于管理,我们可以像管理配置文件那样将其分割成多个子文件,这实现起来很简单: // app/routes.php ... // ...

  10. 3282. Tree【LCT】

    Description 给定N个点以及每个点的权值,要你处理接下来的M个操作. 操作有4种.操作从0到3编号.点从1到N编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和 ...