# encoding: utf-8
'''
1. python约定类定义中"__"开头(至多一个"_"结尾)的属性为"相对"的私有属性
2. 私有属性在类及其子类定义中是"可见"的,在 其它范围正常访问是相对"不可见"的
3. 留下子类可以修改父类私有属性的口子方便debug测试等
4. 在类定义以外可以通过['_'+className+'私有属性名称']名称访问
5. 私有属性引入是避免类,实例等混淆和冲突,私有属性受大家"规约"约束,所以是相对的
6. 在类定义以外类似"类.私有属性"相关操作可以近似理解为类"新增"对应类属性,并在所在上下文"有效"
7. "有效"的私有属性对后续同一上下文中的类和子类实例对应属性有直接影响
8. 注意子类override父类非私有属性的情况以及类定义以外类"新增"属性时后续子类对应属性
Created on 2015年9月4日
@author: LaughLast
'''
import unittest2
_INT_DIRECT_CHANGED_TO = 3333
_INT_CHANGED_BY_INSTANCE = 3000
_CLS_PRIVATE_ATTR = '__private_cls_attr'
_CLS_NON_PRIVATE_ATTR = 'non_private_cls_attr'
class Sample(object):
'''simple class with class attribute'''
# private attribute
__private_cls_attr = 3
# non private attribute
non_private_cls_attr = 3
def __init__(self):
self.init_attribute_x = 1
self.init_attribure_y = 1
def add(self):
return self.__private_cls_attr + self.non_private_cls_attr
@classmethod
def get__private_cls_attr(cls):
return cls.__private_cls_attr
@classmethod
def get_non_private_cls_attr(cls):
return cls.non_private_cls_attr
@classmethod
def initvalue(cls, p, np):
cls.__private_cls_attr = p
cls.non_private_cls_attr = np
class SampleSubCls(Sample):
# private attribute
__private_cls_attr = 33
# non private attribute
non_private_cls_attr = 33
class ClassAttributePrivateOrNotDifference(unittest2.TestCase):
def setUp(self):
'''make sure the same context of critical attr values
'''
Sample.initvalue(3, 3)
SampleSubCls.initvalue(33, 33)
assert Sample.get__private_cls_attr() is 3 \
and Sample.get_non_private_cls_attr() is 3
assert SampleSubCls.get__private_cls_attr() is 33 \
and SampleSubCls.get_non_private_cls_attr() is 33
def test_private_attr_definition_convention(self):
'''actual complex name of private attr with in cls'''
internal__class_int = '_' + Sample.__name__ + _CLS_PRIVATE_ATTR
assert hasattr(Sample, internal__class_int) is True
assert getattr(Sample, internal__class_int) is Sample.get__private_cls_attr()
internal__subclass_int = '_' + SampleSubCls.__name__ + _CLS_PRIVATE_ATTR
assert hasattr(SampleSubCls, internal__subclass_int) is True
assert getattr(SampleSubCls, internal__subclass_int) is SampleSubCls.get__private_cls_attr()
def test_hasattr_diff(self):
'''cls private attr sees as "invisible" out of its cls definition
ref: hasattr(cls,private_attr) return False
'''
assert hasattr(Sample, _CLS_PRIVATE_ATTR) is False \
and hasattr(Sample, _CLS_NON_PRIVATE_ATTR) is True
assert hasattr(SampleSubCls, _CLS_PRIVATE_ATTR) is False\
and hasattr(SampleSubCls, _CLS_NON_PRIVATE_ATTR) is True
def test_class_dotted_assignment_effects_on_class(self):
'''cls dotted assignment to private attr out of cls definition
sees as a "new" attr of the running context away from original
notice the difference of sub cls
'''
Sample.__private_cls_attr = _INT_DIRECT_CHANGED_TO
Sample.non_private_cls_attr = _INT_DIRECT_CHANGED_TO
assert Sample.get__private_cls_attr() is 3,\
'original value of private attr in cls definition must be unchanged'
assert Sample.get_non_private_cls_attr() is _INT_DIRECT_CHANGED_TO,\
'original value of non private attr in cls definition must be changed'
assert SampleSubCls.get__private_cls_attr() is 33,\
'super cls private attr can be changed in sub cls definition,\
on the contrary,Nope'
assert SampleSubCls.__private_cls_attr is _INT_DIRECT_CHANGED_TO,\
'super cls has a "new" private attr in the context,so does sub cls'
assert SampleSubCls.non_private_cls_attr is 33\
and SampleSubCls.get_non_private_cls_attr() is 33,\
'sub cls overrided non private attr in super cls and kept it within itself'
def test_class_dotted_assignment_effects_on_instance(self):
'''cls dotted assignment to attr out of cls definition generally\
changes the relative attr of instance in the same running context\
notice the difference of sub cls
'''
Sample.__private_cls_attr = _INT_DIRECT_CHANGED_TO
Sample.non_private_cls_attr = _INT_DIRECT_CHANGED_TO
assert Sample().__private_cls_attr is _INT_DIRECT_CHANGED_TO \
and Sample().non_private_cls_attr is _INT_DIRECT_CHANGED_TO,\
'the same changes of cls "new" attr must be made to its instance'
instance = Sample()
instance.__private_cls_attr = _INT_CHANGED_BY_INSTANCE
instance.non_private_cls_attr = _INT_CHANGED_BY_INSTANCE
assert Sample.__private_cls_attr is _INT_DIRECT_CHANGED_TO \
and Sample.non_private_cls_attr is _INT_DIRECT_CHANGED_TO,\
'the changes of instance "new" attr must not be made to its cls'
assert SampleSubCls().__private_cls_attr is _INT_DIRECT_CHANGED_TO, \
'super cls has a "new" private attr in context,so do sub cls and its instance'
assert SampleSubCls.get_non_private_cls_attr() is 33\
and SampleSubCls().non_private_cls_attr is 33,\
'sub cls overrided non private attr in super cls and kept it within itself'
instance_sub = SampleSubCls()
instance_sub.__private_cls_attr = _INT_CHANGED_BY_INSTANCE
instance_sub.non_private_cls_attr = _INT_CHANGED_BY_INSTANCE
assert Sample.__private_cls_attr is _INT_DIRECT_CHANGED_TO \
and Sample.non_private_cls_attr is _INT_DIRECT_CHANGED_TO,\
'the changes of instance "new" attr must not be made to its super cls'
if __name__ == '__main__':
unittest2.main()