property
是将一个方法变成属性
class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
@property的实现比较复杂,我们先考察如何使用。把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作:
>>> s = Student()
>>> s.score = 60 # OK,实际转化为s.set_score(60)
>>> s.score # OK,实际转化为s.get_score()
60
>>> s.score = 9999
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!
注意到这个神奇的@property,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴露的,而是通过getter和setter方法来实现的。
还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性:
class Student(object):
@property
def birth(self):
return self._birth
@birth.setter
def birth(self, value):
self._birth = value
@property
def age(self):
return 2014 - self._birth
上面的birth是可读写属性,而age就是一个只读属性,因为age可以根据birth和当前时间计算出来。
staticmethod &&
staticmethod和classmethod的区别:
@staticmethod 不需要访问和类相关的属性或数据(感觉只是概念上的区别,你这样声明了用的人就知道了,如果你非要在这个方法中访问test.xxx 它就和@classmethod的作用一样了。)
@classmethod 可以访问和类相关(不和实例相关)的属性,看 test.my_class_print("class print") 和 my_test.my_class_print("class print") 的结果都是class中定义的class_name 的值,非实例的值:xxx
如果你定义了一个方法它的返回值永远和类的属性及实例无关,结果永远不变,就用@staticmethod
如果你定义了一个方法它的返回值和只和类的属性有关,结果可变(比如上例,我用test.class_name="AAA"改变类的属性值,my_class_print输出的结果就改变了) .就用@classmethod
class Date:
hour = 1
def __init__(self,year,month,day):
self.year = year
self.month = month
self.day = day
def tomorrow(self): #实例方法
self.day += 1 #修改的当前实例的值,不影响类和其他实例
Date.hour +=1
#修改的是类变量的值,只要有实例改变这个值,这个类和其他的实例的该值都会变化
# 如果有值修改过这个值,后续所有该类的实例和该类的这个值都会是修改过后的值。
@staticmethod
def parse_from_str(date_str): #静态方法不需要接收self,函数的调用需要加Date
year,month,day = tuple(date_str.split('-'))
# return Date(int(year),int(month),int(day))
return 123
# 静态方法直接使用类调用就可以,实例也是可以进行调用的,但是类是无法调用实例方法
# 静态方法缺点: return Date(int(year),int(month),int(day)) ,Date是硬编码,如果类名修改了,这里就会报错
# 静态方法优点: 可以写一些属于该类的代码逻辑在里面
@classmethod
def from_string(cls, date_str):
year, month, day = tuple(date_str.split('-')) # 类方法直接使用类调用就可以,实例也是可以进行调用的,但是类是无法调用实例方法
return cls(int(year), int(month), int(day)) # 优点:修改了硬编码的方式,类的名称可以随意去修改
def __str__(self):
return "{year}/{month}/{day}/{hour}".format(year=self.year,month=self.month,day=self.day,hour=self.hour)
# 定义__str__,在打印实例对象(调用)的时候默认输出__str__,不加上__str__方法的时候,调用print是输出实例对象
if __name__=="__main__":
new_day3= Date(2018, 11, 22)
print(new_day3)
new_day = Date(2018,11,22)
new_day.tomorrow()
print(new_day)
print(Date(2018,11,22))
new_day1 = Date(2018, 11, 22)
print(new_day1)
new_day = Date(2018, 11, 22)
print(new_day)
静态方法:@staticmethod
类方法 @classmethod 好处:不用实例化也是可以获取到该方法(编写该类里面的部分逻辑)