一、反射机制

1、什么是反射?指的是程序在运行的过程中可以“动态”获取对象的信息

  首先要知道python是开源的,强类型的,动态的解释型语言。

# 动态语言和静态语言的区别
# x = 18 # 执行到x的时候才发现是什么类型
# 静态语言:就是在程序运行前就已经定义好类型了

  python是动态语言,而反射(reflection)机制被视为动态语言的关键。

  反射机制:指的是在程序的运行状态中

      对于任意一个类,都可以知道这个类的所有属性和方法;

      对于任意一个对象,都能够调用他的任意方法和属性。

      这种动态获取程序信息以及动态调用对象的功能称为反射机制。

  在python中实现反射非常简单,在程序运行过程中,如果我们获取一个不知道存有何种属性的对象,若想操作其内部属性,可以先通过内置函数dir来获取任意一个类或者对象的属性列表,列表中全为字符串格式

 2、为什么要用反射?

# def func(obj):
# if 'x' not in obj.__dict__:
# return
# obj.x
# # func(10) # 10.x # AttributeError: 'int' object has no attribute 'x'
# func()

3、如何实现反射?

class People:
def __init__(self,name,age):
self.name = name
self.age = age
def say(self):
print('<%s:%s>'%(self.name,self.age))

obj = People('lsj',18)

# 实现反射机制的步骤
# 1、查看某一个对象下可以点(.)出有哪些属性
# print(dir(obj))
"""
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name', 'say']
"""
# print(dir(obj)[-2]) # 获取属性名称:name

# 2、可以通过字符串反射到真正的属性上,得到属性值
# obj.'name'
# print(obj.__dict__['name']) # 获取属性值 lsj
# print(obj.__dict__[dir(obj)[-2]]) # 获取属性值 lsj

 4、内置函数的使用

# 四个内置函数的使用:通过字符串操作属性值(对象名,'对象属性')
# 1、hasattr() # 判断对象是否存在。类似于if判断
# print(hasattr(obj,'name')) # True 有则返回True,没有则返回False
# print(hasattr(obj,'name1')) # False 有则返回True,没有则返回False

# 2、getattr() # 获取属性,存在则返回对应的值。不存在则报错。
# print(getattr(obj,'name')) # lsj
# print(getattr(obj,'name1')) # AttributeError: 'People' object has no attribute 'name1'

# 3、setattr() # 赋值属性
# setattr(obj,'name','lsj1') # 赋值操作,将原来的名字给成lsj1,注意:都是对字符串操作。
# print(obj.name) # lsj1

# 4、delattr() # 删除属性
# delattr(obj,'name') # def obj.name
# 查看所有的属性
# print(obj.__dict__) # {'age': 18}

# 使用以上的四个内置函数(类名,'类的属性')
# 使用以上的四个内置函数(对象名,'函数')
res = getattr(obj,'say')
print(res) # 相当于People.say <bound method People.say of <__main__.People object at 0x00000247C52446A0>>
# 使用以上的四个内置函数(函数名,'函数')
# print(getattr(People,'say')) # 相当于obj.say <function People.say at 0x000001E4642E1550>

5、反射实例

obj = 10
# setattr(obj,'x',11111) # obj.x = 11111 -->10.x = 11111
# AttributeError: 'int' object has no attribute 'x'
# 为避免设置时出现的错误,先使用hasattr判断有没有x的属性再去设置操作

# 创建一个程序:支持上传和下载功能
class Ftp:
def put(self):
print('正在执行上传功能!!!')
def get(self):
print('正在执行下载功能!!!')
def interactive(self):
print('用户交互功能!!')
method = input('>>>:').strip() # method = 'put'
# self.method 注意self调用的是属性,而上面给的是字符串,所以这里用到反射概念
if hasattr(self,method):
getattr(self,method)()
else:
print('输入的指令不存在!!')

obj = Ftp()
obj.interactive()

 

二、内置方法

1、什么是内置方法?
定义在类内部,以__开头并以__结尾的方法
特点:会在某种情况下自动触发执行

2、为什么要用内置方法?
为了定制化我们的类or对象
# print('abd'.__len__())  # 3
# print(len('abd')) # 3
# print('abc') # 'abc'.__str__()
3、如何使用内置方法
__str__
__del__
obj1 = int(10)  # 内置数据类型为打印好看一些,专门做了一些定制化的操作
print(obj1) # 打印的结果是10
# 内置方法之一:__str__
class People:
def __init__(self,name,age):
self.name = name
self.age = age
def say(self):
print('<%s:%s>'%(self.name,self.age))

obj = People('lsj',18)
print(obj) # <__main__.People object at 0x000001907C8C7700>
# 如果我想要显示出的结果是['lsj',18]
# __str__:在打印对象时自动触发,然后将返回值(这里的返回值必须时字符串类型)当作本次打印的结果输出
class People:
def __init__(self,name,age):
self.name = name
self.age = age
def say(self):
print('<%s:%s>'%(self.name,self.age))
def __str__(self):
print("运行了")
return '<%s:%s>'%(self.name,self.age)

obj = People('lsj',18)
# print(obj) # <__main__.People object at 0x000001907C8C7700>
# # 如果我想要显示出的结果是['lsj',18]

# obj.__str__()
print(obj) # 运行了,TypeError: __str__ returned non-string (type NoneType)
# print(obj.__str__()) # 与上面相同
# 运行了
# hahaha
# 内置方法之二:__del__
# __del__:在清理对象时触发,会先执行该方法,
# 也就是说对象本身占用的是应该用程序的内存空间,但是该对象所具有的属性可能占用系统的内存空间,这时就要用到__del__
class People:
def __init__(self,name,age):
self.name = name
self.age = age
# self.x = 占用系统内存空间
self.x = open('a.txt',mode='w') # 占用系统内存空间
def __del__(self): # 在对象被删除之前该怎么做
# print('run...')
# 发起系统调用,告诉操作系统回收相关的系统资源
self.x.close()
obj = People('lsj',18) # obj对象只占用应用程序的内存空间
# obj.x # 但是对象的属性占用的是操作系统的内存空间
# del obj # obj.__del__() 但是平时不会这么做,系统会自动执行该操作。
print('='*50,'>') # 程序运行到这里就结束了,释放内存空间清理对象。