python之路-day18-反射
一、昨日内容回顾
类与类之间的关系
1、依赖关系。通过参数的传递把另外的一个类的对象传递进来
2、关联关系,组合,聚合。 通过属性设置来维护两个对象的关系
def __init__():
self.stuList = []
def __init__():
self.teacher = teacher
3、关于继承
self : 谁调用的,self就是谁
4、特殊成员
__init__() 初使化方法
__new__() 构造方法
__call__() 对象()
__add__() +
__getitem__ 对象[]
__setitem__ 对象[] = 值
__delitem__ del 对象[]
__del__ del 对象 析构函数
__len__ len(对象)
__iter__ for. iter()
__next__ next()
__dir__ dir()
__getslice__ 对象[::]
__hash__ hash()
__class__
__dict__ 查看当前对象的属性
二、isinstance , type , issubclass
1、 issubclass :这个内置函数可以帮我们判断xxx类是否是 yyy类型的子类
class Base:
pass
class Foo(Base):
pass
class Bar(Foo):
pass
print(issubclass(Bar, Foo)) # True
print(issubclass(Bar, Base)) # False
print(issubclass(Foo, Bar)) # True
2、type: type(obj) 表示obj是由哪个类创建的 ---- 用法一
class Foo:
pass
obj = Foo()
# 查看对象 obj由哪个类创建
print(obj , type(obj)) # <__main__.Foo object at 0x0000029B31A17080> <class '__main__.Foo'>
type还可以帮我们判断 xxx 是否是 xxx 数据类型的 ---- 用法二
class Boy:
pass
class Girl:
pass
# 统计传进来的男女生数量分别是多少
def func(*args):
b, g = 0, 0
for obj in args:
if type(obj) == Boy:
b += 1
elif type(obj) == Girl:
g += 1
return b , g
ret = func(Boy(),Girl(),Girl(),Girl(),Girl(),Boy(),Boy(),Boy(),Boy())
print(ret) # (5, 4)
在进行计算时,先判断好要计算的数据类型必须是 int 或者 float ----用法三
def add(a, b):
if (type(a) == int or type(a) == float) and (type(b) == int or type(b) == float):
return a + b
else:
print("我要报错")
3、isinstance 它也可以判断xxx是yyy类型的数据,但是 instance没有type那么精准
class Base:
pass
class Foo(Base):
pass
class Bar(Foo):
pass
print(isinstance(Foo(), Foo)) # True
print(isinstance(Foo(), Base)) # True
print(isinstance(Bar(), Base)) # True
print(isinstance(Foo(), Bar)) # False
isinstance 可以判断该对象是否是xxx家族体系中的(只能网上判断)
三、区分函数的方法
1、一般情况下 直接打印一下,就能区分是函数还是方法(特殊情况下不准确)
def func():
pass
print(func) # <function func at 0x000002C283502E18>
class Foo:
def chi(self):
print("我是吃")
f = Foo()
print(f.chi) # <bound method Foo.chi of <__main__.Foo object at 0x0000021DD6227320>>
函数在打印的时候,很明显的显示的是function, 而方法在打印的时候很明显是method
其实,并不一定是这样的。如:
class Foo():
def chi(self):
print("我是吃")
@staticmethod
def static_method():
pass
@classmethod
def class_method(cls):
pass
f = Foo()
print(f.chi) # <bound method Foo.chi of <__main__.Foo object at 0x00000284EC6E7320>>
print(Foo.chi) # <function Foo.chi at 0x000001C8CC0288C8>
print(Foo.static_method) #<function Foo.static_method at 0x0000028079048950>
print(Foo.class_method) # <bound method Foo.class_method of <class '__main__.Foo'>>
print(f.static_method) # <function Foo.static_method at 0x00000272AF6E8950>
print(f.class_method) # bound method Foo.class_method of <class '__main__.Foo'>>
仔细观察,我们能得到以下结论:
1)、类方法,不论任何情况,都是方法
2)、静态方法,不论何种情况,都是函数
3)、实例方法,如果是实例方法,则是方法;如果是类访问,则是函数
2、在程序里如何分辨是函数函还是方法呢?
所有的方法都MethodType的实例
所有的函数都是FunctionType的实例
from types import MethodType,FunctionType
def func():
pass
print(isinstance(func, FunctionType)) # True
print(isinstance(func, MethodType)) # False
class Foo:
def chi(self):
print("我要吃")
@staticmethod
def static_method():
pass
@classmethod
def class_method(cls):
pass
obj = Foo()
print(type(obj.chi)) # method
print(type(Foo.chi)) # function
print(isinstance(obj.chi, MethodType)) # True
print(isinstance(Foo.chi, FunctionType)) # True
print(isinstance(Foo.static_method, FunctionType)) # True
print(isinstance(Foo.static_method, MethodType)) # False
print(isinstance(Foo.class_method, FunctionType)) # False
print(isinstance(Foo.class_method, MethodType)) # True
四、反射
首先我们来看一个这样的需求,有个大牛,写了一堆特别牛逼的代码,然后放在了py文件里(模块)
这时,想要用大牛写的东西,但是,首先得直到大牛写的这些代码都是干什么用的。那就需要把每个函数
跑一下。
DN.py
def chi():
print("大牛特别能吃")
def he():
print("大牛特别能喝")
def la():
print("大牛一次啦三斤")
def sa():
print("大牛一次撒几吨")
接下来错误的示例:这样的写法非常的low,假如有100个函数,这个代码就非常恐怖
import DN
while 1:
print("""作为大牛,我帮你写了:
chi
he
la
sa
等功能,自己看看吧""")
func = input("输入你想要测试的功能:")
if func == "he":
DN.chi()
elif func == "chi":
DN.chi()
。。。
。。。
正确的打开姿势:
import DN
while 1:
print("""作为⼤⽜, 我帮你写了:
chi
he
la
shui
等功能. ⾃⼰看看吧""")
gn = input("请输⼊你要测试的功能:")
# niuB版
func = getattr(DN, gn)
func()
getattr(对象,字符串):从对象中获取到xxx功能。此时xxx是一个字符串。get表示找 attr表示
属性(功能)。但是这里有个问题,假如手一抖,输入错了,在大牛的代码里没有找到想要的内容,那么
这个时候就会报错。所以在getattr之前,要先判断有没有
import DN
from types import FunctionType
while 1:
print("""作为⼤⽜, 我帮你写了:
chi
he
la
shui
等功能. ⾃⼰看看吧""")
gn = input("请输⼊你要测试的功能:")
# niuB版
if hasattr(DN, gn): # 如果master⾥⾯有你要的功能
# 获取这个功能, 并执⾏
attr = getattr(DN, gn)
# 判断是否是函数. 只有函数才可以被调⽤
if isinstance(attr, FunctionType):
attr()
else:
# 如果不是函数, 就打印
print(attr)
总结:getattr可以从模块中获取内容,在python中一切皆为对象。那可以这样认为。getattr()
从对象中动态的获取内容
补充:
关于反射,其实一共有4个函数:
1、hasattr(obj, str) 判断obj中是否包含str成员
2、getattr(obj, str) 从obj中获取 str成员
3、setattr(obj,str,value) 把obj中的str成员设置成value。注意,这里的value
可以是值,也可以是函数或者方法
4、defattr(obj, str) 把obj中的str成员删掉
注意:以上的操作都是在内存中进行的,并不会影响源代码
class Foo:
pass
f = Foo()
print(hasattr(f, "chi")) # False
setattr(f, "chi", "123")
print(f.chi) # 被添加了⼀个属性信息
setattr(f, "chi", lambda x: x + 1)
print(f.chi(3)) # 4
print(f.chi) # 此时的chi既不是静态⽅法, 也不是实例⽅法, 更不是类⽅法. 就相当于你在类中
# 写了个self.chi = lambda 是⼀样的
print(f.__dict__) # {'chi': <function <lambda> at 0x107f28e18>}
delattr(f, "chi")
print(hasattr(f, "chi")) # False
五、MD5 加密
1、md5特点:不可逆的一种加密方式,最多用在密码加密上
2、实例:
import hashlib
# 创建md5的对象
obj = hashlib.md5()
# 给obj设置明文
obj.update("alex".encode("utf-8")) # update传入多的内容需为byte类型
# 获取密文
result = obj.hexdigest() # haxdigest hax是16进制,digest是摘要
print(result) # 534b44a19bf18d20b71ecc4eb77c572f
3、以上为粗略的md5小试,此方法产生的密文容易被撞库破解,下面的是改进版
import hashlib
SALT = b"alex" # 加盐 此方法可有效的防止被撞库
obj = hashlib.md5(SALT)
obj.update("alex".encode("utf-8"))
result = obj.hexdigest()
print(result) # 0bf4375c81978b29d0f546a1e9cd6412
# # md5 的整理使用
def md5_method(content):
obj = hashlib.md5(SALT)
obj.update(content.encode("utf-8"))
return obj.hexdigest()
# 4、 MD5的应用
# 注册 # alex 123 ---》 b75bd008d5fecb1f50cf026532e8ae67
username = input("用户名:")
password = input("密码:")
password = md5_method(password)
# 登录
uname = input("用户名:")
pwd = input("密码:")
if md5_method(pwd) == password and uname == username:
print("登录成功")
else:
print("失败")