当前位置: 首页 > 编程日记 > 正文

06 面向对象之:反射,双下方法

一、反射

反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。

python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

四个可以实现自省的函数

下列方法适用于类和对象(一切皆对象,类本身也是一个对象)

class Foo:f = '类的静态变量'def __init__(self,name,age):self.name=nameself.age=agedef say_hi(self):print('hi,%s'%self.name)obj=Foo('egon',73)#检测是否含有某属性
print(hasattr(obj,'name'))
print(hasattr(obj,'say_hi'))#获取属性
n=getattr(obj,'name')
print(n)
func=getattr(obj,'say_hi')
func()print(getattr(obj,'aaaaaaaa','不存在啊')) #报错#设置属性
setattr(obj,'sb',True)
setattr(obj,'show_name',lambda self:self.name+'sb')
print(obj.__dict__)
print(obj.show_name(obj))#删除属性
delattr(obj,'age')
delattr(obj,'show_name')
delattr(obj,'show_name111')#不存在,则报错print(obj.__dict__)对实例化对象的示例
对实例化对象的反射
class Foo(object):staticField = "old boy"def __init__(self):self.name = 'wupeiqi'def func(self):return 'func'@staticmethoddef bar():return 'bar'print getattr(Foo, 'staticField')
print getattr(Foo, 'func')
print getattr(Foo, 'bar')
对类的反射
import sysdef s1():print 's1'def s2():print 's2'this_module = sys.modules[__name__]hasattr(this_module, 's1')
getattr(this_module, 's2')
当前模块的反射
#一个模块中的代码
def test():print('from the test')
"""
程序目录:module_test.pyindex.py当前文件:index.py
"""
# 另一个模块中的代码
import module_test as obj#obj.test()print(hasattr(obj,'test'))getattr(obj,'test')()其他模块的示例
其他模块的反射

反射的应用:

了解了反射的四个函数。那么反射到底有什么用呢?它的应用场景是什么呢?

现在让我们打开浏览器,访问一个网站,你单击登录就跳转到登录界面,你单击注册就跳转到注册界面,等等,其实你单击的其实是一个个的链接,每一个链接都会有一个函数或者方法来处理。

class User:def login(self):print('欢迎来到登录页面')def register(self):print('欢迎来到注册页面')def save(self):print('欢迎来到存储页面')while 1:choose = input('>>>').strip()if choose == 'login':obj = User()obj.login()elif choose == 'register':obj = User()obj.register()elif choose == 'save':obj = User()obj.save()
没学反射之前的解决方法
class User:def login(self):print('欢迎来到登录页面')def register(self):print('欢迎来到注册页面')def save(self):print('欢迎来到存储页面')user = User()
while 1:choose = input('>>>').strip()if hasattr(user,choose):func = getattr(user,choose)func()else:print('输入错误。。。。')
学了反射之后的解决方式

有多简单,一目了然。

二. 函数 vs 方法

学到这里,我终于能回答你一直以来可能有的一个疑问。那就是,之前的学习中我们称len()为函数(口误时称为方法)却称如str的strip为方法,那它到底叫什么?函数和方法有什么区别和相同之处?我在这里就正式的解释一下。

2.1 通过打印函数(方法)名确定

def func():passprint(func)  # <function func at 0x00000260A2E690D0>class A:def func(self):passprint(A.func)  # <function A.func at 0x0000026E65AE9C80>
obj = A()
print(obj.func)  # <bound method A.func of <__main__.A object at 0x00000230BAD4C9E8>>
View Code

2.2 通过types模块验证

from types import FunctionType
from types import MethodTypedef func():passclass A:def func(self):passobj = A()print(isinstance(func,FunctionType))  # True
print(isinstance(A.func,FunctionType))  # True
print(isinstance(obj.func,FunctionType))  # False
print(isinstance(obj.func,MethodType))  # True
View Code

2.3 静态方法是函数

from types import FunctionType
from types import MethodTypeclass A:def func(self):pass@classmethoddef func1(self):pass@staticmethoddef func2(self):pass
obj = A()# 静态方法其实是函数
# print(isinstance(A.func2,FunctionType))  # True
# print(isinstance(obj.func2,FunctionType))  # True
View Code

三. 双下方法

定义:双下方法是特殊方法,他是解释器提供的 由爽下划线加方法名加双下划线 __方法名__的具有特殊意义的方法,双下方法主要是python源码程序员使用的,我们在开发中尽量不要使用双下方法,但是深入研究双下方法,更有益于我们阅读源码。

