面向对象之反射、包装、(定制)

什么是反射?

反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省),

这一概念的提出很快引发了计算机科学领域关于应用反射的研究。它首次被程序语言的设计领域所采用。并在Lisp和面向

对象方面取得了成绩。

 

一、python3中四个可以实现自省的函数,下列方法适用于类和对象

class BlackMedium:feture='Ugly'def __init__(self,name,addr):self.name=nameself.addr=addrdef sell_hourse(self):print('[%s]正在卖房子,傻逼才买呢'%self.name)def rent_hourse(self):print('[%s]正在租房子,傻逼才买呢'%self.name)b1=BlackMedium('黑中介','殡仪馆')

 

1、hasattr(object,name)

判断object中有没有一个name字符串对应的方法或属性

class BlackMedium:feture='Ugly'def __init__(self,name,addr):self.name=nameself.addr=addrdef sell_hourse(self):print('[%s]正在卖房子,傻逼才买呢'%self.name)def rent_hourse(self):print('[%s]正在租房子,傻逼才买呢'%self.name)b1=BlackMedium('黑中介','殡仪馆')
print(b1.__dict__)#{'name': '黑中介', 'addr': '殡仪馆'}
# b1.name------->b1.__dict__['name]
print(b1.name)#黑中介
print(b1.addr)#殡仪馆
#用hasattr检测类的属性和方法,存在返回TRUE,不存在返回FALSE
print(hasattr(b1,'name'))#True
print(hasattr(b1,'addr'))#True
print(hasattr(b1,'namnmae'))#False
hasattr(object,name)

 

2、getattr(object,name,default=None)

检测正确时,有属性就返回属性值,有方法就返回方法的内存地址,加()就可以运行

检测有错误时,不给default赋值会报错,报错时写什么会提示什么

#检测属性,属性存在就会打印值,属性不存在会打印报错或default
print(getattr(b1,'name'))#黑中介
print(getattr(b1,'aaaaaa'))#有报错提示
print(getattr(b1,'aaaaaa','没有此属性'))#有报错提示:没有此属性#检测方法,有则返回内存地址,加()就可以运行,没有则报错或提示default信息
print(getattr(b1,'sell_hourse','无此方法'))#返回sell_hourse方法的内存地址,-------》b1.sell_hourse
#<bound method BlackMedium.sell_hourse of <__main__.BlackMedium object at 0x0000020EE5447198>>
#有内存地址加()就可以运行
func=getattr(b1,'sell_hourse')
func()#[黑中介]正在卖房子,傻逼才买呢print(getattr(b1,'jskdkflsd','无此方法'))#无此方法
getattr(object,name,default)

 

3、setattr(x,y,z)

可以增加修改属性,也可以增加方法,

x传入对象,y传入字符串相当于字典中的key,x传入值相当于字典中的value

print(b1.__dict__)#{'name': '黑中介', 'addr': '殡仪馆'}
setattr(b1,'name','SB')#修改属性
setattr(b1,'sb',True)#增加属性
print(b1.__dict__)#{'name': 'SB', 'addr': '殡仪馆', 'sb': True}
setattr(b1,'func',lambda self:self.name+'SB')#增加函数属性
# print(b1.func(b1))#黑中介SB
setattr(x,y,z)

 

4、delattr(x,y)

删除属性x,y同上

print(b1.__dict__)#{'name': '黑中介', 'addr': '殡仪馆'}
delattr(b1,'name')#删除属性------》del b1.name
# del b1.name
print(b1.__dict__)#{'addr': '殡仪馆'}
setattr(x,y)

 

5、动态模块导入

1、把模块名或文件名以字符串形式传给__import__,如果模块在二级文件内,__import__方法只能拿到最顶级模块
module_t=__import__('三级菜单')#执行module_t就会执行模块内的代码
print(module_t)2import imaplib
m=imaplib.import_module('文件.三级菜单')#直接定位到三级菜单
print(m)
3、导入有*号时,如果模块里面的属性有 _名字 的属性或方法时,
带 下划线的属性或方法则不能被导入
from 模块名 import *

 补充:

一切皆对象,文件也是对象同样可以使用自省的方法

1、情景:当你写的代码有上万行时(此时已是大佬 ^_^),想不起来某个功能是否完成既可以使用下面的方法来判断

