【问题标题】:Prevent altering instance variable防止更改实例变量
【发布时间】:2017-09-10 12:19:43
【问题描述】:

我希望允许用户在实例化后更改 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


    【解决方案1】:

    来自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"
    

    请注意,一切都一样,但如果尝试修改没有设置器的属性,则会引发错误。

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

    【讨论】:

    【解决方案2】:

    迪兰姆是对的。如果您需要将成员变量设置为只读或在访问使用属性上添加验证或其他任务。请注意,类声明中的 (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)
    

    要覆盖一个成员,只需在子类中再次定义它。属性也不例外。

    【讨论】:

    • “请注意,类声明中的(对象)是可选的”:仅在 Python 3.x 中。在 Python 2.x 中,它在技术上是“可选的”,但它会产生一个“旧式类”,它不能与属性(和一般的描述符)一起正常工作,所以在这种情况下它不是可选的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-19
    • 2014-10-21
    • 1970-01-01
    • 1970-01-01
    • 2016-05-07
    • 1970-01-01
    相关资源
    最近更新 更多