面向对象:反射、内置方法

反射:通过字符串映射到对象或者类的属性

反射的方法:

class People:
    country = "China"

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def talk(self):
        print("%s is talking" % self.name)

obj = People("neo",22)

"""
判断是否拥有某个属性: hasattr(o,name)  # name是字符串格式
"""
print(hasattr(obj,"name"))
print(hasattr(obj,"talk"))

print(hasattr(People,"country"))
print(hasattr(People,"talk"))
# 运行结果:
# True
# True
# True
# True

"""
得到某个属性的值: getattr(o,name,default)   # default处写上“None”,那么即使没有这个name程序也不会报错
"""
print(getattr(obj,"name",None))
print(getattr(obj,"talk",None))
print(getattr(obj,"gender",None))

print(getattr(People,"country",None))
print(getattr(People,"talk",None))
# 运行结果:
# neo
# <bound method People.talk of <__main__.People object at 0x00000035DB166668>>
# None
# China
# <function People.talk at 0x000000878224BA60>

"""
添加、修改某个属性: setattr(object,"name",value)
"""
setattr(obj,"gender","male")
setattr(obj,"name","NEO")
print(obj.gender)
print(obj.name)

setattr(People,"nation","Han")
print(People.__dict__)
print(getattr(People,"nation",None))
print(People.nation)
# 运行结果:
# male
# NEO
# {'__module__': '__main__', 'country': 'China', '__init__': <function People.__init__ at 0x00000018D460B9D8>, 'talk': <function People.talk at 0x00000018D460BA60>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None, 'nation': 'Han'}
# Han
# Han


"""
删除某个属性: delattr(o,name)
"""
delattr(obj,"age")
print(obj.__dict__)

delattr(People,"country")
print(People.__dict__)
# 运行结果:
# {'name': 'NEO', 'gender': 'male'}
# {'__module__': '__main__', '__init__': <function People.__init__ at 0x0000002C1C9BB9D8>, 'talk': <function People.talk at 0x0000002C1C9BBA60>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None, 'nation': 'Han'}

反射的使用:

"""接收用户输入,触发相应的功能"""
class Service:
    def run(self):
        while True:
            # 输入的是格式化的内容,如: get a.txt 或者 upload a.txt
            cmd = input(">>>").strip().split() # cmd = ["get","a.txt"]

            if hasattr(self,cmd[0]):
                func = getattr(self,cmd[0])
                func(cmd)

    def get(self,cmd):
        print("get .......%s" %cmd[1])

    def upload(self,cmd):
        print("upload ......%s" %cmd[1])

obj = Service()
obj.run()

 

内置方法:

一、isinstance(obj,cls)和 issubclass(sub,super)

  isinstance(obj,cls) # 检查对象obj是否为 类 cls的对象  # 返回Bool值

  issubclass(sub,super)  # 检测sub类是否为 super类的派生类(子类) # 返回Bool值

二、item系列: __getitem__(self, item)、__setitem__(self, key, value)、__delitem__(self, key)

"""通过item系列能够把对象当做字典去处理"""
class People:

    def __init__(self,name):
        self.name = name

    def __getitem__(self, item):
        print("get item test [%s]" %item)
        return self.__dict__.get(item)

    def __setitem__(self, key, value):
        print("set item test" )
        self.__dict__[key] = value

    def __delitem__(self, key):
        print("del item test")
        self.__dict__.pop(key)
        # del self.__dict__[key]  # 这种方式也可以

"""下面讨论这3中item在何种情况下被触发"""

p = People("neo")

p["age"]  # 对象["name"] 能够触发 __getitem__(self,item)  # 跟__getitem__(self,item) 函数体的具体代码无关
# 运行结果:
# get item test [age]

p["gender"] = "male"  # 对象["key"] = "value" 能够触发 __setitem__(self,key,value)  # 同样, 与其函数体的具体代码无关
print(p.__dict__)
# 运行结果:
# set item test
# {'name': 'neo', 'gender': 'male'}

del p["name"]   # del 对象["name"] 能够触发 __delitem__(self,key)  # 与其函数体的具体代码无关
# 运行结果:
# del item test

 

三、 __str__(self) 方法:使打印对象的输出结果格式化

"""
__str__(self)方法:将print(object)的打印结果由对象的内存地址格式化成你需要的字符串形式,从而增加了打印结果的可读性
print(object)触发__str__(self),
"""
class People:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __str__(self):
        print("=====>>>")
        return "aaa"   # __str__只能返回字符串格式
        # return "<name:%s> <age:%s>"%(self.name,self.age)   # 可以自己定义打印结果的格式

p = People("neo",18)
print(p)   # 打印对象能够触发__str__(self)
# 运行结果:
# =====>>>
# aaa

 

四、__del__ 方法

补充知识:

# 以open(file)为例

f = open("setting.py")  # python没有能力自己打开硬盘文件,打开文件的动作需要操作系统去完成,所以 open其实是个命令:告诉操作系统让它打开a.txt这个文件;这个赋值过程涉及两方面的资源:变量f 是应用程序的资源,open("setting.py"):打开硬盘文件是操作系统的资源 
f.read()  # read()也是一个命令,是让操作系统读取文件内容 # read()需要在文件关闭之前进行

"""
资源不能一直被占用;python只能回收它自己应用程序的资源(例如python程序结束后资源都会被回收),但python没有能力回收操作系统的资源,所以在python程序结束前一定要关闭掉文件
"""
f.close()  # close()也是一个对操作系统发出的命令,让操作系统关闭掉硬盘上的文件,并把操作系统里面相应的资源回收;注意:python程序结束前一点要关闭掉文件,这一点不要忘

"""
虽然硬盘文件已经关闭掉,但f  还能够打印,因为f 是应用程序的资源;但文件关闭后就不能再read了
"""
print(f)
# 打印结果:
# <_io.TextIOWrapper name='setting.py' mode='r' encoding='cp936'>

 __del__(self) 的作用: 让操作系统回收掉自己的资源

触发情况:1. del f  # del file(file是个对象,如上面示例中的f)能够自动调用类内部的 __del__(self) (先触发__del__再删除f这个对象)

        2. 如果没有del f,那么在程序结束的之前会自动调用__del__(self)(或者说在程序运行到最后已经没有其他代码要执行了) (也是python先触发__del__,再删除python自己的f)

 总结: 在类内部定义的内置方法都是绑定给对象的;而且在某种情况下会自动被触发调用

 附: 其他内置方法可参考链接: http://www.cnblogs.com/linhaifeng/articles/6204014.html

 

posted @ 2018-03-03 11:19  neozheng  阅读(171)  评论(0编辑  收藏  举报