x=111
y=222
#用sys可以导入模块自己,用hasattr可以检测功能是否完成
import sys
obj=sys.modules[__name__]
print(hasattr(obj,'x'))#True
print(hasattr(obj,'xsdf'))#False
导入模块自己

 

2、情景:做程序开发,每个人写不同的功能,当需要用到别人的功能时不知道是否完成,因此我们可以导入同事写的代码文件,用hasattr判断你需要的功能是否完成

import test as obj
print(obj)print(hasattr(obj,'say_hi'))if hasattr(obj,'say_hi'):func=getattr(obj,'say_hi')func()else:print('其他的逻辑')
导入别人的模块

 

二、下划线开头的三种attr方法

这三种方法是给实例用的和类没关系

1、__getattr__(self,item)

只有使用点调用属性且属性不存在时才会触发__getattr__

class Foo:def __init__(self,name,age):self.name=nameself.age=agedef __getattr__(self, item):print('执行__getattr__,item是 %s'%item)#调用不存在属性时触发__getattr__

f1=Foo('飞乐',18)
print(f1.__dict__)#{'name': '飞乐', 'age': 18}
f1.name#不会触发__getattr__
f1.jsdlkf#执行__getattr__,item是 jsdlkf
__getattr__(self,item)

 

2、__delattr__(self,item)

删除属性时会触发

class Foo:def __init__(self,name,age):self.name=nameself.age=agedef __delattr__(self, item):#只要有删除操作就会触发__delattr__,并不一定能删除,# 下面的内容会讲到触发__delattr__并且删除值print('执行__delattr__,item是 %s'%item)
f1=Foo('飞乐',18)
print(f1.__dict__)#{'name': '飞乐', 'age': 18}
del f1.age#执行__delattr__,item是 age
print(f1.__dict__)#{'name': '飞乐', 'age': 18}
__delattr__(self,item)

 

3、__setattr__(self,key,value)

增加或修改属性会触发__setattr__的执行,在实例化对象时__init__函数属于增加属性操作,也会触发__setattr__的执行 

class Foo:def __init__(self,name,age):#会触发__setattr__self.name=nameself.age=agedef __setattr__(self, key, value):#添加或修改属性会触发它的执行print('执行__setattr__,key: %s value: %s'%(key,value))# self.kye=value #一直触发__setattr__无期递归,你好好想想self.__dict__[key]=value#应该使用它

f1=Foo('飞乐',18)
#执行__setattr__,key: name value: 飞乐
#执行__setattr__,key: age value: 18
print(f1.__dict__)#{'name': '飞乐', 'age': 18}
f1.sex='male'#增加属性,执行__setattr__,key: sex value: maleprint(f1.name)#飞乐
f1.name='king'#修改属性,执行__setattr__,key: name value: king
print(f1.__dict__)#{'name': 'king', 'age': 18, 'sex': 'male'}
print(f1.name)#king
__setattr__(self,key,value)

 

4、利用attr方法定制属于自己的方法

根据下方代码可以自己扩展,好好想想

class Foo:def __init__(self,name,age):self.name=nameself.age=agedef __getattr__(self, item):print('%s 属性不存在'%item)def __setattr__(self, key, value):print('正在设置--------》')if type(value) is str:# self.key=value  会触发__setattr__递归self.__dict__[key]=valueelse:print('属性添加必须是字符串')def __delattr__(self, item):print('不允许删除属性 【%s】'%item)#del self.__dict__[item]#self.__dict__.pop(item)
# f1=Foo('飞乐',18)#属性添加必须是字符串
f1=Foo('飞乐','18')#增加或修改属性会触发__setattr__
#正在设置--------》
#正在设置--------》
f1.name#不会触发__getattr__
f1.king#触发__getattr__  king 属性不存在
print(f1.__dict__)#{'name': '飞乐', 'age': '18'}
f1.name='king'#触发了__setattr__
print(f1.__dict__)# {'name': 'king', 'age': '18'}
del f1.name#不允许删除属性 【name】
定制

 

三、包装

包装标准类型,通过继承和派生进行包装定制属于自己的数据类型

1、通过继承派生包装

class List(list):def append(self, object):if type(object) is str:super().append(object)#继承父类的append方法else:print('类型必须是字符串')def show_mid(self):mid_index=int(len(self)/2)return self[mid_index]l1=List('helloword')
print(l1,type(l1))#['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'd'] <class '__main__.List'>
l1.append('king')
print(l1)#['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'd', 'king']
l1.append(3245)#类型必须是字符串类型
print(l1.show_mid())#w
定制属于自己的list方法

 

