zoukankan      html  css  js  c++  java
  • 关于Python的函数(Method)与方法(Function)

    先上结论:

    1. 函数(function)是Python中一个可调用对象(callable), 方法(method)是一种特殊的函数。
    2. 一个可调用对象是方法和函数,和这个对象无关,仅和这个对象是否与类或实例绑定有关(bound method)。
    3. 实例方法,在类中未和类绑定,是函数;在实例中,此实例方法与实例绑定,即变成方法。
    4. 静态方法没有和任何类或实例绑定,所以静态方法是个函数。
    5. 装饰器不会改变被装饰函数或方法的类型。
    6. 类实现__call__方法,其实例也不会变成方法或函数,依旧是类的实例。
    7. 使用callalble() 只能判断对象是否可调用,不能判断是不是函数或方法。
    8. 判断对象是函数或方法应该使用type(obj)。

    下面,使用一些例子,对上述结论进行检测、验证。

    测试的例子中,我们创建一个装饰器、一个函数及一个类,这个类包含:实例方法、类方法、静态方法及被装饰器装饰的方法。

    完整代码: https://github.com/blackmatrix7/python-learning/blob/master/function_/method_func.py

    def test_decorator(func):
        """
        装饰器,测试使用,无功能
        :param func:
        :return:
        """
        @wraps(func)
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        return wrapper
    
    
    def the_function():
        """
        函数
        :return: 
        """
        pass
    
    
    class TheClass:
    
        def __call__(self, *args, **kwargs):
            return self
    
        @classmethod
        def class_method(cls):
            """
            类方法
            :return: 
            """
            pass
    
        def instance_method(self):
            """
            实例方法
            """
            return self
    
        @staticmethod
        def static_method():
            """
            静态方法
            :return: 
            """
            pass
    
        @test_decorator
        def decorated_func(self):
            pass

    先对类方法和实例方法的类型进行检测(注释部分为输出结果,下同)。

    从运行结果上看,类方法和实例方法都是方法(method)。

    同时,通过直接打印类方法和实例方法,可以得知它们都是绑定方法(bound method)。

        print('class_method type {type} '.format(type=type(TheClass.class_method)))
        # class_method type <class_ 'method'>
        print('instance_method type {type} '.format(type=type(the_class.instance_method)))
        # instance_method type <class_ 'method'>
        print(TheClass.class_method)
        # <bound method TheClass.class_method of <class '__main__.TheClass'>>
        print(the_class.instance_method)
        # <bound method TheClass.instance_method of <__main__.TheClass object at 0x00000275DEB3FC50>>

    如果仅通过上述运行结果,就得出类方法和实例方法都是方法,那么就错了。

    再看下面的代码,同一个对象instance_method,之前还是方法(method),现在已经变成函数(function)。

        print('instance_method type {type} '.format(type=type(TheClass.instance_method)))
        # instance_method type <class 'function'>
        print(TheClass.instance_method)
        # <function TheClass.instance_method at 0x00000275DEB3D840>

    第二段代码,和第一段代码的不同之处:第一段代码是通过实例,去访问实例方法;而第二段代码,是通过类去访问实例方法。

    同一个可调用对象,仅仅是访问的方式不同,就能从方法变为函数。

    因为,在类中的实例方法,并没有和类建立绑定关系,所以它是方法。当类进行实例化时,会将实例方法,绑定到类创建出的实例上,此时实例方法与实例形成绑定关系,从函数变为方法。

    所以,可以得到开头的第2、3条结论:

    一个可调用对象是方法和函数,和这个对象无关,仅和这个对象是否与类或实例绑定有关(bound method)。

    实例方法,在类中未和类绑定,是函数;在实例中,此实例方法与实例绑定,即变成方法。

    接着对静态方法进行检测,有了之前的结论,就很容易理解为什么静态方法是函数而不是方法:因为它不会和类或实例进行绑定。

        print('static_method type {type} '.format(type=type(the_class.static_method)))
        # static_method type <class_ 'function_'>
        print('static_method type {type} '.format(type=type(TheClass.static_method)))
        # static_method type <class 'function'>
        print(TheClass.static_method, the_class.static_method, sep='
    ')
        # <function TheClass.static_method at 0x0000024BC5EAD950>
        # <function TheClass.static_method at 0x0000024BC5EAD950>

    而对于一个函数,因为不会和任何类或实例绑定(除非使用MethodType将函数绑定到某个实例上),必然不是方法。

        print('the_function type {type} '.format(type=type(the_function)))
        # the_function type <class_ 'function_'>

    对于装饰器,本身也不会改变被装饰对象的类型

        # 装饰器本身也是个函数
        print('test_decorator type {type} '.format(type=type(test_decorator)))
        # test_decorator type <class_ 'function_'>
    
        # 将装饰器装饰器到实例方法上
        # 检查被装饰的方法的类型
        print('decorated_func type {type} '.format(type=type(the_class.decorated_func)))
        # decorated_func type <class_ 'method'>
        # 从测试结果得知,装饰器不会影响被装饰方法或函数的类型

    如果一个类,实现__call__方法,那么其实例会变为可调用对象,但这个这个实例依旧不是函数或方法

        # 如果类实现__call__方法
        # 执行结果True 其实例变为可调用对象
        print('class_instance callable {callable} '.format(callable=callable(the_class)))
        # 实例的类型依旧是这个类,而不会变成函数或方法
        print('class_instance type {type} '.format(type=type(the_class)))
        # class_instance type <class_ '__main__.TheClass'>
  • 相关阅读:
    定时器
    自定义个性化 EditPeople控件
    infopath 2010 调试.
    MOSS 查询
    网站项目建设流程概述
    跨站点显示列表数据 ListViewWebPart
    VIM记事——大小写转换
    事务码记录 程序优化常用st12
    SAP各模块字段与表的对应关系
    固定资产一览
  • 原文地址:https://www.cnblogs.com/blackmatrix/p/6847313.html
Copyright © 2011-2022 走看看