调用:不同的双下方法有不同的触发方式,就好比盗墓时触发的机关一样,不知不觉就触发了双下方法,例如:__init__

3.01 __len__

class B:def __len__(self):print(666)b = B()
len(b) # len 一个对象就会触发 __len__方法。class A:def __init__(self):self.a = 1self.b = 2def __len__(self):return len(self.__dict__)
a = A()
print(len(a))
View Code

3.02 __hash__

class A:def __init__(self):self.a = 1self.b = 2def __hash__(self):return hash(str(self.a)+str(self.b))
a = A()
print(hash(a))
View Code

3.03 __str__

如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

class A:def __init__(self):passdef __str__(self):return '太白'
a = A()
print(a)
print('%s' % a)
View Code

3.04 __repr__

如果一个类中定义了__repr__方法,那么在repr(对象) 时,默认输出该方法的返回值。

class A:def __init__(self):passdef __repr__(self):return '太白'
a = A()
print(repr(a))
print('%r'%a)
View Code

3.05 __call__

对象后面加括号,触发执行。

注:构造方法__new__的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

class Foo:def __init__(self):passdef __call__(self, *args, **kwargs):print('__call__')obj = Foo() # 执行 __init__
obj()       # 执行 __call__
View Code

3.06 __eq__

class A:def __init__(self):self.a = 1self.b = 2def __eq__(self,obj):if  self.a == obj.a and self.b == obj.b:return True
a = A()
b = A()
print(a == b)
View Code

3.07 __del__

析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

3.08__new__

class A:def __init__(self):self.x = 1print('in init function')def __new__(cls, *args, **kwargs):print('in new function')return object.__new__(A, *args, **kwargs)a = A()
print(a.x)
View Code
class A:__instance = Nonedef __new__(cls, *args, **kwargs):if cls.__instance is None:obj = object.__new__(cls)cls.__instance = objreturn cls.__instance
单例模式
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
【采用单例模式动机、原因】
对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。
【单例模式优缺点】
【优点】
一、实例控制
单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
二、灵活性
因为类控制了实例化过程,所以类可以灵活更改实例化过程。
【缺点】
一、开销
虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
二、可能的开发混淆
使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
三、对象生存期
不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用单例模式具体分析
单例模式具体分析

3.09 __item__系列

class Foo:def __init__(self,name):self.name=namedef __getitem__(self, item):print(self.__dict__[item])def __setitem__(self, key, value):self.__dict__[key]=valuedef __delitem__(self, key):print('del obj[key]时,我执行')self.__dict__.pop(key)def __delattr__(self, item):print('del obj.key时,我执行')self.__dict__.pop(item)f1=Foo('sb')
f1['age']=18
f1['age1']=19
del f1.age1
del f1['age']
f1['name']='alex'
print(f1.__dict__)
View Code

3.10 上下文管理器相关

__enter__  __exit__

# 如果想要对一个类的对象进行with  as 的操作 不行。
class A:def __init__(self, text):self.text = textwith A('大爷') as f1:print(f1.text)
没他们不可以这样操作
class A:def __init__(self, text):self.text = textdef __enter__(self):  # 开启上下文管理器对象时触发此方法self.text = self.text + '您来啦'return self  # 将实例化的对象返回f1def __exit__(self, exc_type, exc_val, exc_tb):  # 执行完上下文管理器对象f1时触发此方法self.text = self.text + '这就走啦'with A('大爷') as f1:print(f1.text)
print(f1.text)
有他们可以这样操作
class Diycontextor:def __init__(self,name,mode):self.name = nameself.mode = modedef __enter__(self):print "Hi enter here!!"self.filehander = open(self.name,self.mode)return self.filehanderdef __exit__(self,*para):print "Hi exit here"self.filehander.close()with Diycontextor('py_ana.py','r') as f:for i in f:print i
自定义文件管理器

相关面试题:

