Python 中的 classmethod 和 staticmethod 有什么具体用途
classmethod将方法变成类方法,自动传给方法的第一个参数是类,而不是类的实例
staticmethod将class中的方法变成静态方法,可以当做普通方法一样调用 ,而不会将类实例本身作为第一个self参数传给方法
静态方法无绑定,和普通函数使用方法一样,只是需要通过类或者实例来调用。没有隐性参数。
类方法通过隐性参数绑定在类上,函数内可通过隐性参数进行实例生成。
实例方法通过隐性参数绑定在类上,函数内通过隐性参数访问实例属性。
用个例子来解释一下:
# class Date(object): def __init__(self, day=0, month=0, year=0): self.day = day self.month = month self.year = year def __str__(self): return "{0}-{1}-{2}".format(self.year, self.month, self.day) @classmethod def from_string(cls, date_as_string): year, month, day = map(int, date_as_string.split('-')) date1 = cls(day, month, year) return date1 @staticmethod def is_date_valid(date_as_string): year, month, day = map(int, date_as_string.split('-')) return day <= 31 and month <= 12 and year <= 3999 @staticmethod def millenium(month, day): return Date(month, day, 2000) class DateTime(Date): def __str__(self): return "{0}-{1}-{2} - 00:00:00PM".format(self.year, self.month, self.day) if __name__=="__main__": s='2012-09-11' if Date.is_date_valid(s): date1 = Date.from_string('2012-09-11') print date1 date2 = DateTime.from_string('2012-09-11') print date2 millenium_new_year1 = Date.millenium(1, 1) print millenium_new_year1 millenium_new_year2 = DateTime.millenium(10, 10) print millenium_new_year2
具体讲解在我的课程里有,
http://study.163.com/course/courseMain.htm?courseId=1000035
这个答案的原文是Difference between @staticmethod and @classmethod in Python
这里的内容是我通知原作者并得到允许的情况下的翻译稿
这个是我的博客文章的地址pyhton静态方法和类方法
类中最常用的方法是实例方法, 即通过通过实例作为第一个参数的方法。
举个例子,一个基本的实例方法就向下面这个:
class Kls(object):
def __init__(self, data):
self.data = data
def printd(self):
print(self.data)
ik1 = Kls('arun')
ik2 = Kls('seema')
ik1.printd()
ik2.printd()
这会给出如下的输出:
arun
seema
然后看一下代码和示例图片:
1,2参数传递给方法.
3 self参数指向当前实例自身.
4 我们不需要传递实例自身给方法,Python解释器自己会做这些操作的.
如果现在我们想写一些仅仅与类交互而不是和实例交互的方法会怎么样呢? 我们可以在类外面写一个简单的方法来做这些,但是这样做就扩散了类代码的关系到类定义的外面. 如果像下面这样写就会导致以后代码维护的困难:
def get_no_of_instances(cls_obj):
return cls_obj.no_inst
class Kls(object):
no_inst = 0
def __init__(self):
Kls.no_inst = Kls.no_inst + 1
ik1 = Kls()
ik2 = Kls()
print(get_no_of_instances(Kls))
输出:
2
@classmethod
我们要写一个只在类中运行而不在实例中运行的方法. 如果我们想让方法不在实例中运行,可以这么做:
def iget_no_of_instance(ins_obj):
return ins_obj.__class__.no_inst
class Kls(object):
no_inst = 0
def __init__(self):
Kls.no_inst = Kls.no_inst + 1
ik1 = Kls()
ik2 = Kls()
print iget_no_of_instance(ik1)
输出
2
在Python2.2以后可以使用@classmethod装饰器来创建类方法.
class Kls(object):
no_inst = 0
def __init__(self):
Kls.no_inst = Kls.no_inst + 1
@classmethod
def get_no_of_instance(cls_obj):
return cls_obj.no_inst
ik1 = Kls()
ik2 = Kls()
print ik1.get_no_of_instance()
print Kls.get_no_of_instance()
输出:
2
2
这样的好处是: 不管这个方式是从实例调用还是从类调用,它都用第一个参数把类传递过来.
@staticmethod
经常有一些跟类有关系的功能但在运行时又不需要实例和类参与的情况下需要用到静态方法. 比如更改环境变量或者修改其他类的属性等能用到静态方法. 这种情况可以直接用函数解决, 但这样同样会扩散类内部的代码,造成维护困难.
比如这样:
IND = 'ON'
def checkind():
return (IND == 'ON')
class Kls(object):
def __init__(self,data):
self.data = data
def do_reset(self):
if checkind():
print('Reset done for:', self.data)
def set_db(self):
if checkind():
self.db = 'new db connection'
print('DB connection made for:',self.data)
ik1 = Kls(12)
ik1.do_reset()
ik1.set_db()
输出:
Reset done for: 12
DB connection made for: 12
如果使用@staticmethod就能把相关的代码放到对应的位置了.
IND = 'ON'
class Kls(object):
def __init__(self, data):
self.data = data
@staticmethod
def checkind():
return (IND == 'ON')
def do_reset(self):
if self.checkind():
print('Reset done for:', self.data)
def set_db(self):
if self.checkind():
self.db = 'New db connection'
print('DB connection made for: ', self.data)
ik1 = Kls(12)
ik1.do_reset()
ik1.set_db()
输出:
Reset done for: 12
DB connection made for: 12
下面这个更全面的代码和图示来展示这两种方法的不同
@staticmethod 和 @classmethod的不同
class Kls(object):
def __init__(self, data):
self.data = data
def printd(self):
print(self.data)
@staticmethod
def smethod(*arg):
print('Static:', arg)
@classmethod
def cmethod(*arg):
print('Class:', arg)
>>> ik = Kls(23)
>>> ik.printd()
23
>>> ik.smethod()
Static: ()
>>> ik.cmethod()
Class: (<class '__main__.Kls'>,)
>>> Kls.printd()
TypeError: unbound method printd() must be called with Kls instance as first argument (got nothing instead)
>>> Kls.smethod()
Static: ()
>>> Kls.cmethod()
Class: (<class '__main__.Kls'>,)
下面这个图解释了以上代码是怎么运行的:
http://www.zhihu.com/question/20021164
亓项复方: 今天刚看了流畅的python,里面有一章就讲到这两个的具体用例.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 ...
梅列区13359186678: python的class中的object是什么意思 - ?
亓项复方: object 是指这个类继承的最顶级的对象.python3.x 中已经可以省略object,可直接 class Sample(): pass
梅列区13359186678: Python中的模块和包的区别 - ?
亓项复方: 1、模块(Module)就是包含代码的文件,不一定是Python代码,有四种代码类型的模块: •使用Python写的程序( .py文件)•C或C++扩展(已编译为共享库或DLL文件) •包(包含多个模块) •内建模块(使用C编写并已链接到Python解...
梅列区13359186678: 在python里 np.cumsum这个命令是干嘛的,怎么用啊? - ?
亓项复方: 累计求和的命令.具体例子如下所示:1 2 3 4 5 6 7 8 9 10 11 12 13 14>>> a =np.array([[1,2,3], [4,5,6]]) >>> a array([[1, 2, 3],[4, 5, 6]]) >>> np.cumsum(a) array([ 1, 3, 6, 10, 15, 21]) >>> np.cumsum(a, dtype=float) # specifies type of output value(...
梅列区13359186678: python中的 -- name- - =="--main--"是什么意思呢 - ?
亓项复方: __name__为python程序内置属性 __name__为__main__时表示程序作为主程序执行,而不是使用import 作为模块导入
梅列区13359186678: Python中静态方法和类方法的区别 - ?
亓项复方: 面相对象程序设计中,类方法和静态方法是经常用到的两个术语.逻辑上讲:类方法是只能由类名调用;静态方法可以由类名或对象名进行调用.在C++中,静态方法与类方法逻辑上是等e79fa5e98193e59b9ee7ad9431333361323532价的,...
梅列区13359186678: python中init方法中定义的 -- metaclass--=xxx的作用? - ?
亓项复方: __metaclass__是Python2的写法,代表指定该类的元类.Python3中对应的写法是class 要定义的类名(metaclass=元类名) 元类是生成类的工厂,就像类是生成对象实例的工厂.在Python中所有类的默认元类是type,如果需要自定义类的生成方式,例如给类添加特定的属性,那么就需要替换默认元类为你自己编写的元类,此时就要用到metaclass语法.一个重要的利用场景就是ORM框架,因为数据库模型类的编写者是无法预知这个类可能有哪些字段的,所以必须要利用元类动态地生成这个类. 关于元类的说明可以看:网页链接
梅列区13359186678: Python中class与type有什么区别? - ?
亓项复方: 我看是这样的 Python 2.7.13 (default, Sep 26 2018, 18:42:22) [GCC 6.3.0 20170516] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> type('Hello, world!') <type 'str'>Python 3.5.3 (default, Sep 27 2018, ...
梅列区13359186678: 如何调用另一个python文件中的代码 - ?
亓项复方: 运行python_a.py文件 python_a.py文件代码:# -*- coding: utf-8 -*- import python_b #引入所有 from python_b import class_b #引入其中一个类# 调用一个函数 python_b.fun_b()# 新建实例 cb = class_b() cb.fun_c()python_b.py文件中代码:# -*- coding: utf-8 -*- def fun_b(): print('我被python_a调用了!') class class_b(): def fun_c(self): print('我被python_a调用了!')
梅列区13359186678: python中main()可不可以换成别的名字 - ?
亓项复方: - 楼上……========================== 完全不需要main.你可以换成你喜欢的名字.由于python是以缩进来判断程序段,完全不需要main来指导程序首先执行模块.对于任意一个py文件(也是模块),在执行或者import的时候会自动执行...