python 类方法和静态方法区别

python @classmethod和@staticmethod区别

Python中至少有三种比较常见的方法类型,即实例方法,类方法、静态方法。它们是如何定义的呢?如何调用的呢?它们又有何区别和作用呢?且看下文。

首先,这三种方法都定义在类中。下面我先简单说一下怎么定义和调用的。(PS:实例对象的权限最大。)

实例方法

定义:第一个参数必须是实例对象,该参数名一般约定为“self”,通过它来传递实例的属性和方法(也可以传类的属性和方法);

调用:只能由实例对象调用。

类方法

定义:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法);

调用:实例对象和类对象都可以调用。

静态方法

定义:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法

调用:实例对象和类对象都可以调用。

类方法

使用装饰器@classmethod。

原则上,类方法是将类本身作为对象进行操作的方法。假设有个方法,且这个方法在逻辑上采用类本身作为对象来调用更合理,那么这个方法就可以定义为类方法。另外,如果需要继承,也可以定义为类方法。

如下场景:

假设我有一个学生类和一个班级类,想要实现的功能为:
    执行班级人数增加的操作、获得班级的总人数;
    学生类继承自班级类,每实例化一个学生,班级人数都能增加;
    最后,我想定义一些学生,获得班级中的总人数。

思考:这个问题用类方法做比较合适,为什么?因为我实例化的是学生,但是如果我从学生这一个实例中获得班级总人数,在逻辑上显然是不合理的。同时,如果想要获得班级总人数,如果生成一个班级的实例也是没有必要的。

class ClassTest(object):
__num = 0 @classmethod
def addNum(cls):
cls.__num += 1 @classmethod
def getNum(cls):
return cls.__num # 这里我用到魔术方法__new__,主要是为了在创建实例的时候调用累加方法。
def __new__(self):
ClassTest.addNum()
return super(ClassTest, self).__new__(self) class Student(ClassTest):
def __init__(self):
self.name = '' a = Student()
b = Student()
print(ClassTest.getNum())

静态方法

使用装饰器@staticmethod。

静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作。可以理解为,静态方法是个独立的、单纯的函数,它仅仅托管于某个类的名称空间中,便于使用和维护。

譬如,我想定义一个关于时间操作的类,其中有一个获取当前时间的函数。

import time

class TimeTest(object):
def __init__(self, hour, minute, second):
self.hour = hour
self.minute = minute
self.second = second @staticmethod
def showTime():
return time.strftime("%H:%M:%S", time.localtime()) print(TimeTest.showTime())
t = TimeTest(2, 10, 10)
nowTime = t.showTime()
print(nowTime)

如上,使用了静态方法(函数),然而方法体中并没使用(也不能使用)类或实例的属性(或方法)。若要获得当前时间的字符串时,并不一定需要实例化对象,此时对于静态方法而言,所在类更像是一种名称空间。

其实,我们也可以在类外面写一个同样的函数来做这些事,但是这样做就打乱了逻辑关系,也会导致以后代码维护困难。

类方法里面可以操作:类方法,静态方法,实例方法

静态方法里面可以操作:类方法,静态方法,实例方法

class Foo(object):
X = 1
Y = 2 def obj_func(self):
print('我是一个实例方法')
return '我是一个实例方法,我将被类方法,静态方法调用' @staticmethod
def averag(*mixes):
foo1 = Foo()
foo1.obj_func()
return sum(mixes) / len(mixes) @staticmethod
def static_method(): # 在静态方法中调用静态方法
print("在静态方法中调用静态方法")
return Foo.averag(Foo.X, Foo.Y) @staticmethod
def static_method1():
print("在静态方法中调用类方法")
return Foo.class_method0() @classmethod
def class_method0(cls):
print("我是一个类方法:classmethod, 我将被静态方法调用")
foo2 = Foo()
return foo2.obj_func() @classmethod
def class_method1(cls): # 在类方法中使用静态方法
print("在类方法中使用静态方法")
return cls.averag(cls.X, cls.Y) foo = Foo()
print(foo.static_method1())
print('*****************************')
print(foo.class_method1())