class StarkConfig:def __init__(self,num):self.num = numdef run(self):self()def __call__(self, *args, **kwargs):print(self.num)class RoleConfig(StarkConfig):def __call__(self, *args, **kwargs):print(345)def __getitem__(self, item):return self.num[item]v1 = RoleConfig('alex')
v2 = StarkConfig('太白金星')
# print(v1[1])
# print(v2[2])
v1.run()-------
class UserInfo:passclass Department:passclass StarkConfig:def __init__(self, num):self.num = numdef changelist(self, request):print(self.num, request)def run(self):self.changelist(999)class RoleConfig(StarkConfig):def changelist(self, request):print(666, self.num)class AdminSite:def __init__(self):self._registry = {}def register(self, k, v):self._registry[k] = vsite = AdminSite()
site.register(UserInfo, StarkConfig)
# 1 
# obj = site._registry[UserInfo]()# 2
obj = site._registry[UserInfo](100)
obj.run()-------
class UserInfo:passclass Department:passclass StarkConfig:def __init__(self,num):self.num = numdef changelist(self,request):print(self.num,request)def run(self):self.changelist(999)class RoleConfig(StarkConfig):def changelist(self,request):print(666,self.num)class AdminSite:def __init__(self):self._registry = {}def register(self,k,v):self._registry[k] = v(k)site = AdminSite()
site.register(UserInfo,StarkConfig)
site.register(Department,RoleConfig)for k,row in site._registry.items():row.run()-------
class A:list_display = []def get_list(self):self.list_display.insert(0,33)return self.list_displays1 = A()
print(s1.get_list())-------
class A:list_display = [1, 2, 3]def __init__(self):self.list_display = []def get_list(self):self.list_display.insert(0, 33)return self.list_displays1 = A()
print(s1.get_list())------
class A:list_display = []def get_list(self):self.list_display.insert(0,33)return self.list_displayclass B(A):list_display = [11,22]s1 = A()
s2 = B()
print(s1.get_list())
print(s2.get_list())
View Code

转载于:https://www.cnblogs.com/Big-Dinosaur/p/10486909.html

相关文章:

实现对学生信息的修改操作

返回目录&#xff1a;《学生信息管理系统&#xff08;JavaJSP&#xff09;》 本篇博客主要实现对学生信息的修改操作&#xff1b; 步骤1、在学生信息的显示页面&#xff08;即student.jsp页面&#xff09;中&#xff0c;在表格最后增加一列“修改”超链接&#xff0c;在<tr&…

UML用例图概要(转)

用例图主要用来图示化系统的主事件流程&#xff0c;它主要用来描述客户的需求&#xff0c;即用户希望系统具备的完成一定功能的动作&#xff0c;通俗地理解用例就是软件的功能模块&#xff0c;所以是设计系统分析阶段的起点&#xff0c;设计人员根据客户的需求来创建和解释用例…

Python之迭代器,生成器与装饰器

1》迭代器原理及使用&#xff1a; 1>原理&#xff1a; 迭代器是访问集合元素的一种方式&#xff0c;迭代器对象从集合的第一个元素开始访问&#xff0c;直到所有的元素被访问完结束&#xff1b;迭代器只能往前不会后退&#xff0c;不过这也没什 么&a…

像乔布斯一样演讲

当苹果公司CEO史蒂夫-乔布斯开始今年&#xff08;2008年1月&#xff09;的Macworld时&#xff0c;我们看到他的商业演讲&#xff08;以下简称&#xff1a;演讲&#xff09;水平更上了一层楼。所有人都希 望能够在演讲中能更加简明扼要&#xff0c;乔布斯做到了&#xff0c;并且…

UNICODE使用的一些知识和技巧

UNICODE宏和_UNICODE宏的关系 在windows编程中,经常要编译Unicode版本的程序,方法是工程文件的配置中加上UNICODE或者_UNICODE编译条件,那么到底是用哪一个呢? Jeffrey Richter在《Windows核心编程》中说,_UNICODE宏用于C运行期头文件,而UNICODE宏则用于Windows头文件.当编译源…

编程学习网站收集

目录 1. 菜鸟教程 1.1 Java 教程 1.2 HTML 教程 1.3 CSS 教程 1.4 JavaScript 教程 1.5 JSP 教程 1.6 Servlet 教程 1.7 jQuery 教程 1.8 AJAX 教程 1.9 MySQL 教程 2. 易百教程 3. w3school 在线教程 1. 菜鸟教程 菜鸟教程 (www.runoob.com) 提供了编程的基础技术…

js短路表达式

今天碰见个题目&#xff0c;感觉短路表达式很好用。 题目&#xff1a; 定义一个计算圆面积的函数area_of_circle()&#xff0c;它有两个参数&#xff1a;r: 表示圆的半径&#xff1b;pi: 表示π的值&#xff0c;如果不传&#xff0c;则默认3.14function area_of_circle(r, pi) …

51nod 1065 最小正字段和 解决办法:set存前缀和,二分插入和二分查找

