I would like to allow the user to change self.path after instantiation but not any other instance variable. However, if self.path is changed then the other instance variables should be reevaluated. Is this possible?
class File(object):
def __init__(self, path):
self.path = os.path.abspath(path)
self.name = os.path.basename(self.path)
self.parent = os.path.dirname(self.path)
self.extension = self._get_extension()
self.category = self.get_category(self.extension)
self.exists = os.path.isfile(self.path)
def _get_extension(self):
extension = None
result = os.path.splitext(self.name)[1][1:]
if result:
extension = result
return extension
def get_category(self, extension):
if extension:
file_extension = extension.upper()
for key in fileGroups.keys():
common = set(fileGroups[key]) & set([file_extension])
if common:
return key
return 'UNDEFINED'
From https://stackoverflow.com/a/598092/3110529 what you're looking for is the property getter/setter pattern. Python implements this via @property
and @member.setter
, you can see this in the example of the answer above.
In terms of your issue you can solve it by doing the following:
class File(object):
def __init__(self, path):
self.__path = os.path.abspath(path)
self.__name = os.path.basename(self.path)
self.__parent = os.path.dirname(self.path)
self.__extension = self._get_extension()
self.__category = self.get_category(self.extension)
self.__exists = os.path.isfile(self.path)
@property
def path(self):
return self.__path
@path.setter
def path(self, value):
self.__path = value
# Update other variables here too
@property
def name(self):
return self.__name
etc for the rest of your properties
This means you can do stuff like:
file = File("a path")
print(file.path)
file.path = "some other path"
# This will throw an AttributeError
file.name = "another name"
Note that everything works the same but properties without setters will throw errors if tried to be modified.
This does make your File
class significantly larger, but it prevents the user from changing members other than path
as there is no setter implemented. Technically the user can still do file.__path = "something else"
but there's generally an understanding that members prefixed with double underscores are private and shouldn't be tampered with.