输出:

在静态方法中调用类方法
我是一个类方法:classmethod, 我将被静态方法调用
我是一个实例方法
我是一个实例方法,我将被类方法,静态方法调用
*****************************
在类方法中使用静态方法
我是一个实例方法
1.5
class Test(object):
def InstanceFun(self):
print("InstanceFun")
print(self) @classmethod
def ClassFun(cls):
print("ClassFun")
print(cls) @staticmethod
def StaticFun():
print("StaticFun")
t = Test()
t.InstanceFun()   # 输出InstanceFun,打印对象内存地址“<__main__.Test object at 0x0293DCF0>”
Test.ClassFun() # 输出ClassFun,打印类位置 <class '__main__.Test'>
Test.StaticFun() # 输出StaticFun
t.StaticFun() # 输出StaticFun
t.ClassFun() # 输出ClassFun,打印类位置 <class '__main__.Test'>
Test.InstanceFun() # 错误,TypeError: unbound method instanceFun() must be called with Test instance as first argument
Test.InstanceFun(t) # 输出InstanceFun,打印对象内存地址“<__main__.Test object at 0x0293DCF0>”
t.ClassFun(Test) # 错误 classFun() takes exactly 1 argument (2 given)

继承类中的区别

从下面代码可以看出,如果子类继承父类的方法,子类覆盖了父类的静态方法,
子类的实例继承了父类的static_method静态方法,调用该方法,还是调用的父类的方法和类属性。
子类的实例继承了父类的class_method类方法,调用该方法,调用的是子类的方法和子类的类属性。

class Foo(object):
X = 1
Y = 14 @staticmethod
def averag(*mixes): # "父类中的静态方法"
return sum(mixes) / len(mixes) @staticmethod
def static_method(): # "父类中的静态方法"
print "父类中的静态方法"
return Foo.averag(Foo.X, Foo.Y) @classmethod
def class_method(cls): # 父类中的类方法
print "父类中的类方法"
return cls.averag(cls.X, cls.Y) class Son(Foo):
X = 3
Y = 5 @staticmethod
def averag(*mixes): # "子类中重载了父类的静态方法"
print "子类中重载了父类的静态方法"
print "666 ",mixes
return sum(mixes) / 3 p = Son()
print "result of p.averag(1,5)"
print (p.averag(1,5))
print "result of p.static_method()"
print(p.static_method())
print "result of p.class_method()"
print(p.class_method())

输出:

result of p.averag(1,5)
子类中重载了父类的静态方法
666 (1, 5)
2
result of p.static_method()
父类中的静态方法
7
result of p.class_method()
父类中的类方法
子类中重载了父类的静态方法
666 (3, 5)
2

classmethod与staticmethod

这两个方法的用法是类似的,在上面的例子中大多数情况下,classmethod也可以通过staticmethod代替,在通过类调用时,这两者对于调用者来说是不可区分的。

这两者的区别在于,classmethod增加了一个对实际调用类的引用,这带来了很多方便的地方:

  1. 方法可以判断出自己是通过基类被调用,还是通过某个子类被调用
  2. 通过子类调用时,方法可以返回子类的实例而非基类的实例
  3. 通过子类调用时,方法可以调用子类的其他classmethod

一般来说classmethod可以完全替代staticmethod。staticmethod唯一的好处是调用时它返回的是一个真正的函数,而且每次调用时返回同一个实例(classmethod则会对基类和子类返回不同的bound method实例),但这点几乎从来没有什么时候是有用的。不过,staticmethod可以在子类上被重写为classmethod,反之亦然,因此也没有必要提前将staticmethod全部改为classmethod,按需要使用即可。

