关于反射,之前没时间更新

Posted guchenxu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于反射,之前没时间更新相关的知识,希望对你有一定的参考价值。

本节主要内容:
  1. isinstance, type, issubclass
  2. 区分函数和?法
  3. 反射(重点)

一、isinstance,type,issubclass

  首先,我们先看issubclass()这个内置函数可以帮我们判断xxx类是否是yyy类型的子类。

class Base:
     pass
class Foo(Base):
     pass
class Bar(Foo):
     pass

print(issubclass(Bar, Foo)) # True
print(issubclass(Foo, Bar)) # False
print(issubclass(Bar, Base)) # True

  然后我们来看看type,type在前面已经使用过了。type(obj)表示查看obj是由哪个类创建的。

class Foo:
     pass
obj = Foo()
print(obj, type(obj)) # 查看obj的类

  那这个鬼东西有什么用呢?可以帮我们判断xxx是否是xxx数据类型的

class Boy:
     pass
class Girl:
     pass

# 统计传进来的男?和??分别有多少
def func(*args):
     b = 0
     g = 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(), Boy(), Boy(), Girl())
print(ret)

  或者,你在进行计算的时候。先判断好要计算的数据类型必须是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("我要报错")

  isinstance也可以判断xxx是yyy类型的数据. 但是isinstance没有type那么精准. 

class Base:
     pass
class Foo(Base):
     pass
class Bar(Foo):
     pass

print(isinstance(Foo(), Foo)) # True
print(isinstance(Foo(), Base)) # True
print(isinstance(Foo(), Bar)) # False

  isinstance可以判断该对象是否是xxx家族体系中的(只能往上判断)

二、区分函数和方法

  我们之前讲过函数和?法. 这两样东?如何进?区分呢? 其实很简单. 我们只需要打印?
下就能看到区别的.

def func():
     pass
print(func) # <function func at 0x10646ee18>
class Foo:
    def chi(self):
         print("我是吃")
f = Foo()
print(f.chi) # <bound method Foo.chi of <__main__.Foo object at0x10f688550>>

  函数在打印的时候. 很明显显?的是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
0x10f688550>>
print(Foo.chi) # <function Foo.chi at 0x10e24a488>
print(Foo.static_method) # <function Foo.static_method at 0x10b5fe620>
print(Foo.class_method) # bound method Foo.class_method of <class
‘__main__.Foo‘>>
print(f.static_method) # <function Foo.static_method at 0x10e1c0620>
print(f.class_method) #<bound method Foo.class_method of <class
‘__main__.Foo‘>>

仔细观察, 我们能得到以下结论:
  1. 类?法. 不论任何情况, 都是?法.
  2. 静态?法, 不论任何情况. 都是函数
  3. 实例?法, 如果是实例访问. 就是?法. 如果是类名访问就是函数.

 

那如何?程序来帮我们分辨. 到底是?法还是函数呢? ?先, 我们要借助于types模块. 

# 所有的?法都是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

  ?types中的FunctionType和MethodType可以区分, 当前内容是?法还是函数, 接下来.
看?个?题, 并分析答案

from types import FunctionType, MethodType
class Foo:
     @classmethod
     def func1(cls):
         pass
     @staticmethod
     def func2():
         pass
     def func3(self):
         pass
     def func4(self):
        pass
lst = [Foo.func1, Foo.func2, Foo.func3]
obj = Foo()
lst.append(obj.func4)
for item in lst:
     print(isinstance(item, MethodType))
     print(isinstance(item, FunctionType))

  练习. 写?个函数. 判断传递进来的内容是函数还是?法

三、反射

  ?先, 我们看这样?个需求, 说, 有个??, 写了?堆特别?B的代码. 然后放在了?个py
?件?(模块), 这时, 你想?这个??写的东?. 但是呢. 你?先得知道??写的这些代码都是
?什么?的. 那就需要你把??写的每?个函数跑?下. 摘?摘??想?的内容. 来咱们模拟
这样的需求, ?先, ??给出?个模块.

 

大牛.py

def chi():
     print("???顿吃100个螃蟹")
 
def he():
     print("???顿喝100瓶可乐")
 
def la():
     print("??不?拉")
 
def shui():
     print("???次睡?年")

  接下来,到你了。你要去一个一个的调用。但是,在调用之前。大牛告诉你了,他写了哪些功能,那现在就可以这么办了:

