一.isinstance,type,issubclass
issubclass() 这个内置函数可以帮我们判断x类是否是y类的子类
issubclass(x,y)
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(obj)表示查看obj是由哪个类创建的
class Foo: pass obj = Foo() print(obj, type(obj)) # 查看obj的类 <class '__main__.Foo'>
可以帮我们判断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)
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家族体系中的(只能往上判断)
二.区分函数和方法
我们之前讲过函数和方法. 这两样东西如何进行区分呢? 其实很简单. 我们只需要打印一
下就能看到区别的.
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. 实例方法, 如果是实例访问. 就是方法. 如果是类名访问就是函数.
三.反射
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)
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