2、通过__getattr__授权(包装)

授权也是一种包装用__getattr__方法,不用继承和派生的方法来实现

import time
class Open:def __init__(self,filename,mode='r',encoding='utf-8'):#用类有两种方法一种是继承另一种是组合self.file=open(filename,mode,encoding=encoding)#组合self.mode=modeself.encoding=encodingdef write(self,line):t=time.strftime('%Y-%m-%d %X')self.file.write('%s %s'%(t,line))def __getattr__(self, item):return getattr(self.file,item)#返回item方法的内存地址,
#f1的属性找不到时会触发__getattr__的执行
f1=Open('a.txt','w+')
print(f1.write)#返回的内存地址加()就可以执行
#<built-in method write of _io.TextIOWrapper object at 0x000002138D1E8B40>
f1.write('helloword')#把内容写入到文件中
f1.seek(0)
print(f1.read())#helloword#f1的write能找到时
f1.write('CPU过载过高\n')
f1.write('内存不足\n')
f1.write('系统被不明病毒攻击\n')
f1.seek(0)
print(f1.read())#读出了定制写入的内容
# 2018-09-10 22:34:34 helloword2018-09-10 22:34:34 CPU过载过高
# 2018-09-10 22:34:34 内存不足
# 2018-09-10 22:34:34 系统被不明病毒攻击
授权

 

转载于:https://www.cnblogs.com/happyfei/p/9618996.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/413351.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[css] 为什么说css中能用子代选择器的时候不要用后代选择器?

[css] 为什么说css中能用子代选择器的时候不要用后代选择器&#xff1f; 选择从右到左依次解析匹配&#xff0c;所以后代选择器会去找它的所有父级&#xff0c; 而子代选择器只会选择直接的父级&#xff1b;减少匹配次数&#xff0c;提高效率个人简介 我是歌谣&#xff0c;欢…

javascript基本函数

如何使用jquery刷新当前页面 下面介绍全页面刷新方法&#xff1a;有时候可能会用到 window.location.reload()刷新当前页面. parent.location.reload()刷新父亲对象&#xff08;用于框架&#xff09; opener.location.reload()刷新父窗口对象&#xff08;用于单开窗口&…

[css] 如何给文字的color设置渐变

