Python是一门动态语言,我们可以程序运行期间做很多事情,可以为对象动态绑定属性,动态绑定方法。所以如果没有一个安全的东西去限制,很容易造成封装后的模块出现严重的问题。
__slots__
防止添加其他未被加入__slots__元组的属性。不过对于子类是不起作用的,除非子类也做__slots__声明
#coding=UTF8 from types import MethodType class Person(object): """测试__slots__功能""" __slots__ = ('name', 'height') # 限制类所能绑定的属性 def __init__(self): super(Person, self).__init__() def printPerson(self): print ('Person') per = Person () per.name = 'Pocket' per.height = 180 # per.age = 23 # 这行会报错,原因是Person类中不存在这样的属性,__slots__中没有添加 per.printPerson() # 这行不会报错,因为__slots__管的不包括内部类函数的声明限制(会管外部函数的动态绑定),只管属性的绑定(内部和外部都限制) def testFun(self): print ("testFun") per.testFun = MethodType (testFun, per, Person) # 报错,因为该函数时动态绑定上的属性 per.testFun() ''' 运行结果: Person Traceback (most recent call last): File "/Users/pocket/Desktop/PythonProject/面向对象练习/dynamic.py", line 46, in <module> per.testFun = MethodType (testFun, per, Person) AttributeError: 'Person' object has no attribute 'testFun' '''
@property
用来在重写类变量的时候用。实现类变量的setter、getter方法,用@property进行修饰,对set和get进行自定义判断操作,比如只允许只读、读写
#coding=UTF8
class Student(object):
"""property"""
def __init__(self):
super(Student, self).__init__()
self.__score = None
self.__name = None
@property # 重写__score属性的getter
def score(self):
return self.__score
@score.setter # 重写__score属性的setter,如果只读的话不用实现@score.setter就好
def score(self, value):
if isinstance(value, int) and value >= 0 and value <= 100: # 一般在setter方法里判断一下需要设置的类型,不对就直接做错误处理
self.__score = value
else:
raise ValueError('value not int or not 0-100')
'''
# 如果不加修饰器,如下这样写,第一个name()函数会被后面同名带参的函数覆盖,相当于第一个函数写的没意义,而且也不能用name()不带参调用,因为会报错提示你参数个数不对
def name(self):
print ('name')
return self.__name;
def name(self, value):
print ('name value')
self.__name = value
'''
def name(self):
print ('name')
return self.__name;
s = Student()
print (type(s.score))
s.score = 56 # setter
print (type(s.score))
print (s.score) # getter
# print (dir(s))
print ('self.__score 的实际分数:%d ' % getattr(s, '_Student__score')) # 与实际值对比
''' 对没有加修饰器的函数测试 '''
print (s.name) # 这一步打印的s.name表示的是类绑定的name函数
s.name = 'Pocket' # 这一步神操作,千万不要这样搞模棱两可,这一步将字符串绑定到name这个属性,使name从函数变成了字符串类型,导致给人感觉setter成功了
print (s.name)
print (type(s.name)) # 打印出name属性是str而不是method了
print ('self.__name 的实际名字:%s ' % getattr(s, '_Student__name')) # 发现屁都没改变,还是None
# s.name() # 当你在调用方法时,发现报错,不可以这样调用,那是因为name不是方法了,是str
# print (dir(s)) # 打印所有属性集合
'''
运行结果:
<type 'NoneType'>
<type 'int'>
56
self.__score 的实际分数:56
<bound method Student.name of <__main__.Student object at 0x102d07910>>
Pocket
<type 'str'>
self.__name 的实际名字:None
'''
'''
结论:
1.就是不要瞎加吧的乱用点语法赋值,@property是作用在属性上的,
使属性重写的setter和getter方法可以便捷的通过点语法调用不是用在普通类函数上的。
'''