Project

General

Profile

Организация доступа к атрибутам классов в 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!