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>]
View Code 

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>>
View Code

反射 ♥

♥♥♥♥♥

 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

 

posted @ 2018-08-30 15:17  葡萄想柠檬  Views(230)  Comments(0)    收藏  举报
目录代码