专栏首页python前行者[887]python中@classmethod和@staticmethod

[887]python中@classmethod和@staticmethod

一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法。 而使用@staticmethod或@classmethod,就可以不需要实例化,**直接类名.方法名()**来调用。 这有利于组织代码,把某些应该属于某个类的函数给放到那个类里去,同时有利于命名空间的整洁。

既然@staticmethod和@classmethod都可以**直接类名.方法名()**来调用,那他们有什么区别呢 ?

从它们的使用上来看,

  • @staticmethod不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样。
  • @classmethod也不需要self参数,但第一个参数需要是表示自身类的cls参数。
  • 如果在@staticmethod中要调用到这个类的一些属性方法,只能直接类名.属性名或类名.方法名。
  • 而@classmethod因为持有cls参数,可以来调用类的属性,类的方法,实例化对象等,避免硬编码。

Python中3种方式定义类方法, 常规方式, @classmethod修饰方式, @staticmethod修饰方式.

class A(object):

    def foo(self, x):
        print("executing foo(%s,%s)" % (self, x))
        print('self:', self)

    @classmethod
    def class_foo(cls, x):
        print("executing class_foo(%s,%s)" % (cls, x))
        print('cls:', cls)

    @staticmethod
    def static_foo(x):
        print("executing static_foo(%s)" % x)    

a = A()

1.定义方式

普通的类方法foo()需要通过self参数隐式的传递当前类对象的实例。 @classmethod修饰的方法class_foo()需要通过cls参数传递当前类对象。@staticmethod修饰的方法定义与普通函数是一样的。

self和cls的区别不是强制的,只是PEP8中一种编程风格,slef通常用作实例方法的第一参数,cls通常用作类方法的第一参数。即通常用self来传递当前类对象的实例,cls传递当前类对象。

问题:@staticmethod修饰的方法函数与普通的类外函数一样,为什么不直接使用普通函数? @staticmethod是把函数嵌入到类中的一种方式,函数就属于类,同时表明函数不需要访问这个类。通过子类的继承覆盖,能更好的组织代码。

2.绑定对象

foo方法绑定对象A的实例,class_foo方法绑定对象A,static_foo没有参数绑定。
>>> print(a.foo)
<bound method A.foo of <__main__.A object at 0x0278B170>>
>>> print(a.class_foo)
<bound method A.class_foo of <class '__main__.A'>>
>>> print(a.static_foo)
<function A.static_foo at 0x02780390>

3.调用方式

foo可通过实例a调用,类对像A直接调用会参数错误。

>>> a.foo(1)
executing foo(<__main__.A object at 0x0278B170>,1)
self: <__main__.A object at 0x0278B170>
>>> A.foo(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() missing 1 required positional argument: 'x'

但foo如下方式可以使用正常,显式的传递实例参数a。

>>> A.foo(a, 1)
executing foo(<__main__.A object at 0x0278B170>,1)
self: <__main__.A object at 0x0278B170>

class_foo通过类对象或对象实例调用。

>>> A.class_foo(1)
executing class_foo(<class '__main__.A'>,1)
cls: <class '__main__.A'>
>>> a.class_foo(1)
executing class_foo(<class '__main__.A'>,1)
cls: <class '__main__.A'>

static_foo通过类对象或对象实例调用。

>>> A.static_foo(1)
executing static_foo(1)
>>> a.static_foo(1)
executing static_foo(1)

4.继承与覆盖普通类函数是一样的。

class B(A):
    pass

b = B()
b.foo(1)
b.class_foo(1)
b.static_foo(1)
# executing foo(<__main__.B object at 0x007027D0>,1)
# self: <__main__.B object at 0x007027D0>
# executing class_foo(<class '__main__.B'>,1)
# cls: <class '__main__.B'>
# executing static_foo(1)

5. 其它

class A(object):

    # 属性默认为类属性(可以给直接被类本身调用)
    num = "类属性"

    # 实例化方法(必须实例化类之后才能被调用)
    def func1(self): # self : 表示实例化类后的地址id
        print("func1")
        print(self)

    # 类方法(不需要实例化类就可以被类本身调用)
    @classmethod
    def func2(cls):  # cls : 表示没用被实例化的类本身
        print("func2")
        print(cls)
        print(cls.num)
        cls().func1()

    # 不传递传递默认self参数的方法(该方法也是可以直接被类调用的,但是这样做不标准)
    def func3():
        print("func3")
        print(A.num) # 属性是可以直接用类本身调用的
    
# A.func1() 这样调用是会报错:因为func1()调用时需要默认传递实例化类后的地址id参数,如果不实例化类是无法调用的
A.func2()
A.func3()

参考:https://www.cnblogs.com/elie/p/5876210.html https://blog.csdn.net/polyhedronx/article/details/81911548 https://www.runoob.com/python/python-func-classmethod.html

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 静态html提取正文的API和开源算法

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

    周小董
  • 企查查api接口操作

    企查查api接口中心:http://openapi.qichacha.com/DataCenter

    周小董
  • [709]python之pywifi

    这一步需要使用tkinter模块,这是python自带的图形界面库,通过import tkinter调用使用就可以了,代码中set_init_window函数就...

    周小董
  • R中的管道操作符%>%

    管道是一种强大的工具,可以清楚地表示由多个操作组成的一个操作序列。管道%>% 来自于magrittr 包。因为tidyverse 中的包会自动加载%>%,所以一...

    生信编程日常
  • python classmethod和

       这两个装饰器是Python自带的,虽然一直都知道装饰器是怎么用的,但是确实不知道何时去使用它们,今天看到某人用到了,又看了一遍,才有所收货.

    py3study
  • VC和GCC成员函数指针实现的研究(二)

    调用的时候主要看(c.*vptr2)()的代码。因为(c.vptr1)()生成的和单继承一样。而由于它们最终都转向vcall,所以vptr2的时候调整了虚表指针...

    owent
  • python expect

    py3study
  • Python中的@staticmethod和@classmethod的区别

    使用classmethods时,对象实例的类作为第一个参数而不是隐式传递self。

    BigYoung小站
  • 你所不知道的“foo”和“bar”

    “foo” 和“foobar”等单词经常会作为示例名称出现在各种程序和技术文档中。据统计,在各种计算机和通信技术文档中,大约有百分之七的文档出现了这些词语。...

    Jean
  • 【译】通过可选链操作符重构大型代码库的经验教训

    如今,可选链操作符已经被支持了。我决定用其来重构Mavo(当然了,还需要提供一个转译版本来适配不支持该特性的浏览器)。我等这一刻已经很久了,这是我认为自箭头函数...

    腾讯IVWEB团队

扫码关注云+社区

领取腾讯云代金券