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'>
  • 相关阅读:
    陶瓷电容的结构、工艺、失效模式
    Vue.js最佳实践
    Vue 超快速学习
    CSS 小技巧
    HTML5 Canvas
    webkit下面的CSS设置滚动条
    Some untracked working tree files would be overwritten by checkout. Please move or remove them before you can checkout. View them
    JSCS: Please specify path to 'JSCS' package
    React中ref的使用方法
    React 60S倒计时
  • 原文地址:https://www.cnblogs.com/blackmatrix/p/6847313.html
Copyright © 2011-2022 走看看