Python 防止更改实例变量

Python 防止更改实例变量,python,variables,instance-variables,Python,Variables,Instance Variables,我希望允许用户在实例化后更改self.path,但不允许更改任何其他实例变量。但是,如果更改了self.path,则应重新计算其他实例变量。这可能吗 class File(object): def __init__(self, path): self.path = os.path.abspath(path) self.name = os.path.basename(self.path) self.parent = os.path.dirn

我希望允许用户在实例化后更改self.path,但不允许更改任何其他实例变量。但是,如果更改了self.path,则应重新计算其他实例变量。这可能吗

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'
您要查找的是属性getter/setter模式。Python通过
@property
@member.setter
实现这一点,您可以在上面的答案示例中看到这一点

对于您的问题,您可以通过执行以下操作来解决:

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
这意味着你可以做以下事情:

file = File("a path")
print(file.path)
file.path = "some other path"

# This will throw an AttributeError
file.name = "another name"
请注意,所有操作都是相同的,但是如果试图修改没有设置器的属性,则会抛出错误

这确实会使
文件
类显著增大,但它会阻止用户更改
路径
以外的成员,因为没有实现setter。从技术上讲,用户仍然可以执行
文件。uu path=“something other”
但一般认为,前缀为双下划线的成员是私有的,不应被篡改。

您要查找的是属性getter/setter模式。Python通过
@property
@member.setter
实现这一点,您可以在上面的答案示例中看到这一点

对于您的问题,您可以通过执行以下操作来解决:

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
这意味着你可以做以下事情:

file = File("a path")
print(file.path)
file.path = "some other path"

# This will throw an AttributeError
file.name = "another name"
请注意,所有操作都是相同的,但是如果试图修改没有设置器的属性,则会抛出错误


这确实会使
文件
类显著增大,但它会阻止用户更改
路径
以外的成员,因为没有实现setter。从技术上讲,用户仍然可以使用
文件。uuu path=“something other”
但一般认为前缀为双下划线的成员是私有的,不应被篡改。

Dilanm是正确的。如果需要将成员变量设置为只读,或在access上添加验证或其他任务,请使用属性。请注意,类声明中的(object)是可选的,因为在python类中没有强制私有成员的方法,所以我只想用“u”来强调我的意图,除非您确实有理由使用“u”

#!/usr/bin/env python3

import os.path

class File:
    def __init__(self, path):
        self._path = path
        self.compute_others()

    def compute_others(self):
        self._parent = os.path.dirname(self._path)
        pass # add other attributes to be computed

    # getter, also makes .path read-only
    @property
    def path(self):
        return self._path

    # setter, allows setting but adds validation or other tasks
    @path.setter
    def path(self, path):
        self._path = path
        self.compute_others()

    # other attributes only have getters (read-only)
    @property
    def parent(self):
        return self._parent

    def __str__(self):
        return 'path:{}\nparent:{}\n\n'.format(self.path, self.parent)

f = File('/usr')
print(f)

f.path = '/usr/local'
#f.parent = '/tmp' # error, read-only property
print(f)

若要重写成员,只需在子类中再次定义它。属性也一样。

迪兰姆是对的。如果需要将成员变量设置为只读,或在access上添加验证或其他任务,请使用属性。请注意,类声明中的(object)是可选的,因为在python类中没有强制私有成员的方法,所以我只想用“u”来强调我的意图,除非您确实有理由使用“u”

#!/usr/bin/env python3

import os.path

class File:
    def __init__(self, path):
        self._path = path
        self.compute_others()

    def compute_others(self):
        self._parent = os.path.dirname(self._path)
        pass # add other attributes to be computed

    # getter, also makes .path read-only
    @property
    def path(self):
        return self._path

    # setter, allows setting but adds validation or other tasks
    @path.setter
    def path(self, path):
        self._path = path
        self.compute_others()

    # other attributes only have getters (read-only)
    @property
    def parent(self):
        return self._parent

    def __str__(self):
        return 'path:{}\nparent:{}\n\n'.format(self.path, self.parent)

f = File('/usr')
print(f)

f.path = '/usr/local'
#f.parent = '/tmp' # error, read-only property
print(f)

若要重写成员,只需在子类中再次定义它。属性也一样。

谢谢,帮助很大。但是如何在文件的子类中重写path@property?(如果你不介意的话)@giantas这个答案应该也能帮你找到下面的答案,它使用了
Super
,实际上我只是自己测试了一下,你甚至不需要这么做,看看我制作的这个贴纸:(这不适用于骑自行车,但可能仍然有用)谢谢,帮助很大。但是如何在文件的子类中重写path@属性呢?(如果你不介意的话)@giantas这个答案应该也能帮助你找到下面的答案,它使用了
Super
,事实上我只是自己测试了它,你甚至不需要这样做,看看我制作的这个粘贴:(这不适用于过度使用,但可能仍然有用)“注意(对象)在类声明中是可选的”:仅在Python 3.x中。在Python2.x中,它在技术上是“可选的”,但随后会生成一个“旧式类”,该类不能正确处理属性(以及一般的描述符),因此在本例中它不是可选的。“请注意,类声明中的(对象)是可选的”:仅在Python3.x中。在Python2.x中,它在技术上是“可选的”,但随后会生成一个“旧式类”,它不能正确处理属性(以及一般的描述符),因此在本例中它不是可选的。