Library-private parameter in Python
Question:
Context
I’m developing an open-source library (Google Calendar Simple API). Say I have an object (e.x. Attendee
) that has a field that should only be set by the library but accessed by the user-developer (e.x. Attendee.response_status
(whether attendee accepted the invitation or not)).
Question
What would be the best practice in Python to implement/enforce such behavior? Is there a neat way to differentiate whether the object was created within the same library or from outside?
The field isn’t private, but shouldn’t be set by developers, only within the library itself.
class Attendee:
def __init__(self, email, response_status):
self.email = email # can be set by developer
self.response_status = response_status # should only be set by the library
The one simple solution I’m thinking about is:
class Attendee:
def __init__(self, email, response_status=None, *, ignore_response_status_parameter=False):
if not ignore_response_status_parameter and response_status is not None:
raise ValueError('response_status can only be set automatically')
self.email = email # can be set by developer
self.response_status = response_status # should only be set by the library
(Is it a SO question? Should it be asked somewhere else?)
Answers:
This pattern would make the property read-only (in as much as that’s possible in Python) for the consumer of the object:
class Attendee:
def __init__(self, email, response_status):
self.email = email
self.__response_status = response_status
@property
def response_status(self):
return self.__response_status
Beyond that, you can’t prevent the consumer to simply import your class and instantiate it themselves and set response_status
to whatever they like. That’s uselessly defensive programming. You just need to ensure that your code works correctly and your functions return the correct data; you can’t defend against someone picking your code—to which they have full access—apart and reusing it in other ways.
This can be done using descriptors (the hard way) or using properties which are a nice descriptor encapsulation.
Here you could change your class to:
class Attendee:
def __init__(self, email):
self.email = email # can be set by developer
self._response_status = 0 # should only be set by the library
@property
def response_status(self):
return self._response_status
def set_good_status(self): # example of internal change
self._response_status = 1
You can then test that response_status is a read-only attribute that can only be internally changed through the private _response_status
member.
>>> a = Attendee('foo')
>>> a.response_status
0
>>> a.response_status = 1
Traceback (most recent call last):
File "<pyshell#29>", line 1, in <module>
a.response_status = 1
AttributeError: can t set attribute
>>> a.set_good_status()
>>> a.response_status
1
Context
I’m developing an open-source library (Google Calendar Simple API). Say I have an object (e.x. Attendee
) that has a field that should only be set by the library but accessed by the user-developer (e.x. Attendee.response_status
(whether attendee accepted the invitation or not)).
Question
What would be the best practice in Python to implement/enforce such behavior? Is there a neat way to differentiate whether the object was created within the same library or from outside?
The field isn’t private, but shouldn’t be set by developers, only within the library itself.
class Attendee:
def __init__(self, email, response_status):
self.email = email # can be set by developer
self.response_status = response_status # should only be set by the library
The one simple solution I’m thinking about is:
class Attendee:
def __init__(self, email, response_status=None, *, ignore_response_status_parameter=False):
if not ignore_response_status_parameter and response_status is not None:
raise ValueError('response_status can only be set automatically')
self.email = email # can be set by developer
self.response_status = response_status # should only be set by the library
(Is it a SO question? Should it be asked somewhere else?)
This pattern would make the property read-only (in as much as that’s possible in Python) for the consumer of the object:
class Attendee:
def __init__(self, email, response_status):
self.email = email
self.__response_status = response_status
@property
def response_status(self):
return self.__response_status
Beyond that, you can’t prevent the consumer to simply import your class and instantiate it themselves and set response_status
to whatever they like. That’s uselessly defensive programming. You just need to ensure that your code works correctly and your functions return the correct data; you can’t defend against someone picking your code—to which they have full access—apart and reusing it in other ways.
This can be done using descriptors (the hard way) or using properties which are a nice descriptor encapsulation.
Here you could change your class to:
class Attendee:
def __init__(self, email):
self.email = email # can be set by developer
self._response_status = 0 # should only be set by the library
@property
def response_status(self):
return self._response_status
def set_good_status(self): # example of internal change
self._response_status = 1
You can then test that response_status is a read-only attribute that can only be internally changed through the private _response_status
member.
>>> a = Attendee('foo')
>>> a.response_status
0
>>> a.response_status = 1
Traceback (most recent call last):
File "<pyshell#29>", line 1, in <module>
a.response_status = 1
AttributeError: can t set attribute
>>> a.set_good_status()
>>> a.response_status
1