一、面向对象那个进阶之反射
定义:所谓反射就是可以通过字符串来操作Python代码中的变量、函数、甚至类和方法。
在反射中有四种自省方法,这四种方法适合类和对象(在Python中一切皆对象),下面是四种方法的说明:
hasattr 判断某一个 变量 是否能够.调用一个名字,返回True或者False
getattr 直接获取一个变量中的名字的值
setattr 为一个变量增加或者修改一个属性
delattr 删除一个变量中的属性或者方法
反射方法使用说明:
反射类中的名字
getattr(类名,'静态属性')
getattr(类名,'类方法')()
getattr(类名,'静态方法')()
# class A:
# name = 'Fang'
# age = 18
# print(getattr(A,'name')) # getattr获取类中的静态属性名字
反射对象中的名字
getattr(对象名,'对象属性')
getattr(对象名,'方法名')()
#!/usr/bin/python
# -*- encodeing:utf-8 -*-
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
def show(self):
for key in self.__dict__:
print(key,self.__dict__[key])
fang = Student('Fang',25)
if hasattr(fang,'name'): #使用hasattr 判断对象属性能否被调用
print(getattr(fang,'name')) #使用getattr获取对象的属性
if hasattr(fang,'show'): # 使用hasattr 判断对象方法能否被调用
getattr(fang,'show')() # 使用getattr获取对象的方法
setattr(fang,'sex','女') # 使用setattr添加一个对象属性
getattr(fang,'show')()
delattr(fang,'age') #使用delattr 删除一个对象的属性
getattr(fang,'show')()
反射模块中的名字
import 模块名
getattr(模块名,'模块中的变量')
getattr(模块名,'模块中的函数')()
getattr(模块名,'模块中的类名')
反射当前模块中的名字
import sys
getattr(sys.modules[__name__],'变量')
getattr(sys.modules[__name__],'函数')()
getattr(sys.modules[__name__],'类名')
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import sys
def s1():
print 's1'
def s2():
print 's2'
this_module = sys.modules[__name__]
hasattr(this_module, 's1')
getattr(this_module, 's2')
二、双下划线方法
__str__和__repr__
_repr__和__str__这两个方法都是用于显示的,__str__是面向用户的,而__repr__面向程序员。
打印操作会首先尝试__str__和str内置函数(print运行的内部等价形式),它通常应该返回一个友好的显示
__repr__用于所有其他的环境中:用于交互模式下提示回应以及repr函数,如果没有使用__str__,会使用print和str。它通常应该返回一个编码字符串,可以用来重新创建对象,或者给开发者详细的显示。
当我们想所有环境下都统一显示的话,可以重构__repr__方法;当我们想在不同环境下支持不同的显示,例如终端用户显示使用__str__,而程序员在开发期间则使用底层的__repr__来显示,实际上__str__只是覆盖了__repr__以得到更友好的用户显示。
#!/usr/bin/python
# -*- encodeing:utf-8 -*-
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self): #添加上__str__时打印类对象就会显示下面的文字
return '打印类对象时执行我'
def __repr__(self): #__repr__属于str的备胎当这个类中没有str这个方法时 程序会直接调用repr这个方法
return '打印类对象时没有str时执行我'
fang = Student('Fang',25)
print(fang) #直接打印fang这个类对象,给我们显示的是一个内存地址,看着不是很友好
__del__、__new__、__call__、__hash__
__del__ 是析构方法。再删除一个对象的时候调用,如果在删除对象的时候,内部存在__del__方法,那么在删除一个对象之前先执行__del__方法中的代码。
__new__是创建一个对象,在类中先执行new方法,创造出一个对象,然后在把创造出来的对象传递给__init__方法。
__call__为了将一个类实例当做函数调用,我们需要在类中实现__call__()
方法
__hash__哈希函数的结果就是__hash__方法的返回值,它在一次成的执行过程中哈希值不会发生变化,并且要想作为字典的key或者作为集合的元素,这个对象对应的类必须实现__hash__方法。
#!/usr/bin/python
# -*- encodeing:utf-8 -*-
#del方法
# class A:
# def __init__(self,name,age):
# self.name = name
# self.age = age
# def __del__(self):
# print('删除时调用我')
# a = A('Fang',25)
# print(a)
# del a
# print(a)
#new 方法
# class A:
# def __init__(self):
# print('执行init方法')
# def __new__(cls):
# print('执行new方法')
# return object.__new__(cls)
# a = A()
# print(type(a))
# print(type(A))
# 先执行__new__方法 创造出一个对象
# 然后把创造出来的对象传递给__init__方法
# 会把self自动的返回,被a接收
class A:
def __call__(self):
print('执行call了')
A()()
三、item系列
item系列给出了三种方法,__getitem__、__setitem__、__delitem__,用于索引操作,如字典。以上分别表示获取、设置、删除数据
class A:
def __init__(self,name):
self.name = name
self.age = 81
def __getitem__(self, item):
return self.__dict__[item]
def __setitem__(self, key, value):
self.__dict__[key] = value
def __delitem__(self, key):
del self.__dict__[key]
a = A('alex')
# print(a['name']) # 对应了类中一个方法的语法
# a.name
# print(a['age']) # 对应了类中一个方法的语法
# a.age
# 增加 和 修改一个属性
a['sex'] = '不详'
# a.sex = '不详'
print(a.__dict__)
# print(a.sex)
# print(a['sex'])
a['sex'] = '女'
print(a.__dict__)
del a['sex']
print(a.__dict__)