4月17日 python学习总结 反射、object内置方法、元类
一、反射
下述四个函数是专门用来操作类与对象属性的,如何操作?
通过字符串来操作类与对象的属性,这种操作称为反射
class People:
country="China"
def __init__(self,name):
self.name=name
def tell(self):
print('%s is aaa' %self.name) obj=People('egon') 1、hasattr
print(hasattr(People,'country'))
print('country' in People.__dict__) print(hasattr(obj,'name'))
print(hasattr(obj,'country'))
print(hasattr(obj,'tell')) 2、getattr #只有在使用点调用属性且属性不存在的时候才会触发
x=getattr(People,'country1',None)
print(x) f=getattr(obj,'tell',None)#obj.tell
print(f == obj.tell)
f()
obj.tell() 3、setattr
People.x=111
setattr(People,'x',111)
print(People.x) obj.age=18
setattr(obj,"age",18)
print(obj.__dict__) 4、delattr
del People.country
delattr(People,"country")
print(People.__dict__) del obj.name
delattr(obj,"name")
print(obj.__dict__)
class Foo:
x=1
def __init__(self,y):
self.y=y def __getattr__(self, item):
print('----> from getattr:你找的属性不存在') def __setattr__(self, key, value):
print('----> from setattr')
# self.key=value #这就无限递归了,你好好想想
# self.__dict__[key]=value #应该使用它 def __delattr__(self, item):
print('----> from delattr')
# del self.item #无限递归了
self.__dict__.pop(item) #__setattr__添加/修改属性会触发它的执行
f1=Foo(10)
print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
f1.z=3
print(f1.__dict__) #__delattr__删除属性的时候会触发
f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作
del f1.a
print(f1.__dict__) #__getattr__只有在使用点调用属性且属性不存在的时候才会触发
f1.xxxxxx
例子
应用实例
class Foo:
def run(self):
while True:
cmd=input('cmd>>: ').strip()
# print('%s run...' %cmd)
if hasattr(self,cmd):
func=getattr(self,cmd)
func() def download(self):
print('download....') def upload(self):
print('upload...') # obj=Foo()
# obj.run()
二、object内置方法
__str__ 、__del__、__call__等没有设置也是默认就有的,从object类中继承来,不做任何操作,此处是在重写父类方法
1、__str__()方法 在打印对象时触发
class People:
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex def __str__(self):
# print('========>')
return '<名字:%s 年龄:%s 性别:%s>' %(self.name,self.age,self.sex) obj=People('egon',18,'male')
print(obj) #执行时相当于print(obj.__str__()) # l=list([1,2,3])
# print(l)
2、__del__() 析构函数 对象删除时触发
eg:
1. del 对象名 删除对象 2. 程序结束释放内存空间时 3. 对象被垃圾回收机制回收时
在对象被创建时,若有打开文件或手动开辟内存空间等操作,在删除对象,这些系统资源没有被释放,就必须要用__del__方法主动释放内存空间
import time class People:
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex def __del__(self): # 在对象被删除的条件下,自动执行
print('__del__') obj=People('egon',18,'male') del obj #obj.__del__() time.sleep(5)
应用
class MyOpen:
def __init__(self,filepath,mode="r",encoding="utf-8"):
self.filepath=filepath
self.mode=mode
self.encoding=encoding
self.fobj=open(filepath,mode=mode,encoding=encoding) def __str__(self):
msg="""
filepath:%s
mode:%s
encoding:%s
""" %(self.filepath,self.mode,self.encoding)
return msg def __del__(self):
self.fobj.close() # f=open('a.txt',mode='r',encoding='utf-8') f=MyOpen('aaa.py',mode='r',encoding='utf-8')
# print(f.filepath,f.mode,f.encoding)
# print(f) # print(f.fobj)
res=f.fobj.read()
print(res)
3、__call__ 方法 调用对象时触发(可用于元类控制类的实例化)
class Foo:
def __init__(self):
pass
def __str__(self):
return '123123' def __del__(self):
pass # 调用对象,则会自动触发对象下的绑定方法__call__的执行,
# 然后将对象本身当作第一个参数传给self,将调用对象时括号内的值
#传给*args与**kwargs
def __call__(self, *args, **kwargs):
print('__call__',args,kwargs)
三、元类
1、cexec()函数
exec(code , global , local) 将第一个参数code中的代码解析,其中的全局变量以字典形式放到第二个参数global中,局部变量以字典形式放到第三个参数 local中
code="""
global x
x=0
y=2
"""
global_dic={'x':100000}
local_dic={}
exec(code,global_dic,local_dic) print(global_dic)
print(local_dic) code="""
x=1
y=2
def f1(self,a,b):
pass
"""
local_dic={}
exec(code,{},local_dic)
print(local_dic)
2、一切皆对象,类也是对象,类的类是什么呢?
类的类就是元类
我们用class定义的类使用来产生我们自己的对象
内置元类type是用来专门产生class定义的类的
1、用内置的元类type,来实例化得到我们的类
class_name='Chinese'
class_bases=(object,)
class_body="""
country="China"
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
def speak(self):
print('%s speak Chinese' %self.name)
"""
class_dic={}
exec(class_body,{},class_dic) 类的三大要素
print(class_name,class_bases,class_dic) Chinese=type(class_name,class_bases,class_dic)
print(Chinese) p=Chinese('egon',18,'male')
print(p.name,p.age,p.sex)
2、自定义元类:
class Mymeta(type):
# 来控制类Foo的创建
def __init__(self,class_name,class_bases,class_dic): #self=Foo
# print(class_name)
# print(class_bases)
# print(class_dic)
if not class_name.istitle():
raise TypeError('类名的首字母必须大写傻叉') if not class_dic.get('__doc__'):
raise TypeError('类中必须写好文档注释,大傻叉') super(Mymeta,self).__init__(class_name,class_bases,class_dic) # 控制类Foo的调用过程,即控制实例化Foo的过程
def __call__(self, *args, **kwargs): #self=Foo,args=(1111,) kwargs={}
# print(self)
# print(args)
# print(kwargs) #1 造一个空对象obj
obj=object.__new__(self) #2、调用Foo.__init__,将obj连同调用Foo括号内的参数一同传给__init__
self.__init__(obj,*args,**kwargs) return obj #Foo=Mymeta('Foo',(object,),class_dic)
class Foo(object,metaclass=Mymeta):
"""
文档注释
"""
x=1
def __init__(self,y):
self.Y=y def f1(self):
print('from f1') obj=Foo(1111) #Foo.__call__() # print(obj)
# print(obj.y)
# print(obj.f1)
# print(obj.x)
单例设计模式:就是只有一个对象的模式,就算是创建多次对象指向的也是同一个对象地址
第一种实现方式:
# 单例模式
import settings class MySQL:
__instance=None
def __init__(self,ip,port):
self.ip=ip
self.port=port @classmethod
def singleton(cls):
if not cls.__instance:
obj=cls(settings.IP, settings.PORT) #setting中的IP 和PORT是固定值
cls.__instance=obj
return cls.__instance # obj4=MySQL(settings.IP,settings.PORT)
# print(obj4.ip,obj4.port) obj4=MySQL.singleton()
obj5=MySQL.singleton()
obj6=MySQL.singleton() print(obj4 is obj5 is obj6)
第二种:通过元类
#方式二:定制元类实现单例模式
# import settings
#
# class Mymeta(type):
# def __init__(self,name,bases,dic): #定义类Mysql时就触发
#
# # 事先先从配置文件中取配置来造一个Mysql的实例出来
# self.__instance = object.__new__(self) # 产生对象
# self.__init__(self.__instance, settings.HOST, settings.PORT) # 初始化对象
# # 上述两步可以合成下面一步
# # self.__instance=super().__call__(*args,**kwargs)
#
#
# super().__init__(name,bases,dic)
#
# def __call__(self, *args, **kwargs): #Mysql(...)时触发
# if args or kwargs: # args或kwargs内有值
# obj=object.__new__(self)
# self.__init__(obj,*args,**kwargs)
# return obj
#
# return self.__instance
#
#
#
#
# class Mysql(metaclass=Mymeta):
# def __init__(self,host,port):
# self.host=host
# self.port=port
#
#
#
# obj1=Mysql() # 没有传值则默认从配置文件中读配置来实例化,所有的实例应该指向一个内存地址
# obj2=Mysql()
# obj3=Mysql()
#
# print(obj1 is obj2 is obj3)
#
# obj4=Mysql('1.1.1.4',3307)
第三种: 装饰器
# 方式三:定义一个装饰器实现单例模式
# import settings
#
# def singleton(cls): #cls=Mysql
# _instance=cls(settings.HOST,settings.PORT)
#
# def wrapper(*args,**kwargs):
# if args or kwargs:
# obj=cls(*args,**kwargs)
# return obj
# return _instance
#
# return wrapper
#
#
# @singleton # Mysql=Singleton(Mysql)
# class Mysql:
# def __init__(self,host,port):
# self.host=host
# self.port=port
#
#
#
# obj1=Mysql()
# obj2=Mysql()
# obj3=Mysql()
# print(obj1 is obj2 is obj3) #True
#
# obj4=Mysql('1.1.1.3',3307)
# obj5=Mysql('1.1.1.4',3308)
# print(obj3 is obj4) #Fals
作业:
'''
4-17日作业
'''
'''
1、判断一个对象是否属于str类型,判断一个类是否是另外一个类的子类
'''
a='123'
print(isinstance(a,str))
print(issubclass(str,object)) '''
2、有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类(放到了另外一个文件中),但是egon去跟女朋友度蜜月去了,还没有完成他写的类,
class FtpClient:
"""
ftp客户端,但是还么有实现具体的功能
"""
def __init__(self,addr):
print('正在连接服务器[%s]' %addr)
self.addr=addr 此处应该完成一个get功能
lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。
''' class FtpClient:
"""
ftp客户端,但是还么有实现具体的功能
""" def __init__(self, addr):
print('正在连接服务器[%s]' % addr)
self.addr = addr
f=FtpClient('egon')
addr=getattr(f,'addr')
print(addr) ''' 3、定义一个老师类,定制打印对象的格式为‘<name:egon age:18 sex:male>’
'''
class Teacher:
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
def __str__(self):
return '<name: %s age: %s sex: %s>'%(self.name,self.age,self.sex)
t=Teacher('egon',18,'male')
print(t) '''
4、定义一个自己的open类,控制文件的读或写,在对象被删除时自动回收系统资源
'''
class MyOpen:
def __init__(self,file,io,encoding):
self.file=file
self.io=io
self.encoding=encoding
self.my_open=open(self.file,self.io,encoding=self.encoding)
def __del__(self):
self.my_open.close()
print('guan bi wen jian') mo=MyOpen(r'F:\python\object\days2\days23\setting.py','rt','utf-8')
del mo '''
5、自定义元类,把自定义类的数据属性都变成大写,必须有文档注释,类名的首字母必须大写
'''
class Mymeta(type):
def __init__(self,class_name,class_base,class_dict):
dict={}
for name in class_dict:
if not name.istitle():
new_name=name.capitalize()
dict.update({new_name:class_dict[name]})
print(dict)
super().__init__(class_name,class_base,dict)
if not class_name.istitle():
raise TypeError('类名必须首字母大写')
if not class_dict.get('__doc__'):
raise TypeError('类必须有文档注释')
class My(object,metaclass=Mymeta):
'''
MY 1233123
'''
char='123'
def abc(self):
print(self.char)
m=My()
print(My.__dict__) ''' 6、用三种方法实现单例模式,参考答案:http://www.cnblogs.com/linhaifeng/articles/8029564.html#_label5
''' class Mymeta(type):
__obj = ''
def __call__(self, *args, **kwargs):
if self.__obj=='':
self.__obj=self.__new__(self)
self.__obj.__init__(*args, **kwargs)
return self.__obj
class My(object,metaclass=Mymeta):
'''
MY 1233123
'''
char='123'
def abc(self):
print(self.char)
m = My()
m2 = My()
m3 = My()
print(m, m2, m3)
4月17日 python学习总结 反射、object内置方法、元类的更多相关文章
- python 面向对象之反射及内置方法
面向对象之反射及内置方法 一.静态方法(staticmethod)和类方法(classmethod) 类方法:有个默认参数cls,并且可以直接用类名去调用,可以与类属性交互(也就是可以使用类属性) 静 ...
- python面向对象之反射和内置方法
一.静态方法(staticmethod)和类方法(classmethod) 类方法:有个默认参数cls,并且可以直接用类名去调用,可以与类属性交互(也就是可以使用类属性) 静态方法:让类里的方法直接被 ...
- python基础之反射内置方法元类
补充内置函数 isinstance(obj,Foo) # 判断obj是不是foo的实例 issubclass() # 判断一个类是不是另一个类的子类 反射 什么是反射? 通过字符串来操作 ...
- python学习day7 数据类型及内置方法补充
http://www.cnblogs.com/linhaifeng/articles/7133357.html#_label4 1.列表类型 用途:记录多个值(一般存放同属性的值) 定义方法 在[]内 ...
- Python学习之路8 - 内置方法
abs(-230) #取绝对值 all([0,1,-5]) #如果参数里面的所有值都为真就返回真,否则返回假 any([0,1,-5]) #如果参数里面有一个值为真则返回真,否则返回假 ascii([ ...
- Python反射和内置方法(双下方法)
Python反射和内置方法(双下方法) 一.反射 什么是反射 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省).这一概念的提出很快引发 ...
- day31 反射,内置方法,元类
目录 一.反射 1 什么是反射 2 如何实现反射 二.内置方法 1 什么是内置方法 2 为什么要用内置方法 3 如何使用内置方法 3.1 str 3.2 del 三.元类 1 什么是元类 2 clas ...
- Learning-Python【26】:反射及内置方法
反射的概念 可以用字符串的方式去访问对象的属性,调用对象的方法(但是不能去访问方法),Python 中一切皆对象,都可以使用反射. 反射有四种方法: hasattr:hasattr(object, n ...
- 面向对象(五)——isinstance与issubclass、反射、内置方法
isinstance与issubclass.反射.内置方法 一.isinstance与issubclass方法 1.isinstance是用来判断对象是否是某个类 isinstance(obj,cla ...
随机推荐
- Java面试-常见基础笔试题目
1. Vector, ArrayList, LinkedList的区别 Vector:①长度可变,以类似数组的形式存储于内存中,线程安全(同步),因为其大部分方法都有synchronized 关键字, ...
- Linux 源码安装Ansible 参考篇
Ansible 源码搭建配置 近期在学习自动化运维相关技术,文章主要模拟内网情况下对Ansible的安装演示,源码安装较为繁琐.枯燥,尤其是在实际安装过程中可能出现各式各样的问题,所有在安装过程中尽量 ...
- 《PHP程序员面试笔试宝典》——如何回答技术性的问题?
如何巧妙地回答面试官的问题? 本文摘自<PHP程序员面试笔试宝典> 程序员面试中,面试官会经常询问一些技术性的问题,有的问题可能比较简单,都是历年的面试.笔试真题,求职者在平时的复习中会经 ...
- Solution -「ZJOI 2020」「洛谷 P6631」序列
\(\mathcal{Description}\) Link. 给定一个长为 \(n\) 的非负整数序列 \(\lang a_n\rang\),你可以进行如下操作: 取 \([l,r]\),将 ...
- 【第二十四期】golang 一年经验开发 富途
他们家是按题目来的,从一个小题目慢慢延伸着问,由浅入深,问到你换题为止. 第一题 给了一个网址,解释一下浏览器填入这个网址后发生了什么? TCP为什么要三次握手四次挥手? 502是什么? 如果出现50 ...
- C#Winform 注册使用全局快捷键详解
C#.NET Winform 注册使用全局快捷键详解 借助于全局快捷键,用户可以在任何地方操控程序,触发对应的功能.但 WinForms 框架并没有提供全局快捷键的功能.想要实现全局快捷键需要跟 Wi ...
- 五、MyBatis缓存初体验
缓存就是内存中的数据,常常来自对数据库查询结果的保存,使用缓存, 我们可以避免频繁的与数据库进行交互, 进而提高响应速度. 一级缓存初体验(session,默认打开) 同一查询执行两次以上:selec ...
- nginx域名转发
场景1:因服务器限制,所以只对外开放了一个端口,但是需要请求不同的外网环境,所以在中转服务器上用nginx做了一次转发 实现: server { listen 8051; server_name lo ...
- 赶紧收藏!最好用的BI工具都在这了!
1.bi厂商--思迈特软件Smartbi 广州思迈特软件有限公司成立于2011 年,以提升和挖掘企业客户的数据价值为使命,专注于商业智能与大数据分析软件产品与服务.思迈特软件是国家认定的"高 ...
- Mybatis学习笔记(详细)
介绍 三层架构:视图层.业务逻辑层.持久层 mybatis框架: 执行数据库操作,完成对数据库的增删改查,封装了jdbc mapper映射,将表中数据转为一个Java对象,一个表对应一个接口 Myba ...