[css] 如何给文字的color设置渐变 .text {background: -webkit-linear-gradient(#eee, #333);-webkit-background-clip: text;-webkit-text-fill-color: transparent; }个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。…

微信小程序运行报错---invoke event

微信小程序页面跳转 //跳转到新的页面&#xff0c;新的页面带有返回按钮&#xff0c;不能跳转到tabBar页面&#xff0c;否则会报invoke event之类的错误 wx.navigateTo({url: }) //跳转到新的页面&#xff0c;不带返回按钮&#xff0c;但是不能太偶转到tabBar页面&#xff0…

js 静止f1到f12 和屏蔽鼠标右键

//静止键盘f1-f12 function testKeyDown(event) { if ((event.keyCode 112) || //屏蔽 F1 (event.keyCode 113) || //屏蔽 F2 (event.keyCode 114) || //屏蔽 F3 (event.keyCode 115) || //屏蔽 F4 //(event.keyCode 116) || //屏蔽 F5 (event.keyCode 117) || //屏蔽 F6…

[css] 如何在白天和黑夜自动切换页面的颜色?

[css] 如何在白天和黑夜自动切换页面的颜色&#xff1f; 媒体查询的内容都是设备的属性&#xff1a;宽度高度&#xff0c;旋转方向&#xff0c;打印样式&#xff0c;分辨率 所以用媒体查询的话&#xff0c;需要用户的设备拥有切换黑暗模式的功能 借助 js 切换页面颜色的话&…

py 的 第 30 天

首先学习了一下socket&#xff0c;这个经过周末作业总算是掌握精髓了&#xff0c;可能还没掌握只是以为掌握了? import socketserverclass MyServer(socketserver.BaseRequestHandler):def handle(self):passserver socketserver.ThreadingTCPServer((192.168.13.84,8001,),M…

Error: Cannot find module 'webpack-cli'--解决方案

npm install webpack-cli -g 全局安装解决 今日赠语&#xff1a; 哈佛大学研究心理学表示&#xff1a; 1、床乱糟糟的人&#xff0c;比穿整洁的人&#xff0c;创造力平均要高出50% 2、经常迟到的人&#xff0c;比不迟到的人&#xff0c;幽默感平均要高出70% 3、饭量大的人&…

[css] CSS中哪些属性会引起GPU渲染,会增加耗电吗?

[css] CSS中哪些属性会引起GPU渲染&#xff0c;会增加耗电吗&#xff1f; 肆无忌惮的开启GPU硬件加速&#xff0c;会导致大量消耗设备电量&#xff0c;降低电池寿命等问题。个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很…

[css] OOCSS有哪些好处?对应的库有哪些?

[css] OOCSS有哪些好处&#xff1f;对应的库有哪些&#xff1f; 有语义的类名&#xff0c;逻辑性强的层次关系 可重用&#xff0c;样式和结构的分离&#xff0c;容器和内容的分离 Kite个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但…

分享菜单效果

分享菜单效果&#xff1a; 1 <!DOCTYPE html>2 <html lang"en">3 <head>4 <meta charset"UTF-8">5 <title>分享菜单</title>6 <style>7 #div1{width: 100px; height: …

vue中的js引入图片,必须require进来

vue怎样能把assets里面的图片拿出来&#xff1f; 1.在img标签里面直接写上路径&#xff1a; <img src"../assets/a1.png" class"" width"100%"/> 2.利用数组保存再循环输出&#xff1a; return {imgs: [{url: require(/assets/slide1.…

[css] 如何解决IE6浮动时产生双倍边距的BUG?

[css] 如何解决IE6浮动时产生双倍边距的BUG&#xff1f; 1.当块级元素有浮动样式的时候&#xff0c;给元素添加margin-left和margin-right样式&#xff0c;在ie6下就会出现双倍边距2.给当前元素添加样式&#xff0c;使当前元素不为块&#xff0c;如&#xff1a;display:inline…

CSP 行车路线 最短路变型

问题描述&#xff1a; 小明和小芳出去乡村玩&#xff0c;小明负责开车&#xff0c;小芳来导航。小芳将可能的道路分为大道和小道。大道比较好走&#xff0c;每走1公里小明会增加1的疲劳度。小道不好走&#xff0c;如果连续走小道&#xff0c;小明的疲劳值会快速增加&#xff0c…

vue使用axios并存数据到state

npm安装 npm install axios --save main.js导入 // 引入axios&#xff0c;并加到原型链中 import Axios from axios import QS from qs Vue.prototype.$axios Axios Vue.prototype.qs QS 各子模块中使用&#xff0c;通过原型链 this.$axios ...... get实例 <div id&…

[css] 如何让IE6支持min-width和max-width?

[css] 如何让IE6支持min-width和max-width&#xff1f; 利用IE特有的css语法 .className {max-width:620px;min-width:1px;_width:expression(this.scrollWidth > 620 ? "620px":(this.scrollWidth < 1? "1px":"auto")); }个人简介 我…

tf.name_scope tf.variable_scope学习

1. 首先看看比较简单的 tf.name_scope(‘scope_name’). tf.name_scope 主要结合 tf.Variable() 来使用&#xff0c;方便参数命名管理。 Signature: tf.name_scope(*args, **kwds) Docstring: Returns a context manager for use when defining a Python op.# 也就是说&#x…

vue axios解决post传参数问题

我相信遇到这个问题的兄弟们&#xff0c;不带参数的情况下都是没有问题吧&#xff0c; 如果有问题&#xff0c;百度吧&#xff0c;好解决&#xff0c;答案都比较靠谱 这里主要针对带参数的情况&#xff0c;坑多 另外&#xff0c;我默认你用postman带参测试接口是没问题的 不…

[css] padding会影响到元素的大小,那不想让它影响到元素的宽度应该怎么办?

[css] padding会影响到元素的大小&#xff0c;那不想让它影响到元素的宽度应该怎么办&#xff1f; box-sizing:border-box个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端…

vue路由传参的三种基本方式

一&#xff1a; getDescribe(id) { // 直接调用$router.push 实现携带参数的跳转this.$router.push({path: /describe/${id},}) 方案一&#xff0c;需要对应路由配置如下&#xff1a; {path: /describe/:id,name: Describe,component: Describe} 很显然&#xff0c;需要在p…