python 面向对象 isinstance + 反射 + 函数和方法
issubclass / type / isinstance
♥♥♥
1. issubclass
issubclass(Foo,Base) Foo类是否为Base类的子类, 这里的子类指子子孙孙, 即这里Base也可以是Foo的爷爷类
判断第一个参数是否为第二个参数的 子孙类
返回值为 bool
class Base(object):
pass
class Foo(Base):
pass
class Bar(Foo):
pass
print(issubclass(Bar,Base)) # 检查第一个参数是否是第二个参数的 子子孙孙类
# True
2. type
获取当前对象是由哪个类创建的,
class Foo(object):
pass
obj = Foo()
print(obj,type(obj)) # 获取当前对象是由那个类创建。
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 # 返回的是元组
# 方法一
result = func(Foo(),Bar(),Foo()) # result 为元组
print(result)
# 方法二
v1,v2 = func(Foo(),Bar(),Foo()) # 可以 v1,v2 来接收返回值 获取的是值
print(v1,v2)
# (2, 1)
# 2 1
3. isinstance
检查第一个参数 (对象) 是否为第二个参数 (类及父类) 的实例.
class Base(object):
pass
class Foo(Base):
pass
obj1 = Foo()
print(isinstance(obj1,Foo)) # 检查第一个参数(对象)是否是第二个参数(类及父类)的实例。# True
print(isinstance(obj1,Base)) # 检查第一个参数(对象)是否是第二个参数(类及父类)的实例。# True
obj2 = Base()
print(isinstance(obj2,Foo)) # 检查第一个参数(对象)是否是第二个参数(类及父类)的实例。# False
print(isinstance(obj2,Base)) # 检查第一个参数(对象)是否是第二个参数(类及父类)的实例。# True
总结 :
1. 给一个参数,判断对象是不是由某一个指定类 创建的?
用 type() >>> type(obj) == Foo
2. 给一个参数,判断对象是不是由某一个指定类 或其父类 创建的?
用 isinstance >>> isinstance(obj,Foo)
方法和函数
方法和函数 是由如何调用来区分的,并非是由如何定义来区分的.
1. 称谓(为了方便) :
类中, 方法
类外, 函数
2. 到底是 方法 还是 函数?
对象.xxx --> xxx就是方法
类.xxx --> xxx就是函数
xxx --> xxx就是函数
静态方法是函数,只能用对象调用的是方法.
3. 可以打印 (函数名或方法名) 查看是 方法 还是 函数?
print(func)
function 是函数
method 是方法
4. 检查是函数还是方法?
函数是FunctionType创建的,方法是由MethodType创建的
需要导入模块 : from types import MethodType,FunctionType
from types import MethodType,FunctionType
def check(arg):
"""
检查arg是方法还是函数?
:param arg:
:return:
"""
if isinstance(arg,MethodType):
print('%s是一个方法'%arg)
elif isinstance(arg,FunctionType):
print('%s是一个函数'%arg)
else:
print('不知道是什么')
def func():
pass
class Foo(object):
def detail(self):
pass
@staticmethod
def xxx():
pass
check(func) # 函数
obj = Foo()
check(obj.detail) #方法
check(obj.xxx) #函数
5. 实例方法的调用? (了解即可)
当类调用实例方法的时候, 函数不会自动传self值必须手动传参
class Foo:
def f1(self):
pass
# 方法一 类调用(不建议用)
obj = Foo()
Foo.f1(obj) # 把f1当做函数 手动传参 obj
# 方法二 对象调用 (常用)
obj = Foo()
obj.f1() # 把f1当做方法,自动传self值
6. 练习
1) 类中的方法 被类调用的时候是函数, 此时函数不会自动传入self参数, 需要手动传参.
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: # 循环类列表
# item(Foo()) # item() 也就是f1()此时是函数不会自动传入self参数,需要手动传入
item(123) # item() 中的参数不一定是对象 也可以是123等
print(Foo.list_display)
#[<function Foo.f1 at 0x0000024185FB2048>, <function Foo.f2 at 0x0000024185FB20D0>]
2) 对象的调用 是一个方法, 类的调用是一个函数, 注意区分
class Foo(object):
def f1(self):
pass
def f2(self):
pass
def f3(self):
pass
list_display = [f1,f2] # f1 和 f2 是作为函数添加到列表中的
obj = Foo()
Foo.list_display.append(obj.f3) # obj.f3 (对象调用)是一个方法 作为方法传进了参数
for item in Foo.list_display:
print(item)
# <function Foo.f1 at 0x000001DF6E3D2048>
# <function Foo.f2 at 0x000001DF6E3D20D0>
# <bound method Foo.f3 of <__main__.Foo object at 0x000001DF6E3C9518>>
反射 ♥
♥♥♥♥♥
1. 需求
可以解决之前常用的 if ... elif ... elif ... else ... 等.
if xx:
...
elif xx:
...
elif xx:
...
else:
...
2 . 总结
v = getattr (obj,"func") # 根据 字符串为参数 (第二个参数) , 去对象 (第一个参数) 中寻找与之同名的成员.
这里的对象是广泛的对象,在python中一切皆对象. 这里对象可以指 模块 / 类 等.
getattr() # 根据字符串的形式, 去对象中找成员
hasattr() # 根据字符串的形式, 去判断对象中是否有该成员
setattr() # 根据字符串的形式, 动态设置一个成员 (内存级别的,不会在原模块或类中添加)
delattr() # 根据字符串的形式, 动态删除一个成员 (内存级别的,不会在原模块或类中删除)
3. 应用
1) 反射示例 -- 模块中
在 handler.py 文件中
# handler.py
f0 = 9
def f1():
print('F1')
def f2():
print('F2')
def f3():
print('F3')
def f4():
print('F4')
def f5():
print('F5')
在 run.py 文件中
# run.py
from types import FunctionType # 导入模块用于判断是否为函数
import handler # 导入handler 用于查找
while True:
print("""
系统支持的函数有:
1. f1
2. f2
3. f3
4. f4
5. f5
""")
val = input("请输入要执行的函数:") # val = "f1"
# 方法一 这是错误的
# handler.val()
# 方法二 运用反射
if hasattr(handler,val): # 判断 handler 中是否有 val(f1)
func_or_val = getattr(handler,val) # f1 # 根据字符串为参数,去模块中寻找与之同名的成员。
if isinstance(func_or_val,FunctionType): # 判断是否为函数
func_or_val() # 为函数则执行
else:
print(func_or_val) # 否则就打印 (为变量)
else:
print('handler中不存在输入的属性名')
# 方法三 以前常用的 正确方式
"""
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()
"""
2) 反射示例 -- 类中
重点看看
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] # 此处类变量建议使用 类Account来调用
# func = getattr(Account,func_name) # Account.login 也是正确的
# func(self)
func = getattr(self, func_name) # self.login
func()
obj1 = Account()
obj1.run()
obj2 = Account()
obj2.run()
4. 反射补充 -- 以handler模块为例
import handler # 1. 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 # 2. 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 # 3. delattr delattr(handler,'f0') # v8 = getattr(handler,'f0') # print(v8) # AttributeError: module 'handler' has no attribute 'f0'
callable
用于判断是否能够被调用
1. 你见过什么后面可以加 括号( ) ?
- 类( ) >>> 创建对象
- 对象( ) >>> 自动执行类中的 __call__ 方法
- 函数( ) >>> 函数被执行
- 方法( ) >>> 方法被执行
以上所有加了括号, 都是可以被调用的.
2. 如何判断一个 xxx 是否可以被 调用?
使用 callable(xxx) 打印返回的是 bool 值
示例 :
def func(): pass class Foo(object): def __call__(self, *args, **kwargs): pass def func(self): pass obj = Foo() print(callable(func)) # 函数 print(callable(Foo)) # 类 print(callable(obj)) # 对象 print(callable(obj.func)) # 方法 # 结果都为True


浙公网安备 33010602011771号