python中常见的双下方法_python进阶六——反射, 双下方法

1. 反射

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

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

四个可以实现自省的函数

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

classFoo:

f= '类的静态变量'def __init__(self,name,age):

self.name=name

self.age=age

def say_hi(self):

print('hi,%s'%self.name)

obj=Foo('huihuang',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__)

对实例化对象的示例

对对象的反射

classFoo:

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= "yan hui"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 sys

def 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_testasobj

#obj.test()

print(hasattr(obj,'test'))

getattr(obj,'test')()

其他模块的示例

其他模块的反射

反射的应用:

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

classUser:

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()

没学反射之前的解决方式

classUser:

def login(self):

print('欢迎来到登录页面')

def register(self):

print('欢迎来到注册页面')

def save(self):

print('欢迎来到存储页面')

user=User()while 1:

choose= input('>>>').strip()ifhasattr(user,choose):

func=getattr(user,choose)

func()else:

print('输入错误。。。。')

学了反射之后解决方式

2. 函数 vs 方法

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

def func():

pass

print(func) #

classA:

def func(self):

pass

print(A.func) #obj=A()

print(obj.func) #>

View Code

2.2 通过types模块验证

fromtypes import FunctionTypefromtypes import MethodType

def func():

passclassA:

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

View Code

2.3 静态方法是函数

fromtypes import FunctionTypefromtypes import MethodTypeclassA:

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

View Code

2.4 函数与方法的区别

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

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

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

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

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

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

3. 双下方法

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

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

3.1 __len__

classB:

def __len__(self):

print(666)

b=B()

len(b) # len 一个对象就会触发 __len__方法。classA:

def __init__(self):

self.a= 1self.b= 2def __len__(self):returnlen(self.__dict__)

a=A()

print(len(a))

View Code

3.2 __hash__

classA:

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.3 __str__

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

classA:

def __init__(self):

pass

def __str__(self):return '辉煌'a=A()

print(a)

print('%s' % a)

View Code

3.4 __repr__

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

classA:

def __init__(self):

pass

def __repr__(self):return '辉煌'a=A()

print(repr(a))

print('%r'%a)

View Code

3.5 __call__

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

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

classFoo:

def __init__(self):

pass

def __call__(self,*args, **kwargs):

print('__call__')

obj=Foo() # 执行 __init__

obj() # 执行 __call__

View Code

3.6 __eq__

classA:

def __init__(self):

self.a= 1self.b= 2def __eq__(self,obj):if self.a == obj.a and self.b ==obj.b:returnTrue

a=A()

b=A()

print(a== b)

View Code

3.7 __del__

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

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

3.8__new__

classA:

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

单例模式

单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。

【采用单例模式动机、原因】

对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。

如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。

【单例模式优缺点】

【优点】

一、实例控制

单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。

二、灵活性

因为类控制了实例化过程,所以类可以灵活更改实例化过程。

【缺点】

一、开销

虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。

二、可能的开发混淆

使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。

三、对象生存期

不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用

单例模式具体分析

单例模式具体分析

3.9 __item__系列

classFoo:

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.age1

del f1['age']

f1['name']='yan'print(f1.__dict__)

View Code

3.10 上下文管理器相关

__enter__  __exit__

# 如果想要对一个类的对象进行with as的操作 不行。classA:

def __init__(self, text):

self.text=text

with A('哈哈') asf1:

print(f1.text)

没他们不可以这样操作

classA:

def __init__(self, text):

self.text=text

def __enter__(self): # 开启上下文管理器对象时触发此方法

self.text= self.text + '您来啦'

returnself # 将实例化的对象返回f1

def __exit__(self, exc_type, exc_val, exc_tb): # 执行完上下文管理器对象f1时触发此方法

self.text= self.text + '这就走啦'with A('哈哈') asf1:

print(f1.text)

print(f1.text)

有他们可以这样操作

classDiycontextor:

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)returnself.filehander

def __exit__(self,*para):

print"Hi exit here"self.filehander.close()

with Diycontextor('py_ana.py','r') asf:for i inf:

print i

自定义文件管理器

示例:

classStarkConfig:

def __init__(self,num):

self.num=num

def run(self):

self()

def __call__(self,*args, **kwargs):

print(self.num)classRoleConfig(StarkConfig):

def __call__(self,*args, **kwargs):

print(345)

def __getitem__(self, item):returnself.num[item]

v1= RoleConfig('yan')

v2= StarkConfig('辉煌')

# print(v1[1])

# print(v2[2])

v1.run()-------

classUserInfo:

passclassDepartment:

passclassStarkConfig:

def __init__(self, num):

self.num=num

def changelist(self, request):

print(self.num, request)

def run(self):

self.changelist(999)classRoleConfig(StarkConfig):

def changelist(self, request):

print(666, self.num)classAdminSite:

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]()

#2obj= site._registry[UserInfo](100)

obj.run()-------

classUserInfo:

passclassDepartment:

passclassStarkConfig:

def __init__(self,num):

self.num=num

def changelist(self,request):

print(self.num,request)

def run(self):

self.changelist(999)classRoleConfig(StarkConfig):

def changelist(self,request):

print(666,self.num)classAdminSite:

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 insite._registry.items():

row.run()-------

classA:

list_display=[]

def get_list(self):

self.list_display.insert(0,33)returnself.list_display

s1=A()

print(s1.get_list())-------

classA:

list_display= [1, 2, 3]

def __init__(self):

self.list_display=[]

def get_list(self):

self.list_display.insert(0, 33)returnself.list_display

s1=A()

print(s1.get_list())------

classA:

list_display=[]

def get_list(self):

self.list_display.insert(0,33)returnself.list_displayclassB(A):

list_display= [11,22]

s1=A()

s2=B()

print(s1.get_list())

print(s2.get_list())

View Code

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值