防止改变实例变量

问题描述 投票:0回答:2

我想允许用户在实例化后更改 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'
python variables instance-variables
2个回答
4
投票

来自 https://stackoverflow.com/a/598092/3110529 你要找的是属性 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 的属性将抛出错误。

这确实使您的

File
类显着变大,但它阻止了用户更改
path
以外的成员,因为没有实现 setter。从技术上讲,用户仍然可以执行
file.__path = "something else"
,但通常认为以双下划线为前缀的成员是私有的,不应被篡改。


1
投票

Dilanm 是对的。如果您需要将成员变量设置为只读或添加验证或其他访问权限任务,请使用属性。请注意,类声明中的 (object) 是可选的,并且由于无法在 python 类中强制执行私有成员,我只会用“_”强调我的意图,除非你真的有理由使用“__”。

#!/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)

要覆盖一个成员,只需在子类中再次定义它。属性没有什么不同。

© www.soinside.com 2019 - 2024. All rights reserved.