`
luozhaoyu
  • 浏览: 347629 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

理解python的staticmethod与classmethod实现

阅读更多
本文源于一时好奇,想要弄清出python的staticmethod()这一builtin方法的实现,查了一些资料(主要是python官方手册了)汇集于此

python在类中,有三种调用method的方法:普通method,staticmethod和classmethod
前两个应该都好理解,classmethod就是在调用这个函数的时候,会把调用对象的class object对象隐式地传进去。咦?这个class object不是一个类型?No,在python里面,class object不像静态语言一样是个类型,它在虚拟机中,就是一个对象
普通method调用需要把自己self作为参数传递,初学的时候怎么着也不能理解,不过看多了就自然熟悉了。比较奇怪的是staticmethod和classmethod不像静态语言一样,通过保留关键字定义,而是使用@staticmethod或者staticmethod()这种builtin函数进行定义。这个@staticmethod到底是个什么东东?
@staticmethod
def foo(x):
    print(x)


之前用过java,所以第一反应这是个annotation……唔,确实感觉像个AOP的东西,python里把它称作decorator。如果我们要自己实现一个staticmethod,该怎么写呢?

研究了下官方的代码,我再改了改,感觉应该这样写:
def foo(x):
    print(x)
class StaticMethod(object):
    def __init__(self, function):
        print("__init__() called")
        self.f = function
    def __get__(self, instance, owner):
        print("\t__get__() called")
        print("\tINFO: self = %s, instance =%s, owner = %s" % (self, instance, owner))
        return self.f

class Class1(object):
    method = StaticMethod(foo)
    
if __name__ == '__main__':
    ins = Class1()
    print("ins = %s, Class1 = %s" % (ins, Class1))
    print("ins.method = %s, Class1.method = %s" % (ins.method, Class1.method))
    ins.method('abc')
    Class1.method('xyz')


输出结果是:
__init__() called
ins = <__main__.Class1 object at 0xece2d0>, Class1 = <class '__main__.Class1'>
	__get__() called
	INFO: self = <__main__.StaticMethod object at 0xece5d0>, instance =<__main__.Class1 object at 0xece2d0>, owner = <class '__main__.Class1'>
	__get__() called
	INFO: self = <__main__.StaticMethod object at 0xece5d0>, instance =None, owner = <class '__main__.Class1'>
ins.method = <function foo at 0xeb6c00>, Class1.method = <function foo at 0xeb6c00>
	__get__() called
	INFO: self = <__main__.StaticMethod object at 0xece5d0>, instance =<__main__.Class1 object at 0xece2d0>, owner = <class '__main__.Class1'>
abc
	__get__() called
	INFO: self = <__main__.StaticMethod object at 0xece5d0>, instance =None, owner = <class '__main__.Class1'>
xyz

嗯,看上去一切都挺顺利,Class1包含了一个变量method,不过这个method其实也是一个特殊处理过的StaticMethod类。这个类中有一个__get__函数,当类被“get”的时候,被访问的时候,会默认把访问者的instance和class信息都传进来。所以我们看到不管是否调用method()这个函数,只要碰着了method,这个函数就会触发,就会打印出当前instance和class信息。虽然ins和Class1的instance各有不同,但__get__函数中只是返回foo函数,所以这里调用method之时就没有区别,调用的都是同一个function对象。

好的,那么classmethod又如何实现呢?
def foo2(cls, x):
    print("foo2's class = ", cls)
    print(x)

class ClassMethod(object):
    def __init__(self, function):
        print("ClassMethod: __init__() called")
        self.f = function
    def __get__(self, instance, owner = None):
        print("\t__get__() called")
        print("\tINFO: self = %s, instance =%s, owner = %s" % (self, instance, owner))
        def tmpfunc(x):
            print("I'm tmpfunc")
            return self.f(owner, x)
        return tmpfunc

class Class2(object):
    method = ClassMethod(foo2)

class Class21(Class2):
    pass
if __name__ == '__main__':
    ins = Class2()
    print("ins.method = %s, Class2.method = %s, Class21.method = %s" % (ins.method, Class2.method, Class21.method))
    ins.method('abc')
    Class2.method('xyz')
    Class21.method('asdf')


输出结果是:
ClassMethod: __init__() called
	__get__() called
	INFO: self = <__main__.ClassMethod object at 0xdeb250>, instance =<__main__.Class2 object at 0xdeb350>, owner = <class '__main__.Class2'>
	__get__() called
	INFO: self = <__main__.ClassMethod object at 0xdeb250>, instance =None, owner = <class '__main__.Class2'>
	__get__() called
	INFO: self = <__main__.ClassMethod object at 0xdeb250>, instance =None, owner = <class '__main__.Class21'>
ins.method = <function tmpfunc at 0xdee050>, Class2.method = <function tmpfunc at 0xdee1e8>, Class21.method = <function tmpfunc at 0xdee270>
	__get__() called
	INFO: self = <__main__.ClassMethod object at 0xdeb250>, instance =<__main__.Class2 object at 0xdeb350>, owner = <class '__main__.Class2'>
I'm tmpfunc
foo2's class =  <class '__main__.Class2'>
abc
	__get__() called
	INFO: self = <__main__.ClassMethod object at 0xdeb250>, instance =None, owner = <class '__main__.Class2'>
I'm tmpfunc
foo2's class =  <class '__main__.Class2'>
xyz
	__get__() called
	INFO: self = <__main__.ClassMethod object at 0xdeb250>, instance =None, owner = <class '__main__.Class21'>
I'm tmpfunc
foo2's class =  <class '__main__.Class21'>
asdf


可以看出,classmethod和staticmethod的实现方法是大同小异。staticmethod比较简单,直接返回self.f变量就好了,而classmethod不行,需要把调用时候的class类型信息传给foo2函数,这个函数根据接收的class信息来作不同的工作。(不过我现在也没有想到可以用来做些什么)

有个地方值得注意,可能同志们刚才也已经想到了,我一定必须要定义一个tempfunc,再返回它才能完成工作吗?可不可以不要
def tmpfunc(x):
            print("I'm tmpfunc")
            return self.f(owner, x)
        return tmpfunc


而直接返回一个
return self.f(owner, *args)



我刚试了一把,直接传args默认参数是不行的,因为__get__被调用的时候,还没有把参数传进来。只有return tmpfunc之后,Class2.method('xyz')的参数才挂在tmpfunc之上。

当然,如果有朋友成功做到了,请一定留言告诉我XD

小结:看来staticmethod和classmethod实现不是很困难,多亏了__get__函数帮忙。前文也提到__get__被调用时会把instance和class信息都填进来,真是帮了很大忙。但是,这个__get__函数到底又是怎么一回事?为什么这么神奇?这里卖个关子,本文先不讲了,下篇博文再看看这个__get__函数
1
1
分享到:
评论

相关推荐

    python的staticmethod与classmethod实现实例代码

    在Python中,我们有三种主要的方式来定义类的方法:普通方法(实例方法)、静态方法(staticmethod)和类方法(classmethod)。这些方法在不同的场景下有着各自的作用。 首先,普通方法(实例方法)是通过`self`...

    Python中staticmethod和classmethod的作用与区别

    要理解staticmethod和classmethod的作用与区别,首先需要了解Python中实例方法、静态方法和类方法的基本概念。 实例方法是定义在类中,并以self参数开头的方法。self参数代表的是类的实例对象,即每一个创建出来的...

    基于python中staticmethod和classmethod的区别(详解)

    总的来说,理解`staticmethod`和`classmethod`的区别有助于编写更加清晰、可维护的Python代码,它们提供了灵活的方式来组织和扩展类的行为。在实际编程中,根据具体需求选择合适的方法修饰器是非常重要的。

    staticmethod和classmethod的区别

    python中有三种方法,实例方法、静态方法(staticmethod) 和 类方法(classmethod)

    Python @函数装饰器及@staticmethod,@classmethod.docx

    除了通用的函数装饰器,Python 还提供了内置的装饰器 `@staticmethod` 和 `@classmethod`。 - **@staticmethod**:将一个方法标记为静态方法,意味着它不需要实例化对象就可以被调用。 - **@classmethod**:将一个...

    Python 类方法和实例方法(@classmethod),静态方法(@staticmethod)原理与用法分析

    静态方法则是通过`@staticmethod`装饰器定义的,它们与类或实例无关,不接收`self`或`cls`参数。静态方法内部不能访问类属性或实例属性,它们更像是独立的辅助函数,但被标记为与特定类相关联。在`Dog`类中,`run`...

    python面试题

    - 更多关于这个问题的讨论:[What is the difference between staticmethod and classmethod in Python?]...

    Python探索之静态方法和类方法的区别详解

    python staticmethod and classmethod Though classmethod and staticmethod are quite similar, there's a slight difference in usage for both entities: classmethod must have a reference to a class object ...

    python实现装饰器、描述符

    装饰器进阶:property、staticmethod、classmethod源码分析(python代码实现) 装饰器基础 无参装饰器 ''' 假定有一个需求是:打印程序函数运行顺序 此案例打印的结果为: foo1 function is starting foo2 ...

    python装饰器decorator介绍

    一、装饰器decorator ... 比较常用的功能一般使用decorator来实现,例如python自带的staticmethod和classmethod。 装饰器有两种形式: 复制代码 代码如下: @A def foo():  pass 相当于: 复制代码 代码如下

    python-3_pythondocs中文_python3.8.2文档_python3.8.2下载_python文档_Pytho

    Python 3.8中,`@classmethod`和`@staticmethod`装饰器现在可以直接在类体内部定义,提高了代码的可读性。 5. **模块开发和打包**:对于希望创建自己的Python模块或扩展的开发者,文档会介绍如何编写setup.py文件,...

    stat_python_

    Python提供了`classmethod`和`staticmethod`装饰器来处理类方法。静态方法(`staticmethod`)不接收`self`参数,可以直接调用类名或实例来调用。然而,它们并不是真正的静态变量,因为它们无法直接访问类变量。如果...

    超全面python面试题

    3 @staticmethod和@classmethod 4 类变量和实例变量 5 Python自省 6 字典推导式 7 Python中单下划线和双下划线 8 字符串格式化:\x和.format 9 迭代器和生成器 10 *args and **kwargs 11 面向切面编程AOP和装饰器 12 ...

    python3.5.3.zip

    4. **新函数特性**:`@classmethod`和`@staticmethod`现在可以接受参数,这提供了一种更灵活的类方法定义方式。 5. **新的内置函数**:包括`ascii()`,用于返回对象的ASCII表示,不包含非ASCII字符;`sorted()`现在...

    Python Attributes and Methods

    在Python中,方法是与类或对象相关的函数,它们通常用于实现类的特定功能。方法可以访问并操作对象的数据,即属性。与普通函数相比,方法的第一个参数通常是`self`,表示当前对象的引用,这让方法能够访问对象的属性...

    python全套课程继承与多态

    **数据工具的继承与实现**通常涉及到如何处理类中的数据成员,如属性和方法。在继承过程中,子类会继承父类的所有非私有属性和方法。可以通过`__init__`方法初始化这些数据,确保每个实例都有正确的初始状态。同时,...

    python函数文档_python函数_python文档_python_

    例如,`@staticmethod` 和 `@classmethod` 装饰器改变类方法的调用方式,`@property` 用于创建属性访问器。 Python 标准库还包含了异常处理机制,使用 `try/except` 语句捕获和处理错误。例如: ```python try: ...

    Python 静态方法和类方法实例分析

    要了解类方法和静态方法,首先需要理解类属性和实例属性的概念。 类属性是属于类本身的属性,它被这个类的所有实例共享。通常,类属性用于定义该类的常量或为所有实例提供通用的数据。在Python中,类属性通过直接在...

    Python语言特性.docx_python面试

    3. @staticmethod 和 @classmethod Python 中有三种方法:实例方法、类方法和静态方法。实例方法需要绑定实例,类方法需要绑定类,而静态方法不需要绑定任何对象。实例方法和类方法都需要传递 self 或 cls 参数,而...

    python练手经典100例-推荐几个适合新手练手的Python项目《python入门例子》.pdf

    ⾄于说没有run()没有参数self,⽽是参数cls,为什么可⽤,那就是装饰器@classmethod在起作⽤了,理解了装饰器,就知道这个问题的 答案了。不然的话,还有@staticmethod可以让⽅法连cls⽅法都不需要⼜怎么说。 ...

Global site tag (gtag.js) - Google Analytics