博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
06 面向对象之:反射, 双下方法
阅读量:5879 次
发布时间:2019-06-19

本文共 10455 字,大约阅读时间需要 34 分钟。

一. 反射

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

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

四个可以实现自省的函数

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

class Foo:    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__)对实例化对象的示例
对对象的反射
class Foo(object):     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')
对类的反射
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.py    index.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)  # 
class A: def func(self): pass print(A.func) #
obj = A()print(obj.func) #
>
View Code

2.2 通过types模块验证

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

2.3 静态方法是函数

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

2.4 函数与方法的区别

那么,函数和方法除了上述的不同之处,我们还总结了一下几点区别。

(1)函数的是显式传递数据的。如我们要指明为len()函数传递一些要处理数据。

(2)函数则跟对象无关。

(3)方法中的数据则是隐式传递的。

(4)方法可以操作类内部的数据。

(5)方法跟对象是关联的。如我们在用strip()方法是,是不是都是要通过str对象调用,比如我们有字符串s,然后s.strip()这样调用。是的,strip()方法属于str对象。

我们或许在日常中会口语化称呼函数和方法时不严谨,但是我们心中要知道二者之间的区别。

在其他语言中,如Java中只有方法,C中只有函数,C++么,则取决于是否在类中。

三. 双下方法

定义:双下方法是特殊方法,他是解释器提供的 由爽下划线加方法名加双下划线 __方法名__的具有特殊意义的方法,双下方法主要是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 = 1        self.b = 2    def __len__(self):        return len(self.__dict__)a = A()print(len(a))
View Code

3.02 __hash__

class A:    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))
View Code

3.03 __str__

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

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

3.04 __repr__

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

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

3.05 __call__

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

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

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

3.06 __eq__

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

3.07 __del__

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

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

3.08__new__

class A:    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)
View Code
class A:    __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__系列

class Foo:    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']=18f1['age1']=19del f1.age1del 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 = 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)
有他们可以这样操作
class Diycontextor:    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
自定义文件管理器

 相关面试题:

class StarkConfig:    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:    passclass Department:    passclass 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] = vsite = AdminSite()site.register(UserInfo, StarkConfig)# 1 # obj = site._registry[UserInfo]()# 2obj = site._registry[UserInfo](100)obj.run()-------class UserInfo:    passclass Department:    passclass 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_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/jin-xin/articles/10325036.html

你可能感兴趣的文章
发展大数据不能抛弃“小数据”
查看>>
25000个布满恶意软件的摄像头组成的僵尸网络
查看>>
FB全球开放360度直播功能 首先需要一个FB账号
查看>>
量子通信成信息安全领域发展重点 潜在市场望达1000亿元
查看>>
数据中心新的自动化运维技术
查看>>
OpenFlow下一步该怎么走?
查看>>
CoreOS为容器安全带来不同方法
查看>>
用EXCEL导入QC需求和测试用例详解
查看>>
中了WannaCry病毒的电脑几乎都是Win 7
查看>>
iOS开发月报#2|201808
查看>>
SMSSDK进化之路
查看>>
【干货来袭】使用 Python 扩展 UiBot 的功能
查看>>
node之搭建一个http完整的静态服务器(命令行工具)
查看>>
阿里云IPv6 DDoS防御被工信部认定为“网络安全技术应用试点示范项目
查看>>
史上最快Docker入门实战! (二) - Docker环境的搭建方法
查看>>
【思维导图】PHP基础
查看>>
小程序使用之自定义组件
查看>>
Java springcloud B2B2C o2o多用户商城 springcloud架构(四):熔断器Hystrix
查看>>
spring cloud微服务分布式云架构-服务消费者Feign
查看>>
Lua Windows环境搭建以及配置netbeans IDE Glider插件For Lua
查看>>