题目&#xff1a; 这题要求大于0的最小字段和&#xff0c;常规O&#xff08;n&#xff09;求最大字段和的方法肯定是没法解的。 我的解法是&#xff1a;用sum[i]存前i项的和&#xff0c;也就是前缀和。 这题就变成了求sum[j]-sum[i]的大于0的最小值( j > i )。 我们可以看到…

著名作者网站论文下载

http://www.cs.wright.edu/~agoshtas/ardyCV.htmlhttp://www.cse.msu.edu/~stockman/http://www.dkfz.de/tbi/people/homepages/rohr/转载于:https://www.cnblogs.com/stoneresearch/archive/2008/11/06/4336753.html

内存与进程管理

这一节的内容有点杂&#xff0c;只能自己手动输入了 1.uname命令用于打印当前系统相关信息&#xff08;内核版本号、硬件架构、主机名称和操作系统类型等&#xff09;。 uname -a显示全部信息 2.cat /etc/redhat-release 查看当前系统版本 3.free -m / -g 查看内存使用状况&…

Python的闭包和装饰器

什么是闭包 python中函数名是一个特殊的变量&#xff0c;它可以作为另一个函数的返回值&#xff0c;而闭包就是一个函数返回另一个函数后&#xff0c;其内部的局部变量还被另一个函数引用。 闭包的作用就是让一个变量能够常驻内存。 def count():fs []for i in range(1, 4):de…

用@Data注解的形式替代类中的setter、getter方法

目录 1. 封装 2. Data注解介绍 3. Lombok的使用 1. 封装 在类中&#xff0c;为了增强数据的安全性和隐蔽性&#xff0c;通常会对数据和与数据有关的方法进行封装&#xff1b; 封装的步骤&#xff1a; 1、将类中的属性设置为private(私有的)&#xff0c;只能本类才能访问&…

note-在VisualStudio中使用正则表达式

前言&#xff1a;本来昨天已经写了&#xff0c;但由于意外给搞丢失了&#xff0c;由于刚刚看了这篇文章知道了一些真相&#xff1b;现在的心理状态已经和昨天不一样了&#xff0c;昨天是满心的高兴&#xff0c;对VisualSduio很有好感&#xff0c;当时自认为是没有把正则学好&am…

AS 发展小计

2000 -- 2003: ActionScript 1.0, 和 Flash 5.0 一起发布&#xff1b;变成可文本编辑&#xff08;以前是从对话框和下拉菜单中选择&#xff0c;当然&#xff0c;那个时候不叫AS&#xff09;添加 switch 语句和strict equality 操作&#xff1b;2003 -- 2006: ActionScript 2.0 …

2019年3月8日比赛(知网是什么)

第一题&#xff08;对冒泡排序原理的理解&#xff09; 题意&#xff1a;第一行的输入代表下一行输入的无序数的数的个数&#xff0c;然后下一行&#xff0c;数字与上一行数字对应&#xff0c;若对应为1则该数可以与下一个数交换位置。 根据冒泡排序可知&#xff0c;任何一个无序…

Mybatis 中$与#的区别

1 #是将传入的值当做字符串的形式&#xff0c;eg:select id,name,age from student where id #{id},当前端把id值1&#xff0c;传入到后台的时候&#xff0c;就相当于 select id,name,age from student where id 1. 2 $是将传入的数据直接显示生成sql语句&#xff0c;eg:select…

UUID.randomUUID()生成唯一识别码

目录 1、UUID 的概念 2、UUID的组成 3、UUID.randomUUID()使用 1、UUID 的概念 UUID&#xff08;Universally Unique Identifier&#xff09;&#xff1a;通用唯一识别码&#xff0c;是一种软件建构的标准。 UUID 目的是让分布式系统中的所有元素&#xff0c;都能有唯一的…

人生应该记住的16句话(转载)

1、再烦&#xff0c;也别忘微笑&#xff1b;再急&#xff0c;也要注意语气&#xff1b; 再苦&#xff0c;也别忘坚持&#xff1b;再累&#xff0c;也要爱自己。 2、 低调做人&#xff0c;你会一次比一次稳健&#xff1b;高调做事&#xff0c;你会一次比一次优秀。 3、 成功的时…

转:一个简单的基于WEB的QTP自动化测试框架-SAFFRON

来源: http://www.itestware.com/ctest/index.php?optioncom_content&viewarticle&id62:webqtp-saffron&catid35:testing_is_believing 06年的时候&#xff0c;Mercury 提供了一个QTP自动化测试框架原型 - SAFFRON&#xff0c;可用于指导我们开发基于WEB的自动化测…

