面向对象高级编程
春花不红不如草,少年不美不如老。
限制实例的属性 slot
- 使用__slots__这样不允许私自增加属性
class Student(obj):
__slot__ = ('name','age') #使用元祖定义允许绑定的属性名称
- 然后测试一下
s = Student()
s.name = 'Mike'
s.age = 18
s.score = 25
# 这样直接报错
由于 ‘score’ 没有放到slot中,所以不能绑定 score 属性,所以报错误
要注意的是 __slot__定义的属性仅仅对当前类的实例起作用,对继承的子类是不起作用的
- 比如
class GraduateStudent():
pass
g = GraduateStudent()
g.score = 9999
@property 装饰器负责把方法当成限制属性调用的
- @property 属性
class Student(obj):
@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 be between 0 to 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 = 999
# 这样就报错误
- @property 还可以定义只读属性,只定义 getter 方法,不定义 setter 方法就是个只读属性
class Student(obj):
@property
def birth(self):
return self._birthday
@birth.setter
def birth(self,value):
self._birth = value
@property
def age(self):
return 2015 - self._birth
上面的 birth 就是可读写的 下面的 age 只能是可读的属性
@property 广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查
多重继承
- 有的时候我们需要一个类继承好多个基类,用法类似
class Man():
pass
class Woman():
pass
class Person(Man,Woman):
pass
通过多重继承一个子类就可以同时获取多个父类的所有功能
定制类
- __str__ 返回一个用户看的懂的字符串,它必须和 print 结合使用
我们先定义了一个 Student 类,打印实例
class Student():
def __init__(self,value):
self.name = name
def __str__(self):
return 'Student object(name:%s' %self.name)
print(Student('Mike'))
- __call__ 一个对象实例可以又自己的属性和方法,当我们调用实例方法后,我们用 instance.method()来调用,自己掉自己
class Student():
def __init__(self,name):
self.name = name
def __call__(self):
print('My name is $s' % self.name)
# 调用方式
# s = Student('Mike')
# s() # self参数不要传入
# My name is Mike
调用了 call 方法你完全可以把类当作一个方法,自己调自己
@classmethod 和@staticmethod 区别
- 看代码
class test:
class_name = "test"
def __init__(self, name):
self.class_name = name
def my_print(self, value):
print(value + " " +self.class_name)
@staticmethod
def my_static_print(val):
print(val)
@classmethod
def my_class_print(cls, val):
print(val +" "+ cls.class_name)
if __name__ == "__main__":
my_test = test("xxx")
test.my_static_print("static print")
test.my_class_print("class print")
my_test.my_static_print("static print")
my_test.my_class_print("class print")
my_test.my_print("my_print")
- 最后结果
static print
class print test
static print
class print test
my_print xxx
- 总结
classmathod 必须要传入一个 cls 参数,这个参数就代表类本身,后面跟的是值
staticmethod 则完全没必要
- 记忆
如果你定义了一个方法它的返回值和类的属性以及实例无关,结果永远不变 那就用@staticmethod
如果你定义了一个方法它的返回值只和类的属性有关,结果可变.那就用@classmethod