主要内容:
- 1. isinstance, type, issubclass
- 2. 区分函数和方法
- 3. 反射(重点)
1. isinstance, type, issubclass
(1) issubclass(xxx,yyy) 这个内置函数可以帮我们判断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
(2) 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) # (3, 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): 判断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家族体系中的(只能往上判断)
2. 区分函数和方法
def func(): print("你猜猜看") print(func) #<function func at 0x000002819F1B6048>
在外边定义的函数一定是函数
class Foo: # 实例方法: 对象.方法 方法 类名.方法 函数 def func(self): print("这里是什么呢!") obj = Foo() print(obj.func) #<bound method Foo.func of <__main__.Foo object at 0x00000217422E7978>> Foo.func(obj) print(Foo.func) #<function Foo.func at 0x000002BCB0528A60>
class Foo: @staticmethod def static_method(): pass @classmethod # 都是方法 def class_method(cls): # 类对象的内容 pass @property # 神马都不是. 变量 def age(self): return 10 f = Foo() # print(f.static_method) #<function Foo.static_method at 0x000001ACF90D8A60> # print(Foo.static_method) #<function Foo.static_method at 0x0000012304688A60> # print(f.class_method) #<bound method Foo.class_method of <class '__main__.Foo'>> # print(Foo.class_method) #<bound method Foo.class_method of <class '__main__.Foo'>> print(f.age) #10 print (Foo.age) # <property object at 0x000002B3197FB7C8>
结论:
- 类方法. 不论任何情况, 都是方法.
- 静态方法, 不论任何情况. 都是函数
- 实例方法, 如果是实例访问. 就是方法. 如果是类名访问就是函数.
另外:用types中的FunctionType和MethodType可以区分, 当前内容是方法还是函数,
from types import MethodType,FunctionType class Foo: @classmethod def func1(self): pass @staticmethod def func2(self): pass def func3(self): pass def func4(self): pass lst = [func1, func2, func3] obj = Foo() Foo.lst.append(obj.func4) for item in Foo.lst: print(isinstance(item,MethodType)) # print(isinstance(item,FunctionType))
3.反射
一个需求, 说, 有个大牛, 写l一堆特别牛B的代码. 然后放在一个py文件里里(模块),这时, 你想用这个大牛写的东西,但是呢. 你首先得知道大牛写的这些代码都是干什么用的. 那就需要你把大牛写的每一个函数跑一下. 摘⼀摘自己想用的内容. 来咱们模拟 这样的需求,首先, 大牛给出一个模块.
def chi(): print ("大牛一次吃一桶") def he(): print ("大牛一顿喝100杯水") def la(): print ("大牛不用拉") def sleep(): print("大牛一睡睡一年") name = "大牛"
import master while 1 : print('''大牛写了很多东西 chi he la sleep ''') val = input("请输入你要测试的功能") if hasattr(master,val): attr = getattr(master,val) # 从xxx对象或者模块中找xxxxx(字符串) 功能, 变量 if callable(attr): #判断这个东西是否可以被调用 attr() else: print(attr) else: print("没有这个功能")
上面有两个函数:一个是getattr(),hasattr().
- getattr()用来获取信息.
- hasattr()用来判断xxx中是否包含了xxx功能,.
在面向对象中:
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 方法
class Person: def __init__(self,name): self.name = name self .age = None def chi(self): print("%s喜欢吃东西" % self.name) p = Person("张三") # p.chi() val = input("请输入你想让张三执行的动作:") if hasattr(p,val): func = getattr(p,val) func()
另外:
class Person: def __init__(self,name): self.name = name self .age = None def chi(self): print("%s喜欢吃东西" % self.name) p = Person("张三") setattr(p,"name","大阳哥") # 动态的给对象设置属性和值 setattr(p,"age",18) # 很少用. 慎用 print(p.age) delattr(p, "age") print(p.age)
反射共有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成员删除掉
注意, 以上操作都是在内存中进行的. 并不会影响你的源代码