什么是反射?
用字符串数据类型的变量名来访问这个变量的值
反射的方法:getattr,hasattr,setattr,delattr
类:(通过类名反射类名空间里面的内容的)
类:静态属性,类方法,静态方法
命名空间.xxx = gettattr(命名空间,“xxx”)
引子
class Student:
def __init__(self): pass
def cheak_course(self):
print("cheak_course")
def choose_course(self):
print("choose_course")
def choosed_course(self):
print("查看已选的课程")
stu = Student()
num = input(">>>>")
if num == "cheak_course":
stu.cheak_course()
elif num == "choose_course":
stu.choose_course()
elif num == "choosed_course":
stu.choosed_course()
如果类的方法越多,下面的判断就越多,代码太冗余。可以使用反射
怎么通过用户输入的字符串拿到对应的值?
class Student:
ROLE = "STUDENT" # 静态属性
@classmethod
def cheak_course(cls): # 类方法
print("查看课程")
@staticmethod
def login(): # 静态方法
print("登录")
# 反射查看属性
print(Student.ROLE)
# 用户输入input进来的永远是字符串"ROLE",那么怎么从Student里面拿到ROLE呢
# eval 这个东西,要明确的写在代码里面的,不能用户输入什么就eval()什么,太不安全
print(getattr(Student, "ROLE")) # 第一个参数的命名空间中的,变量名为第二个参数的值。前面是命名空间,后面是变量名,字符串
# 反射调用方法
getattr(Student, "cheak_course")()
# 反射调用静态方法
getattr(Student, "login")()
# 结果
# STUDENT
# STUDENT
# 查看课程
# 登录
接收用户的输入的字符串
class Student:
ROLE = "STUDENT" # 静态属性
@classmethod
def cheak_course(cls): # 类方法
print("查看课程")
@staticmethod
def login(): # 静态方法
print("登录")
num = input("请输入要操作的动作:")
getattr(Student, num)() #加括号就调用
这样就保证程序的绝对安全了,有这个方法就直接执行,没有的话就报错
如果要做的好一点,可以用hasattr,有这个方法的话就返回True,没有的话就返回False
class Student:
ROLE = "STUDENT" # 静态属性
@classmethod
def cheak_course(cls): # 类方法
print("查看课程")
@staticmethod
def login(): # 静态方法
print("登录")
num = input("请输入要操作的动作:")
if hasattr(Student, num): # 输入的字符串在Student里面找到就返回True,找不到就返回False
getattr(Student, num)()
对象
反射方法,对象属性
class A():
age = 100 # 静态属性
def __init__(self, name):
self.name = name # 属性
def func(self):
print("in func")
a = A("Alex") # 实例化
# 正常是访问属性
print(a.name)
# 通过反射取属性,方法
print(getattr(a, "name"))
getattr(a, "func")()
# 结果
# Alex
# Alex
# in func
模块
反射和直接调用效果是一样的
print(os.rename) # 获取函数的内存地址
print(getattr(os, "rename"))
# 结果
# <built-in function rename>
# <built-in function rename>
反射别的模块中的内容
import os
os.rename("__init__.py", "init")
# getattr(os, "rename") 就相当于os.rename (没有括号)
getattr(os, "rename")('init', "__init__.py") # 后面括号是参数
# 将文件名改回来再改回去
反射自己模块中的内容,找到自己当前文件的命名空间
#因为现在只能拿到字符串类型的数据,不知道模块名。要反射的话必须要有反射名
def wahaha():
print("wahaha")
def qqxing():
print("qqixng")
import sys
# print(sys.modules) # sys.modules表示所有在这个python程序中导入的模块
# 找到自己当前文件的命名空间
# print(sys.modules["__main__"])
# 结果:
# <module '__main__' from 'D:/参考/daydayup/day20/反射.py'>
my_file = sys.modules["__main__"]
# my_file.wahaha()
getattr(my_file, "wahaha")()
#结果
#wahaha
总结:
反射
getattr,hasattr
类名.名字
getattr(对象,“名字”)
对象名.名字
getattr(对象,“名字”)
模块名.名字
import 模块
getattr(模块,“名字”)
自己文件.名字
import sys
getattr(sys.modules[“main”],“名字”)
反射演练
class Manager:
def __init__(self, name):
self.name = name
def create_student(self):
print("创建学生账号")
def create_course(self):
print("创建课程")
def ckeck_student_info(self):
print("查看学生信息")
class Student:
def __init__(self, name):
self.name = name
def cheak_course(self):
print("cheak_course")
def choose_course(self):
print("choose_course")
def choosed_course(self):
print("查看已选的课程")
def login():
username = input("user: ")
password = input("pwd: ")
with open("userinfo") as f:
for line in f:
user, pwd, ident = line.strip().split("|") # 解包,拿列表里面的每一个值。ident = "Manager\n",strip()去掉换行符
if user == username and pwd == password: # 判断输入法的用户名密码,是否和存的用户名密码对上
print("登录成功")
return username, ident # 返回用户名,身份,知道具体是谁
import sys
def main():
# 程序的逻辑在main里面
usr, id = login() # 拿到用户名和身份,身份就是Student或Manager,刚好和上面的类名一样
print("use,id", usr, id) # 返回的是两个字符串
file = sys.modules["__main__"] # 获取当前所在的模块,就是当前文件的命名空间
cls = getattr(file, id) # getattr(当前文件,Manager),从当前文件,找类Manager或Student的内存空间,id是从文件里拿的字符串,这样就能找到类名空间
obj = cls(usr) # 这个是实例化,拿到的就是对象
print(Student, Manager)
print(cls) # 就是Manager类的内存地址
main()
插播enumerate
l = ["a", "b", "c"]
for i in l:
print(i)
# 结果
# a
# b
# c
1
l = ["a", "b", "c"]
for i in enumerate(l):
print(i)
# 结果
# (0, 'a')
# (1, 'b')
# (2, 'c')
原地解包1
l = ["a", "b", "c"]
for num, i in enumerate(l): # 从0开始
print(num, i)
# 结果
# 0 a
# 1 b
# 2 c
原地解包2
l = ["a", "b", "c"]
for num, i in enumerate(l,1): # 从1开始
print(num, i)
#结果
# 1 a
# 2 b
# 3 c
主程序的逻辑不需要动,尽管添加学生和老师的方法就行。
class Manager:
OPERATE_LIST = [("创造学生账号", "create_student"),
("创建课程", "create_course"),
("查看学生信息", "ckeck_student_info")]
def __init__(self, name):
self.name = name
def create_student(self):
print("创建学生账号")
def create_course(self):
print("创建课程")
def ckeck_student_info(self):
print("查看学生信息")
class Student:
OPERATE_DIC = [
('查看所有课程', 'check_course'),
('选择课程', 'choose_course'),
('查看已选择的课程', 'choosed_course')
]
def __init__(self, name):
self.name = name
def cheak_course(self):
print("cheak_course")
def choose_course(self):
print("choose_course")
def choosed_course(self):
print("查看已选的课程")
def login():
username = input("user: ")
password = input("pwd: ")
with open("userinfo") as f:
for line in f:
user, pwd, ident = line.strip().split("|") # 解包,拿列表里面的每一个值。ident = "Manager\n",strip()去掉换行符
if user == username and pwd == password: # 判断输入法的用户名密码,是否和存的用户名密码对上
print("登录成功")
return username, ident # 返回用户名,身份,知道具体是谁
import sys
def main():
# 程序的逻辑在main里面
usr, id = login() # 拿到用户名和身份,身份就是Student或Manager,刚好和上面的类名一样
print("use,id", usr, id) # 返回的是两个字符串
file = sys.modules["__main__"] # 获取当前所在的模块,就是当前文件的命名空间
cls = getattr(file, id) # getattr(当前文件,Manager),从当前文件,找类Manager或Student的内存空间,id是从文件里拿的字符串,这样就能找到类名空间
obj = cls(usr) # 这个是实例化,拿到的就是对象
operate_list = cls.OPERATE_LIST # 通过类名拿静态变量
while True: # 循环起来
for num, i in enumerate(operate_list,
1): # 1 ('创造学生账号', 'create_student') 2 ('创建课程', 'create_course') 3 ('查看学生信息', 'ckeck_student_info')
print(num, i[0]) # 1 创造学生账号2 创建课程3 查看学生信息
choise = int(input("请输入要操作的序号:")) # 拿到用户要操作的序号,转成证书类型
choice_item = operate_list[choise - 1] # 需要从1开始的,是("创造学生账号", "create_student")这样的元组
getattr(obj, choice_item[1])() # choice_item[1]这个就是要找的字符串
main()
#结果:
# user: Alex
# pwd: 123456
# 登录成功
# use,id Alex Manager
# 1 创造学生账号
# 2 创建课程
# 3 查看学生信息
# 请输入要操作的序号:1
# 创建学生账号
# 1 创造学生账号
# 2 创建课程
# 3 查看学生信息
# 请输入要操作的序号:2
# 创建课程
# 1 创造学生账号
# 2 创建课程
# 3 查看学生信息
# 请输入要操作的序号:3
# 查看学生信息
# 1 创造学生账号
# 2 创建课程
# 3 查看学生信息
# 请输入要操作的序号:
setattr 修改(了解)
class A:
def __init__(self, name):
self.name = name
a = A("alex")
# a.name = "alex_SB" # 一般正常这样用
# getattr(a,"name") #取值
setattr(a, "name", "alex_SB") # 修改,最后一个是修改后的数据
print(a.name)
# 结果
# alex_SB
delatter删除(了解)
不用反射
class A:
def __init__(self, name):
self.name = name
a = A("alex")
print(a.__dict__)
del a.name
print(a.__dict__)
# 结果
# {'name': 'alex'}
# {}
用反射
class A:
def __init__(self, name):
self.name = name
a = A("alex")
print(a.__dict__)
delattr(a,"name")
print(a.__dict__)
# 结果
# {'name': 'alex'}
# {}