python @classmethod和@staticmethod区别的更多相关文章

  1. python classmethod 和 staticmethod的区别

    https://stackoverflow.com/questions/12179271/meaning-of-classmethod-and-staticmethod-for-beginner 1. ...

  2. Fluent Python: Classmethod vs Staticmethod

    Fluent Python一书9.4节比较了 Classmethod 和 Staticmethod 两个装饰器的区别: 给出的结论是一个非常有用(Classmethod), 一个不太有用(Static ...

  3. Python @classmethod和@staticmethod装饰器使用介绍

    @classmethod和@staticmethod装饰器使用介绍 by:授客 QQ:1033553122 简介 静态方法:类中用 @staticmethod装饰的不带 self 参数的方法.类的静态 ...

  4. Python中classmethod与staticmethod区别

    classmethod:类方法staticmethod:静态方法 在python中,静态方法和类方法都是可以通过类对象和类对象实例访问.但是区别是: @classmethod 是一个函数修饰符,它表示 ...

  5. Python的classmethod和staticmethod区别

    静态方法(staticmethod) 类方法(classmethod) 静态方法和类方法都可以通过类名.方法名或者实例.方法访问. #-*- coding:utf8 -*- class A(objec ...

  6. classmethod和staticmethod区别

    实例方法:在类中,定义的方法,这个方法的第一个参数默认是实例对象,一般习惯使用self 类方法:在类中,定义的方法,这个方法的第一个参数默认是类对象,一般习惯用cls表示,用@classmethod装 ...

  7. @classmethod 与 @staticmethod 区别

  8. python -- @classmethod @staticmethod区别和使用

    python中的定义: class MyClass: ... @classmethod  # classmethod的修饰符 def class_method(cls, arg1, arg2, ... ...

  9. 面试题:python 中 staticmethod 和 classmethod有什么区别

    面试中经常会问到staticmethod 和 classmethod有什么区别? 首先看下官方的解释: staticmethod: class staticmethod staticmethod(fu ...

随机推荐

  1. java-Java实现mysql事务处理操作

    数据库事务(简称:事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成. 并非任意的对数据库的操作序列都是数据库事务.数据库事务拥有以下四个特性,习惯上被称之为ACID特性. ...

  2. 常用docker管理UI

    1. HumpBacks 特性 Web UI Supporting, Easy to use. Container Grouping and Isolation. Container Upgrades ...

  3. HotSpot虚拟机的锁优化

    面试中多次被问到synchronized关键字的实现原理,一直认为仅是monitorenter与monitorexit两条指令而已,原来底层涉及到多种锁优化策略,包括:自旋锁,轻量锁,偏向锁. 1.自 ...

  4. Python包模块化调用方式详解

    Python包模块化调用方式详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一般来说,编程语言中,库.包.模块是同一种概念,是代码组织方式. Python中只有一种模块对象类型 ...

  5. db2 mysql oracle 邮件 tomcat ssh telnet ftp samba 账号密码

    db2 mysql oracle 邮件 tomcat ssh telnet ftp samba 账号密码 检测

  6. Vuex 是什么?

    Vuex 是什么? Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件状态,并以相应的规则保证状态以一种可预测的方式发生变   什么是"状态管 ...

  7. 1220 Vue与Django前后端的结合

    目录 vue的安装 Vue前端的设置 页面的分布 后台数据的替换 css样式 Django的配置 国际化配置 axios插件安装 CORS跨域问题(同源策略) 处理跨域问题: cors插件 axios ...

  8. Convert 输入字符串的格式不正确

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Cons ...

  9. Pivotal Greenplum 6.0 新特性介绍

    Pivotal Greenplum 6.0 新特性介绍   在1月12日举办的Greenplum开源有道智数未来技术研讨会上,Pivotal中国研发中心Greenplum 产品经理李阳向大家介绍了Pi ...

  10. 【洛谷P4931】 情侣?给我烧了!(加强版)组合计数

    挺有意思的一道题... code: #include <bits/stdc++.h> using namespace std; #define N 5000006 #define mod ...