import master
while 1:
     print("""作为??, 我帮你写了:
         chi
         he
         la
         shui
        等功能. ??看看吧""")
     gn = input("请输?你要测试的功能:")
         if gn == ‘chi‘:
             master.chi()
         elif gn == "he":
             master.he()
         elif gn == "la":
             master.la()
         elif gn == "shui":
             master.shui()
         else:
             print("??就这?个功能. 别搞事情")

  

  写是写完了. 但是.....如果??现在写了100个功能呢? 你的判断要判断100次么? 太累
了吧. 现有的知识解决不了这个问题. 那怎么办呢? 注意看. 我们可以使?反射来完成这样的
功能. 非常的简单. 想想. 这?我们是不是让?户输入要执?的功能了. 那这个功能就是对应
模块?的功能. 那也就是说. 如果能通过字符串来动态访问模块中的功能就能解决这个问题.
好了. 我要告诉你

  反射解决的就是这个问题. 为什么叫反射? 反着来啊. 正常是我们先引入
模块, 然后?模块去访问模块?的内容. 现在反了. 我们?动输入要运?的功能. 反着去模块
?找. 这个就叫反射。

import master
while 1:
     print("""作为??, 我帮你写了:
         chi
         he
         la
         shui
        等功能. ??看看吧""")
     gn = input("请输?你要测试的功能:")
     # niuB版
     func = getattr(master, gn)
     func()

  getattr(对象, 字符串): 从对象中获取到xxx功能. 此时xxx是?个字符串. get表?找, attr
表?属性(功能). 但是这?有个问题. ?户如果??抖, 输入错了. 在??的代码?没有你要找
的内容. 那这个时候就会报错. 所以. 我们在获取attr之前. 要先判断?下. 有没有这个attr.
  完整代码:

import master
from types import FunctionType
while 1:
     print("""作为??, 我帮你写了:
         chi
         he
         la
         shui
        等功能. ??看看吧""")
     gn = input("请输?你要测试的功能:")
     # niuB版
     if hasattr(master, gn): # 如果master??有你要的功能
         # 获取这个功能, 并执
        attr = getattr(master, gn)
         # 判断是否是函数. 只有函数才可以被调?
         if isinstance(attr, FunctionType):
             attr()
         else:
             # 如果不是函数, 就打印
             print(attr)

  好了, 这?我们讲到了两个函数. ?个是getattr(). ?个是hasattr(). 其中getattr()?来获
取信息. hasattr()?来判断xxx中是否包含了xxx功能, 那么我们可以在模块中这样来使?反射.
在?向对象中?样可以这样进?操作. 这个就比较?B了. 后期你学习的相关框架内部核?源
码?乎都是这些东?. ?先, 我们先看?些简单的.

class Person:
     country = "?清"
     def chi(self):
         pass
# 类中的内容可以这样动态的进?获取
print(getattr(Person, "country")) 
print(getattr(Person, "chi")) # 相当于Foo.func 函数

# 对象?样可以
obj = Person()
print(getattr(obj, "country"))
print(getattr(obj, "chi")) # 相当于obj.func ?法

  总结, getattr可以从模块中获取内容, 也可以从类中获取内容, 也可以从对象中获取内
容. 在python中?切皆为对象. 那可以这样认为. getattr从对象中动态的获取成员
  来看?个?例.

class Person:
     def chi(self):
         print("吃")
     def he(self):
         print("喝")
     def la(self):
         print("拉")
     def sa(self):
         print("撒")
     def shui(self):
         print("睡")
    def run(self):
         lst = [‘chi‘, ‘he‘, ‘la‘, ‘sa‘, ‘shui‘]
         num = int(input("""本系统有以下功能
                1. 吃
                2. 喝
                3. 拉
                4. 撒
                5. 睡    
请选择你要执?的功能:"""))

     # 通过类名也可以使?
     # func = getattr(Person, lst[num - 1])
     # func(self)

     # 通过对象来访问更加合理
     # method = getattr(self, lst[num-1])
     # method()
p = Person()
p.run()

  

  

补充:
  关于反射, 其实?共有4个函数:
    1. hasattr(obj, str) 判断obj中是否包含str成员
    2. getattr(obj,str) 从obj中获取str成员
    3. setattr(obj, str, value) 把obj中的str成员设置成value. 注意. 这?的value可以是
     值, 也可以是函数或者?法
    4. delattr(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

  

 

































以上是关于关于反射,之前没时间更新的主要内容,如果未能解决你的问题,请参考以下文章

java 反射代码片段

getitemcount() 值在片段重新启动之前不会更新

回归 | js实用代码片段的封装与总结(持续更新中...)

光照 漫反射光照

光照 漫反射光照

光照 漫反射光照