Python面向对象之反射,双下方法
一. 反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
f = '类的静态变量'
def __init__(self,name,age):
self.name=name
self.age=age
def 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__)
对实例化对象的示例
staticField = "old boy"
def __init__(self):
self.name = 'wupeiqi'
def func(self):
return 'func'
@staticmethod
def bar():
return 'bar'
print getattr(Foo, 'staticField')
print getattr(Foo, 'func')
print getattr(Foo, 'bar')
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.py
index.py
当前文件:
index.py
"""
# 另一个模块中的代码
import module_test as obj
#obj.test()
print(hasattr(obj,'test'))
getattr(obj,'test')()
其他模块的示例
反射的应用:
了解了反射的四个函数。那么反射到底有什么用呢?它的应用场景是什么呢?
现在让我们打开浏览器,访问一个网站,你单击登录就跳转到登录界面,你单击注册就跳转到注册界面,等等,其实你单击的其实是一个个的链接,每一个链接都会有一个函数或者方法来处理。
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()
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 通过打印函数(方法)名确定
pass
print(func) # <function func at 0x00000260A2E690D0>
class A:
def func(self):
pass
print(A.func) # <function A.func at 0x0000026E65AE9C80>
obj = A()
print(obj.func) # <bound method A.func of <__main__.A object at 0x00000230BAD4C9E8>>
2.2 通过types模块验证
from types import MethodType
def func():
pass
class A:
def func(self):
pass
obj = A()
print(isinstance(func,FunctionType)) # True
print(isinstance(A.func,FunctionType)) # True
print(isinstance(obj.func,FunctionType)) # False
print(isinstance(obj.func,MethodType)) # True
2.3 静态方法是函数
from types import MethodType
class A:
def func(self):
pass
@classmethod
def func1(self):
pass
@staticmethod
def func2(self):
pass
obj = A()
# 静态方法其实是函数
# print(isinstance(A.func2,FunctionType)) # True
# print(isinstance(obj.func2,FunctionType)) # True
2.4 函数与方法的区别
那么,函数和方法除了上述的不同之处,我们还总结了一下几点区别。
(1)函数的是显式传递数据的。如我们要指明为len()函数传递一些要处理数据。
(2)函数则跟对象无关。
(3)方法中的数据则是隐式传递的。
(4)方法可以操作类内部的数据。
(5)方法跟对象是关联的。如我们在用strip()方法是,是不是都是要通过str对象调用,比如我们有字符串s,然后s.strip()这样调用。是的,strip()方法属于str对象。
我们或许在日常中会口语化称呼函数和方法时不严谨,但是我们心中要知道二者之间的区别。
在其他语言中,如Java中只有方法,C中只有函数,C++么,则取决于是否在类中。
三. 双下方法
定义:双下方法是特殊方法,他是解释器提供的 由爽下划线加方法名加双下划线 __方法名__的具有特殊意义的方法,双下方法主要是python源码程序员使用的,我们在开发中尽量不要使用双下方法,但是深入研究双下方法,更有益于我们阅读源码。
调用:不同的双下方法有不同的触发方式,就好比盗墓时触发的机关一样,不知不觉就触发了双下方法,例如:__init__
3.01 __len__
def __len__(self):
print(666)
b = B()
len(b) # len 一个对象就会触发 __len__方法。
class A:
def __init__(self):
self.a = 1
self.b = 2
def __len__(self):
return len(self.__dict__)
a = A()
print(len(a))
3.02 __hash__
def __init__(self):
self.a = 1
self.b = 2
def __hash__(self):
return hash(str(self.a)+str(self.b))
a = A()
print(hash(a))
3.03 __str__
如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
def __init__(self):
pass
def __str__(self):
return '太白'
a = A()
print(a)
print('%s' % a)
3.04 __repr__
如果一个类中定义了__repr__方法,那么在repr(对象) 时,默认输出该方法的返回值。
def __init__(self):
pass
def __repr__(self):
return '太白'
a = A()
print(repr(a))
print('%r'%a)
3.05 __call__
对象后面加括号,触发执行。
注:构造方法__new__的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__
3.06 __eq__
def __init__(self):
self.a = 1
self.b = 2
def __eq__(self,obj):
if self.a == obj.a and self.b == obj.b:
return True
a = A()
b = A()
print(a == b)
3.07 __del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
3.08__new__
def __init__(self):
self.x = 1
print('in init function')
def __new__(cls, *args, **kwargs):
print('in new function')
return object.__new__(A, *args, **kwargs)
a = A()
print(a.x)
__instance = None
def __new__(cls, *args, **kwargs):
if cls.__instance is None:
obj = object.__new__(cls)
cls.__instance = obj
return cls.__instance #单例模式
【采用单例模式动机、原因】
对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。
【单例模式优缺点】
【优点】
一、实例控制
单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
二、灵活性
因为类控制了实例化过程,所以类可以灵活更改实例化过程。
【缺点】
一、开销
虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
二、可能的开发混淆
使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
三、对象生存期
不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用
单例模式具体分析
3.09 __item__系列
def __init__(self,name):
self.name=name
def __getitem__(self, item):
print(self.__dict__[item])
def __setitem__(self, key, value):
self.__dict__[key]=value
def __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__)
3.10 上下文管理器相关
__enter__ __exit__
class A:
def __init__(self, text):
self.text = text
with A('大爷') as f1:
print(f1.text)
def __init__(self, text):
self.text = text
def __enter__(self): # 开启上下文管理器对象时触发此方法
self.text = self.text + '您来啦'
return self # 将实例化的对象返回f1
def __exit__(self, exc_type, exc_val, exc_tb): # 执行完上下文管理器对象f1时触发此方法
self.text = self.text + '这就走啦'
with A('大爷') as f1:
print(f1.text)
print(f1.text)
def __init__(self,name,mode):
self.name = name
self.mode = mode
def __enter__(self):
print "Hi enter here!!"
self.filehander = open(self.name,self.mode)
return self.filehander
def __exit__(self,*para):
print "Hi exit here"
self.filehander.close()
with Diycontextor('py_ana.py','r') as f:
for i in f:
print i
相关面试题:
def __init__(self,num):
self.num = num
def 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:
pass
class Department:
pass
class StarkConfig:
def __init__(self, num):
self.num = num
def 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
site = AdminSite()
site.register(UserInfo, StarkConfig)
# 1
# obj = site._registry[UserInfo]()
# 2
obj = site._registry[UserInfo](100)
obj.run()
-------
class UserInfo:
pass
class Department:
pass
class StarkConfig:
def __init__(self,num):
self.num = num
def 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_display
s1 = 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_display
s1 = A()
print(s1.get_list())
------
class A:
list_display = []
def get_list(self):
self.list_display.insert(0,33)
return self.list_display
class B(A):
list_display = [11,22]
s1 = A()
s2 = B()
print(s1.get_list())
print(s2.get_list())
Python面向对象之反射,双下方法的更多相关文章
- 百万年薪python之路 -- 面向对象之 反射,双下方法
面向对象之 反射,双下方法 1. 反射 计算机科学领域主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省) python面向对象中的反射:通过字符串的形式操作对象相关的属性.python ...
- python之面向对象函数与方法,反射,双下方法
一.函数和方法 1.函数和方法的区别 函数: 全都是显性传参,手动传参,与对象无关 方法: 存在隐性传参,与对象有关 1.1通过函数名可以判断 len()就是函数 str.count()就是方法 de ...
- Python 面向对象(四) 反射及其魔术方法
反射 reflection 也有人称之为自省 作用: 运行时获取.添加对象的类型定义信息,包括类 内建方法: getattr(object, name[, default]) 返回object对象 ...
- Python面向对象06 /元类type、反射、函数与类的区别、特殊的双下方法
Python面向对象06 /元类type.反射.函数与类的区别.特殊的双下方法 目录 Python面向对象06 /元类type.反射.函数与类的区别.特殊的双下方法 1. 元类type 2. 反射 3 ...
- python 面向对象专题(六):元类type、反射、函数与类的区别、特殊的双下方法
目录 Python面向对象06 /元类type.反射.函数与类的区别.特殊的双下方法 1. 元类type 2. 反射 3. 函数与类的区别 4. 特殊的双下方法 1. 元类type type:获取对象 ...
- Python进阶----反射(四个方法),函数vs方法(模块types 与 instance()方法校验 ),双下方法的研究
Python进阶----反射(四个方法),函数vs方法(模块types 与 instance()方法校验 ),双下方法的研究 一丶反射 什么是反射: 反射的概念是由Smith在1982年首次提出的 ...
- Python反射和内置方法(双下方法)
Python反射和内置方法(双下方法) 一.反射 什么是反射 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省).这一概念的提出很快引发 ...
- Python面向对象 | 双下方法
定义:双下方法是特殊方法,他是解释器提供的.由双下划线+方法名+双下划线 .它具有特殊意义的方法,双下方法主要是python源码程序员使用的,我们在开发中尽量不要使用双下方法,但是深入研究双下方法,更 ...
- day27:反射和双下方法
1, # 面向对象的三大特性:继承,多态和封装 # 继承: # 单继承: **** # 父类(超类,基类) # 子类(派生类) 派生方法和派生属性 # 子类的对象在调用方法和属性:先用自己的,自己没有 ...
随机推荐
- 方差分析|残差|MSA/MSE|Completely randomized design|Randomized block design|LSD|主效应|intercept|多重比较|
符合方差分析的三个条件: 残差=实际值-预测值(其实是均值). 在原假设下,MSA的期望会等于MSE的期望:在备选假设下,MSA的期望会大于MSE的期望,所以MSA/MSE的取值范围在(1,正无穷), ...
- OpenCV 对两幅图像求和(求混合(blending))
#include <cv.h> #include <highgui.h> #include <iostream> using namespace cv; int m ...
- VisionPro 图标工具说明
- Trailing Zeroes (III) LightOJ - 1138 二分+找规律
Time Limit: 2 second(s) Memory Limit: 32 MB You task is to find minimal natural number N, so that N! ...
- SpringMVC学习笔记四:SimpleMappingExceptionResolver异常处理
SpringMVC的异常处理,SimpleMappingExceptionResolver只能简单的处理异常 当发生异常的时候,根据发生的异常类型跳转到指定的页面来显示异常信息 ExceptionCo ...
- Android开发之《Module相互引用,NDK不能正常Debug》
解决Android Studio不能进入调试模式问题 Android Studio 2.2.3 native debug 无法调试?:https://www.zhihu.com/question/54 ...
- PyCharm 介绍、安装、入门使用
一.Pycharm介绍 前面几年的时间,我一直用的eclipse,后面开始听同事说用IntelliJ IDEA了,而且说是目前业界最好用的java开发工具,IDE(集成开发环境),没有之一.PyCha ...
- 携程酒店DevOps测试实践
作者简介 王幸福,携程酒店研发部高级测试经理,负责无线自动化测试相关工作.在测试框架和平台研发.移动测试.DevOps等领域有着丰富的经验. 如今很多大型互联网公司.创新型企业都在积极地进行DevOp ...
- loadrunner通过odbc测mysql数据库语句
#include "lrd.h" Action() { double trans_time; //定义一个double型变量用来保存事务执行时间 static LRD_INIT_ ...
- Hello World!(这不是第一篇)
如题,这不是第一篇blog,但是为了表示这个闲置了1年多的blog现在被我正式启用了,我还是走个过场吧. #include <iostream> using namespace std; ...