Reputation: 19
I am trying to implement a class with the best and safest conventions possible. Are there better ways to
a) prevent external edits to properties, and
b) enforce certain constraints, such as valid rank and suit, on these properties?
class Card:
__ranks = ['Ace', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', 'King']
__suits = ['Heart', 'Club', 'Diamond', 'Spade']
def __init__(self, rank, suit):
assert rank in self.__ranks
assert suit in self.__suits
self.__rank = rank
self.__suit = suit
def getRank(self):
return self.__rank
def getSuit(self):
return self.__suit
Upvotes: 1
Views: 262
Reputation: 12672
It's more common to control this type of behavior through the property decorator. You can essentially create a read-only attribute by not implementing a setter:
class Foo:
def __init__(self, bar):
self._bar = bar
@property
def bar(self):
"""Read-only access to bar."""
return self._bar
I wouldn't bother with the double underscore name mangling. That still won't (and isn't intended to) make attributes inaccessible from the outside.
Upvotes: 1
Reputation: 8212
You could use a named tuple, so that the object is immutable
>>> from collections import namedtuple
>>> Card = namedtuple('Card','rank,suit')
>>> acard = Card('10','D')
>>> acard.suit
'D'
>>> acard.rank
'10'
>>> acard.rank='H'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
>>>
For more information see the namedtuple
documentation (in the collections
module, https://docs.python.org/2/library/collections.html)
Upvotes: 2
Reputation: 765
Any attribute can be changed when you have a class instance. But you can follow convention that attributes started from single and double underscore is private and you should not access them directly unless you know what are you doing.
To provide public interface @property
decorator really what you want.
Quote from docs:
In the current implementation, the built-in variable
__debug__
isTrue
under normal circumstances,False
when optimization is requested (command line option-O
). The current code generator emits no code for an assert statement when optimization is requested at compile time.
Assets is for development only. They can be used for test checking, etc. In case you need to check appropriate values are passed into __init__
method, you can raise ValueError
or custom error derived from it.
class Card(object):
class CardValueError(ValueError):
pass
__ranks = ['Ace', '2', '3', '4', '5', '6', '7', '8', '9', '10',
'Jack', 'Queen', 'King']
__suits = ['Heart', 'Club', 'Diamond', 'Spade']
def __init__(self, rank, suit):
if rank not in self.__ranks or suit not in self.__suits:
raise Card.CardValueError()
self.__rank = rank
self.__suit = suit
@property
def rank(self):
return self.__rank
@property
def suit(self):
return self.__suit
Upvotes: 1