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
View Code
  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("失败")


 

原文地址:https://www.cnblogs.com/alvin-jie/p/9936225.html