Организация доступа к атрибутам классов в Python¶
BUG: Язык программирования Python не поддерживает важную составляющую объектно-ориентированного подхода программирования: инкапсуляцию.
Мы считаем, что поддержка данного подхода необходима для создания качественных приложений.
<Тут мы придумали design by contract и написали BaseObject>
Ниже представлены примеры использования BaseObject для реализации различного уровня доступа к атрибутам класса.
Для проверки доступа можно использовать следующий каркас:
__READ_TEST=0 __WRITE_TEST=1 def makeTest(type, name, function): message = 'Value of %s is: ' % (name) exceptMessage = 'Got an exception while tried to read ' + name if type == __WRITE_TEST: message = 'Successfully assigned new value to ' + name exceptMessage = 'Got an exception while tried to assign value to ' + name try: returnValue = function() print '%s %s' % (message, unicode(returnValue)) except AttributeError: print exceptMessage print 'Exception message: ' + unicode(sys.exc_info()[1])
Полное ограничение доступа к атрибуту¶
Реализация:
<code class=java> class SimpleNoAccess(BaseObject): def __init__(self): self.hidevar = 'Hidden value' </code>
Проверочные функции для каркаса:
<code class=java> def readSimpleNoAccsess(): simpleClass = SimpleNoAccess() return simpleClass.hidevar def writeSimpleNoAccsess(): simpleClass = SimpleNoAccess() simpleClass.hidevar = 'New value' makeTest(__READ_TEST, 'hidden attribute', readSimpleNoAccsess) makeTest(__WRITE_TEST, 'hidden attribute', writeSimpleNoAccsess) </code>
Результат выполнения:
Got an exception while tried to read hidden attribute Exception message: hidevar is not a readable attribute! Got an exception while tried to assign value to hidden attribute Exception message: hidevar is not an attribute!
Простое чтение ссылки атрибута¶
Реализация:
<code class=java> class SimpleReadOnly(BaseObject): def __init__(self): self.readOnly = 'Read-only attribute value' self.readOnlyAttr('readOnly') </code>
Проверочные функции для каркаса:
<code class=java> def readSimpleReadOnly(): simpleReadOnly = SimpleReadOnly() return simpleReadOnly.readOnly def writeSimpleReadOnly(): simpleReadOnly = SimpleReadOnly() simpleReadOnly.readOnly = 'New read-only attibute value' makeTest(__READ_TEST, 'simple read-only attribute', readSimpleReadOnly) makeTest(__WRITE_TEST, 'simple read-only attribute', writeSimpleReadOnly) </code>
Результат выполнения:
Value of simple read-only attribute is: Read-only attribute value Got an exception while tried to assign value to simple read-only attribute Exception message: readOnly is not an attribute!
Доступ к атрибутам только на чтение с помощью property()¶
Реализация:
<code class=java> class ComplexReadOnly(BaseObject): def __init__(self): self._readOnlyList= list('Initial value') self.readOnlyAttr('readOnlyList') def getReadOnlyList(self): ''' Public getter of a read-only list attribute ''' return list(self._readOnlyList) readOnlyList = property(getReadOnlyList,None,None,'The read only version of a list') </code>
Проверочные функции для каркаса:
<code class=java> def read1ComplexReadOnly(): complexReadOnly = ComplexReadOnly() return complexReadOnly._readOnlyList def read2ComplexReadOnly(): complexReadOnly = ComplexReadOnly() return complexReadOnly.readOnlyList def read3ComplexReadOnly(): complexReadOnly = ComplexReadOnly() return complexReadOnly.getReadOnlyList() def write1ComplexReadOnly(): complexReadOnly = ComplexReadOnly() complexReadOnly._readOnlyList = list('New contents') def write2ComplexReadOnly(): complexReadOnly = ComplexReadOnly() complexReadOnly.readOnlyList = list('New contents') makeTest(__READ_TEST, 'complex RO attribute through direct access', read1ComplexReadOnly) makeTest(__READ_TEST, 'complex RO attribute through property access', read2ComplexReadOnly) makeTest(__READ_TEST, 'complex RO attribute through public method', read3ComplexReadOnly) makeTest(__WRITE_TEST, 'complex RO attribute through direct access', write1ComplexReadOnly) makeTest(__WRITE_TEST, 'complex RO attribute through property access', write2ComplexReadOnly) </code>
Результат выполнения:
Got an exception while tried to read complex RO attribute through direct access Exception message: _readOnlyList is not a readable attribute! Value of complex RO attribute through property access is: ['I', 'n', 'i', 't', 'i', 'a', 'l', ' ', 'v', 'a', 'l', 'u', 'e'] Value of complex RO attribute through public method is: ['I', 'n', 'i', 't', 'i', 'a', 'l', ' ', 'v', 'a', 'l', 'u', 'e'] Got an exception while tried to assign value to complex RO attribute through direct access Exception message: _readOnlyList is not an attribute! Got an exception while tried to assign value to complex RO attribute through property access Exception message: readOnlyList is not an attribute!
Доступ к аттрибуту только на чтение с помощью @property¶
Реализация:
<code class=java> class ComplexReadOnly2(BaseObject): def __init__(self): self._readOnly = 'My value is: initial' self.readOnlyAttr('readOnly') @property def readOnly(self): return self._readOnly </code>
Проверочные функции для каркаса:
<code class=java> def read1ComplexReadOnly2(): complexReadOnly2 = ComplexReadOnly2() return complexReadOnly2._readOnly def read2ComplexReadOnly2(): complexReadOnly2 = ComplexReadOnly2() return complexReadOnly2.readOnly def write1ComplexReadOnly2(): complexReadOnly2 = ComplexReadOnly2() complexReadOnly2._readOnly = 'New value for read only attribute' def write2ComplexReadOnly2(): complexReadOnly2 = ComplexReadOnly2() complexReadOnly2.readOnly = 'New value for read only attribute' makeTest(__READ_TEST, 'complex RO attribute through direct access', read1ComplexReadOnly2) makeTest(__READ_TEST, 'complex RO attribute through property access', read2ComplexReadOnly2) makeTest(__WRITE_TEST, 'complex RO attribute through direct access', write1ComplexReadOnly2) makeTest(__WRITE_TEST, 'complex RO attribute through property access', write2ComplexReadOnly2) </code>
Результат выполнения:
Got an exception while tried to read complex RO attribute through direct access Exception message: _readOnly is not a readable attribute! Value of complex RO attribute through property access is: My value is: initial Got an exception while tried to assign value to complex RO attribute through direct access Exception message: _readOnly is not an attribute! Got an exception while tried to assign value to complex RO attribute through property access Exception message: readOnly is not an attribute!
Полный доступ к атрибуту¶
Реализация:
<code class=java> class SimpleFullAccess(BaseObject): def __init__(self): self.fullAccess = 'Full access attribute' self.attribute('fullAccess') </code>
Проверочные функции для каркаса:
<code class=java> def readSimpleFullAccess(): simpleFullAccess = SimpleFullAccess() return simpleFullAccess.fullAccess def writeSimpleFullAccess(): simpleFullAccess = SimpleFullAccess() simpleFullAccess.fullAccess = 'New value for full access attribute' makeTest(__READ_TEST, 'simple full access attribute', readSimpleFullAccess) makeTest(__WRITE_TEST, 'simple full access attribute', writeSimpleFullAccess) </code>
Результат выполнения:
Value of simple full access attribute is: Full access attribute Successfully assigned new value to simple full access attribute None
Полный доступ к атрибуту с помощью property()¶
Реализация:
<code class=java> class ComplexFullAccess(BaseObject): def __init__(self): self._fullAccess = 'My value is: initial' self.attribute('fullAccess') def getFullAccess(self): return self._fullAccess def setFullAccess(self, value): self._fullAccess = 'My value is: %s' % (unicode(value)) fullAccess = property(getFullAccess, setFullAccess, None, 'Fully available attribute') </code>
Проверочные функции для каркаса:
<code class=java> def read1ComplexFullAccess(): complexFullAccess = ComplexFullAccess() return complexFullAccess._fullAccess def read2ComplexFullAccess(): complexFullAccess = ComplexFullAccess() return complexFullAccess.fullAccess def read3ComplexFullAccess(): complexFullAccess = ComplexFullAccess() return complexFullAccess.getFullAccess() def write1ComplexFullAccess(): complexFullAccess = ComplexFullAccess() complexFullAccess._fullAccess = 'Testing' def write2ComplexFullAccess(): complexFullAccess = ComplexFullAccess() complexFullAccess.fullAccess = 'New value' def write3ComplexFullAccess(): complexFullAccess = ComplexFullAccess() complexFullAccess.setFullAccess('New value') makeTest(__READ_TEST, 'complex RW attribute through direct access', read1ComplexFullAccess) makeTest(__READ_TEST, 'complex RW attribute through property access', read2ComplexFullAccess) makeTest(__READ_TEST, 'complex RW attribute through public method', read3ComplexFullAccess) makeTest(__WRITE_TEST, 'complex RW attribute through direct access', write1ComplexFullAccess) makeTest(__WRITE_TEST, 'complex RW attribute through property access', write2ComplexFullAccess) makeTest(__WRITE_TEST, 'complex RM attribute through public method', write3ComplexFullAccess) </code>
Результат выполнения:
Got an exception while tried to read complex RW attribute through direct access Exception message: _fullAccess is not a readable attribute! Value of complex RW attribute through property access is: My value is: initial Value of complex RW attribute through public method is: My value is: initial Got an exception while tried to assign value to complex RW attribute through direct access Exception message: _fullAccess is not an attribute! Successfully assigned new value to complex RW attribute through property access None Successfully assigned new value to complex RM attribute through public method None
Доступ к виртуальному атрибуту с помощью property()¶
Реализация:
<code class=java> class VirtualReadOnly(BaseObject): def __init__(self): self.readOnlyAttr('readOnly') def getReadOnly(self): return 'My value is: ' + unicode(random()) readOnly = property(getReadOnly, None, None, 'Virtual read-only property') </code>
Проверочные функции для каркаса:
<code class=java> def read1VirtualReadOnly(): virtualReadOnly = VirtualReadOnly() return virtualReadOnly.readOnly def read2VirtualReadOnly(): virtualReadOnly = VirtualReadOnly() return virtualReadOnly.getReadOnly() def writeVirtualReadOnly(): virtualReadOnly = VirtualReadOnly() virtualReadOnly.readOnly = 'New value' makeTest(__READ_TEST, 'read only virtual attribute through property access', read1VirtualReadOnly) makeTest(__READ_TEST, 'read only virtual attribute through public method', read2VirtualReadOnly) makeTest(__WRITE_TEST, 'read only virtual attribute through property access', writeVirtualReadOnly) </code>
Результат выполнения:
Value of read only virtual attribute through property access is: My value is: 0.0751941265467 Value of read only virtual attribute through public method is: My value is: 0.897739424629 Got an exception while tried to assign value to read only virtual attribute through property access Exception message: readOnly is not an attribute!