一、issubclass/type/isinstance(***)
1、issubclass(参数1, 参数2):检查第一个参数是否是第二个参数的 子子孙孙类,如下示例:
class Base(object): pass class Foo(Base): pass class Bar(Foo): pass print(issubclass(Bar, Foo)) # True print(issubclass(Bar, Base)) # True
2、type():获取当前对象时由哪个类创建,如下示例:
# #####示例一:判断一个参数是不是某一个指定类的对象 class Foo(object): pass obj = Foo() print(obj,type(obj)) # <__main__.Foo object at 0x0000000002618F60> <class '__main__.Foo'> if type(obj) == Foo: # 判断一个参数是不是某一个指定类的对象 print('obj是Foo类型') # #####示例二:练习题:判断函数的参数分别是哪个类的对象 class Foo(object): pass class Bar(object): pass def func(*args): foo_counter = 0 bar_counter = 0 for item in args: if type(item) == Foo: foo_counter += 1 elif type(item) == Bar: bar_counter += 1 return foo_counter, bar_counter print(func(Foo(), Bar(), Foo())) # (2, 1)
# 补充:示例三:如何判断参数是不是一个类 class Foo(object): pass obj = Foo() print(type(Foo) == type) # True print(type(obj) == type) # False
3、isinstance(参数1, 参数2):检查第一个参数是否是第二个参数的实例,如下示例:
# #####示例一:判断一个参数是不是某一个指定类或其父类的对象 class Base: pass class Foo(Base): pass class Bar(Foo): pass obj1 = Bar() print(isinstance(obj1, Bar)) # True print(isinstance(obj1, Foo)) # True print(isinstance(obj1, Base)) # True obj2 = Foo() print(isinstance(obj2, Bar)) # False
二、用科学的方式判断是函数和方法(*)
一般我们笼统的称定义在类中的函数为方法,定义在类外的就是函数,其实是不太严谨的,如下示例:
# #####示例一:如何看得出是函数还是方法 def func(): pass class Foo(object): def inner(self): pass @staticmethod def detail(): pass print(func) # <function func at 0x00000000028C99D8> 是函数 obj = Foo() print(obj.inner) # 是方法 # <bound method Foo.inner of <__main__.Foo object at 0x00000000028D1208>> print(Foo.detail) # <function Foo.detail at 0x00000000028F9AE8> 是函数 print(obj.detail) # <function Foo.detail at 0x00000000028F9AE8> 是函数
其实,在python中,一切皆对象,只要是对象,它就有对应的类,函数是FunctionType创建的,方法是由MethodType创建的,所以,我们可以按照如下示例判断是函数还是方法:
# #####示例二 from types import MethodType,FunctionType def check(arg): """ 检查arg是方法还是函数? """ if isinstance(arg,MethodType): print('arg是一个方法') elif isinstance(arg,FunctionType): print('arg是一个函数') else: print('不知道是什么') check(func) # arg是一个函数 check(obj.inner) # arg是一个方法
# #####示例三:是不是方法跟写在哪里没关系,跟调用有关系 class Foo(object): def f1(self): pass obj = Foo() obj.f1() # 把f1当做方法,python自动传self值 print(obj.f1) # <bound method Foo.f1 of <__main__.Foo object at 0x0000000002724390>> obj = Foo() Foo.f1(obj) # 把f1当做函数,需要自己传参数 print(Foo.f1) # <function Foo.f1 at 0x0000000002791AE8>
# #####示例四:练习题 class Foo(object): def f1(self): pass def f2(self): pass def f3(self): pass list_display = [f1,f2] def __init__(self): pass for item in Foo.list_display: print(item) item(123) # item是函数,所以要自己传参数 # 结果为: # <function Foo.f1 at 0x00000000029A3B70> # <function Foo.f2 at 0x00000000029A3BF8>
# #####示例五 class Foo(object): def f1(self): pass def f2(self): pass def f3(self): pass list_display = [f1,f2] obj = Foo() Foo.list_display.append(obj.f3) for item in Foo.list_display: print(item) # 结果为: # <function Foo.f1 at 0x0000000002973D90> # <function Foo.f2 at 0x0000000002973E18> # <bound method Foo.f3 of <__main__.Foo object at 0x0000000002908A90>>
总结:执行那个类里边的 .什么功能 的时候,如果是 对象.功能,那么这个功能就是方法。
对象.xxx --- > xxx就是方法
类.xxx --- > xxx就是函数
三、反射(*****)
重点:v = getattr(obj , “func”) # 根据字符串为参数(第二个参数),去对象(第一个参数)中寻找与之同名的成员。
应用一、首先定义一个handler模块,handler.py文件内容如下:
f0 = 9 def f1(): print('F1') def f2(): print('F2') def f3(): print('F3') def f4(): print('F4') def f5(): print('F5')
现有个需求,用户输入模块中的函数名,则执行该函数,你可能会按照如下方式写代码:
""" import handler val = input("请输入要执行的函数:") if val == 'f1': handler.f1() elif val == 'f2': handler.f2() elif val == 'f3': handler.f3() elif val == 'f4': handler.f4() elif val == 'f5': handler.f5() """
学习了反射,我们可以这样写,如下示例:
from types import FunctionType import handler while True: print(""" 系统支持的函数有: 1. f1 2. f2 3. f3 4. f4 5. f5 """) val = input("请输入要执行的函数:") if hasattr(handler, val): # 假如 val = "f1" func_or_val = getattr(handler, val) # 根据字符串为参数,去模块中寻找与之同名的成员。 if isinstance(func_or_val, FunctionType): func_or_val() # 是函数则执行 else: print(func_or_val) # 不是函数则打印出来 else: print('handler中不存在输入的属性名')
应用二、用户登录、注销、注册程序:
class Account(object): func_list = ['login', 'logout', 'register'] def login(self): """ 登录 """ print('登录111') def logout(self): """ 注销 """ print('注销111') def register(self): """ 注册 """ print('注册111') def run(self): """ 主代码 """ print(""" 请输入要执行的功能: 1. 登录 2. 注销 3. 注册 """) choice = int(input('请输入要执行的序号:')) func_name = Account.func_list[choice-1] func = getattr(self, func_name) # self.login func() obj1 = Account() obj1.run()
反射补充:还是以引入handler模块为例:
import handler # hasattr v1 = hasattr(handler,'f0') v2 = hasattr(handler,'f1') v3 = hasattr(handler,'f2') v4 = hasattr(handler,'xxx') print(v1,v2,v3,v4) # True True True False # setattr setattr(handler,'x2',999) v5 = getattr(handler,'x2') print(v5) # 999 setattr(handler,'f8',lambda x:x+1) v6 = getattr(handler,'f8') v7 = v6(1) print(v7) # 2 # delattr delattr(handler,'f0') # v8 = getattr(handler,'f0') # print(v8) # AttributeError: module 'handler' has no attribute 'f0'
总结:
getattr # 根据字符串的形式,去对象中找成员;
hasattr # 根据字符串的形式,去判断对象中是否有成员;
setattr # 根据字符串的形式,动态的设置一个成员(内存);
delattr # 根据字符串的形式,动态的删除一个成员(内存);
四、补充知识点(callable)
你见过的什么后面可以加括号?
- 类() - 对象()
- 函数() - 方法()
以上所有都可以被调用。如何验证呢?如下示例:
def func(): pass class Foo(object): def __call__(self, *args, **kwargs): pass def func(self): pass obj = Foo() print(callable(func)) # True print(callable(Foo)) # True print(callable(obj)) # True print(callable(obj.func)) # True
五、特殊成员补充
# print(对象),会自动执行__str__方法 class Foo(object): def __init__(self): pass def func(self): pass def __str__(self): return "F1" # 必须返回字符串 obj = Foo() print(obj,type(obj)) # F1 <class '__main__.Foo'>
# __doc__ class Foo(object): """ 这里是注释 """ def __init__(self): pass def func(self): pass def __str__(self): return "F1" obj = Foo() print(obj.__doc__) # 这里是注释
# __dict__ class Foo(object): def __init__(self, name, age): self.name = name self.age = age def func(self): pass obj1 = Foo('刘博文', 99) obj2 = Foo('史雷', 89) print(obj1.__dict__) # {'name': '刘博文', 'age': 99} print(obj2.__dict__) # {'name': '史雷', 'age': 89}
# __iter__ class Foo(object): def __init__(self,name,age): self.name = name self.age = age def __iter__(self): return iter([11,22,33]) # 生成器 # yield 11 # yield 22 # yield 33 """ 如果想要把不可迭代对象 -> 可迭代对象 1. 在类中定义__iter__方法 2. iter内部返回一个迭代器(生成器也是一种特殊迭代器) """ obj1 = Foo('刘博文',99) for item in obj1: print(item) # 结果为: # 11 # 22 # 33