积极学习的朋友

自从去年7月反省之后&#xff0c;认识的朋友逐渐多了&#xff0c;天下那么大&#xff0c;优秀的人很多&#xff0c;通过网络认识是一个很不错的途径&#xff0c;经过一段时间后&#xff0c;圈子范围扩大了很多&#xff0c;行业上和非行业上都有涉及&#xff0c;对自己认知冲击很…

hive向表格中插入数据并分析语句

1&#xff0c;---导入mds_imei_month_info set hive.exec.max.dynamic.partitions 100000; //最大的动态分区表 set hive.support.concurrencyfalse; //是否支持并发 set hive.exec.max.dynamic.partitions.pernode 100000; //each mapper or reducer可以创建的最大动态分区数 …

资源与工具下载

Red Hat Linux镜像文件 链接&#xff1a;https://pan.baidu.com/s/1N3Khh6pyKpMkOnkEL-U9_A 提取码&#xff1a;0hnu jdk1.8(32位64位)安装版 链接&#xff1a;https://pan.baidu.com/s/15Jm6Ca6IBR3OEauge-4FYQ 提取码&#xff1a;uo2l Tomcat 8(32位64位)安装版 链接…

Global.asax中Application_Error无法执行

Global.asax中Application_Error无法执行问题解决后才发现这句是错误的&#xff0c;之前用VS2005开发后发布到服务器上也出现这种情况&#xff0c;后来莫名 的好了(是解决了没发现原因)。之前的文章链接后来用catch捕捉后真相大白&#xff0c;System.Security.SecurityExceptio…

虚拟化如何做实?详解戴尔2.0版解决方案

继5月份推出虚拟化解决方案后&#xff0c;2008年9月16日&#xff0c;戴尔又宣布推出包括新款服务器、存储产品&#xff0c;管理工具及基础设施咨询服务在内的全新虚拟化2.0解决方案&#xff0c;致力于为客户提供通向虚拟化的智慧之道。戴尔的虚拟化解决方案包括哪些具体的内容&…

Socket/ServerSocket 选项

Socket/ServerSocket 选项 原文:Socket/ServerSocket 选项在网络编程中&#xff0c;Socket/ServerSocket有一些选项用来自定义一些行为&#xff0c;现在分享一下。Socket选项 1.TCP_NODELAY 在Socket发送数据时&#xff0c;默认情况下&#xff0c;数据会先进入缓冲区&#xff0…

MySQL主从复制的常用拓扑结构

1、复制的常用拓扑结构 复制的体系结构有以下一些基本原则&#xff1a; (1) 每个slave只能有一个master&#xff1b; (2) 每个slave只能有一个唯一的服务器ID&#xff1b; (3) 每个master可以有很多slave&#xff1b; (4) 如果你设置log_slave_updates&#xff0c;…

统计java文件中的代码行数

统计Java代码行数工具类 —— CodeCounterUtil.java 统计指定目录下的java文件中代码行数 —— public static int getCodeNumFromFolder(String filePath)统计具体文件中的java代码行数 —— public static int getCodeNumFromFile(String filePath)import java.io.Buf…

jQuery插件thickbox在ie下垂直居中问题

jQuery 插件 thickbox 3.1 在ie下总不能垂直居中&#xff0c;按“http://jamazon.co.uk/web/2008/03/17/thickbox-31-ie7-positioning-bug/”上的方法改了也没用&#xff0c;咋办&#xff1f; 我是这样改的&#xff1a;管它ie6还是ie789&#xff0c;一视同仁&#xff01; 原284…

dos分区:C语言建立多个PRI DOS分区

dos分区:C语言建立多个PRI DOS分区 来源: 发布时间:星期四, 2008年9月25日 浏览:127次 评论:0一、引言 在DOS系统下&#xff0c;在计算机应用培训中因培训要求不同&#xff0c; 对软件的要求也不同&#xff0c;由于学员的误操作&#xff0c;存放在硬盘上的软件和重要数据容 易被…

简单几步让CentOS系统时间同步

在使用CentOS系统的时候&#xff0c;我们可能会遇到时间不准的问题&#xff0c;那我们如何解决这个我问题呢&#xff0c;下面就来教大家一个CentOS系统时间同步的方法&#xff0c;希望大家可以解决自己所存在的疑问。 CentOS系统时间同步的步骤如下&#xff1a; 新装的CentOS系…