一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法
。而使用@staticmethod
或@classmethod
,就可以不需要实例化,直接类名.方法名()
来调用。
这有利于组织代码,把某些应该属于某个类的函数给放到那个类里去,同时有利于命名空间的整洁。
既然@staticmethod和@classmethod都可以直接类名.方法名()来调用,那他们有什么区别呢?
从它们的使用上来看,
@staticmethod
不需要表示自身对象的self和自身类的cls参数,就跟使用普通函数一样。
@classmethod
也不需要self参数,但第一个参数需要是表示自身类的cls参数
。
如果在@staticmethod
中要调用到这个类的一些属性方法,只能直接类名.属性名
或类名.方法名
。
而@classmethod
因为持有cls参数,可以来调用类的属性,类的方法,实例化对象等,避免硬编码。
class A(object):
bar = 1
def foo(self): # self代表调用该方法的 当前的类对象
print 'foo'
@staticmethod
def static_foo(): # 注意参数列表形式
print 'static_foo'
print A.bar # 注意调用方式
@classmethod
def class_foo(cls): # 注意参数列表形式,cls代表调用该方法的类本身
print 'class_foo'
print cls.bar # # 注意调用方式
cls().foo() # 注意调用方式
###执行
A.static_foo()
A.class_foo()
输出
static_foo
1
class_foo
1
foo
staticmethod用于修饰类中的方法,使其可以在不创建类实例的情况下调用方法,这样做的好处是执行效率比较高。当然,也可以像一般的方法一样用实例调用该方法。
该方法一般被称为静态方法。静态方法不可以引用类中的属性或方法
,其参数列表也不需要约定的默认参数self
。
我个人觉得,静态方法就是类对外部函数的封装,有助于优化代码结构和提高程序的可读性(把类内常用到的外部函数放在类内,方便维护)。当然了,被封装的方法应该尽可能的和封装它的类的功能相匹配。
class Time():
def __init__(self,sec):
self.sec = sec
#声明一个静态方法
@staticmethod
def sec_minutes(s1,s2):
#返回两个时间差
return abs(s1-s2)
#分别使用类名调用和使用实例调用静态方法
print("----------------------不通过例化的方法调用----------")
print(Time.sec_minutes(10,5)) #类直接调用
#结果为5 5
t = Time(10) #先实例化类,即对象
print("----------------------通过例化方法调用----------")
print(t.sec_minutes(t.sec,5)) #通过对象进行调用
classmethod是用来指定一个类的方法为类方法,长的像下面这个样子:
class cc:
@classmethod
def f(cls, arg1, arg2, ...): ...
cls通常用作类方法的第一参数 跟self有点类似( __init__里面的slef通常用作实例方法的第一参数)。即通常用self来传递当前类的实例–对象,cls传递当前类。
self 和cls 没有特别的含义,作用只是把参数绑定到普通的函数上, 不一定非得是self 或cls,可以换成别的xxx。
那么为什么会出现classmethod?
classmethod设计的目的是什么呢?事实上与Python面向对象编程有关的,由于Python不支持多个的參数重载构造函数,比方在C++里,构造函数能够依据參数个数不一样。能够写多个构造函数。Python为了解决问题,採用classmethod修饰符的方式,这样定义出来的函数就能够在类对象实例化之前调用这些函数,就相当于多个构造函数,解决多个构造函数的代码写在类外面的问题;
类最基本的作用是实例化出一个对象,但是有的时候再实例化之前,就需要先和类做一定的交互,这种交互可能会影响实际实例化的过程,所以必须放在调用构造函数之前。大概也可能是因为这个原因出现了classmethod;
直接一点来说,我们知道对于一个普通的类,我们要使用其中的函数的话,需要对类进行实例化,而一个类中,某个函数前面加上了staticmethod或者classmethod的话,那么这个函数就可以不通过实例化直接调用,可以通过类名进行调用的;
@classmethod 定义的类方法是可选构造函数中,我们定义了一个类方法,类方法的第一个参数(cls)指代的就是类本身。类方法会用这个类来创建并返回最终的实例。使用类方法的另一个好处就是在继承的时候,保证了子类使用可选构造函数构造出来的类是子类的实例而不是父类的实例。
class Data_test(object):
day=0
month=0
year=0
def __init__(self,year=0,month=0,day=0):
self.day=day
self.month=month
self.year=year
def out_date(self):
print "year :"
print self.year
print "month :"
print self.month
print "day :"
print self.day
t=Data_test(2016,8,1)
t.out_date()
输出:
year :
2016
month :
8
day :
1
符合期望。
如果用户输入的是 "2016-8-1" 这样的字符格式,那么就需要调用Date_test 类前做一下处理:
string_date='2016-8-1'
year,month,day=map(int,string_date.split('-'))
s=Data_test(year,month,day)
先把‘2016-8-1’ 分解成 year,month,day 三个变量,然后转成int,再调用Date_test(year,month,day)函数。 也很符合期望。
那我可不可以把这个字符串处理的函数放到 Date_test 类当中呢?
那么@classmethod 就开始出场了
class Data_test2(object):
day=0
month=0
year=0
def __init__(self,year=0,month=0,day=0):
self.day=day
self.month=month
self.year=year
@classmethod
def get_date(cls,data_as_string):
#这里第一个参数是cls, 表示调用当前的类名
year,month,day=map(int,string_date.split('-'))
date1=cls(year,month,day)
#返回的是一个初始化后的类
return date1
def out_date(self):
print "year :"
print self.year
print "month :"
print self.month
print "day :"
print self.day
在Date_test类里面创建一个成员函数, 前面用了@classmethod装饰。 它的作用就是有点像静态类,比静态类不一样的就是它可以传进来一个当前类作为第一个参数。
那么如何调用呢?
r=Data_test2.get_date("2016-8-6")
r.out_date()
输出:
year :
2016
month :
8
day :
1
这样子等于先调用get_date()对字符串进行出来,然后才使用Data_test的构造函数初始化。
这样的好处就是你以后重构类的时候不必要修改构造函数,只需要额外添加你要处理的函数,然后使用装饰符 @classmethod 就可以了。
Python中访问对象的属性可以这么做:实例名.变量名!!@property是python的一种装饰器,是用来修饰方法的。
作用:
我们可以使用@property装饰器来创建只读属性,@property装饰器会将方法转换为相同名称的只读属性,可以与所定义的属性配合使用,这样可以防止属性被修改。
通俗理解:
可以使用@property装饰器将方法伪装成 属性 的样式使用
@property
下方的函数只能是self参数
,不能有其他的参数,property 常和私有属性相结合使用
。
class DataSet(object):
@property
def method_with_property(self): ##含有@property
return 15
def method_without_property(self): ##不含@property
return 15
l = DataSet()
print(l.method_with_property) # 加了@property后,可以用调用属性的形式来调用方法,后面不需要加()。
print(l.method_without_property()) #没有加@property , 必须使用正常的调用方法的形式,即在后面加()
两个都输出为15。
由于python进行属性的定义时,没办法设置私有属性,因此要通过@property的方法来进行设置。这样可以隐藏属性名,让用户进行使用的时候无法随意修改。
class DataSet(object):
def __init__(self):
self._images = 1
self._labels = 2 #定义属性的名称
@property
def images(self): #方法加入@property后,这个方法相当于一个属性,这个属性可以让用户进行使用,而且用户有没办法随意修改。
return self._images
@property
def labels(self):
return self._labels
l = DataSet() #用户进行属性调用的时候,直接调用images即可,而不用知道属性名_images,因此用户无法更改属性,从而保护了类的属性。
print(l.images) # 加了@property后,可以用调用属性的形式来调用方法,后面不需要加()。