如何限制在构造函数之外设置属性?

2024-09-28 20:16:05 发布

您现在位置:Python中文网/ 问答频道 /正文

我希望在初始化类之后禁止对类的某些属性进行进一步的赋值。例如,在Person实例“p”初始化之后,没有人可以显式地将任何值赋给“ssn”(社会保险号)属性。setattr方法内部赋值时也被调用,因此这不是我想要的。我只想限制进一步的任务。我怎么才能做到呢?在

class Person(object):
    def __init__(self, name, ssn):
        self.name = name
        self._ssn = ssn

    def __setattr__(self, name, value):
        if name == '_ssn':
            raise AttributeError('Denied.')
        else:
            object.__setattr__(self, name, value)

>> p = Person('Ozgur', '1234')
>> AttributeError: Denied.

Tags: 实例方法nameself属性objectvaluedef
3条回答

您可以通过在构造函数中直接分配给实例字典来绕过setattr。当然,这个技巧总是可以用来欺骗你用来使∗ssn变为只读的(在初始写入之后)

 class Person(object): 
    def __init__(self, name, ssn):    
        self.name = name
        self.__dict__['_ssn'] = ssn 

    def __setattr__(self, name, value):
        if name == '_ssn':
            raise AttributeError('Denied.')
        else:
            object.__setattr__(self, name, value)

Python不支持private或protected属性。您需要实现描述符协议。标准库提供了修饰符来简洁地实现这一点。在

只需在init方法中声明前面带有两个下划线的属性。它被称为name mangling,并阻止通过xusn访问属性,尽管在这种情况下,_Person_ussn仍然可以访问和修改属性。但是,如果不显式定义setter,它将引发AttributeError。在

当然,如果有人有滥用API的意图,如果他是非常有意图的话,他可以这样做。但这不是偶然的。在

import re

class Person:
    """Encapsulates the private data of a person."""

    _PATTERN = re.COMPILE(r'abcd-efgh-ssn')

    def __init__(self, name, ssn):
       """Initializes Person class with input name of person and
       his social security number (ssn).
       """
       # you can add some type and value checking here for defensive programming
       # or validation for the ssn using regex for example that raises an error
       if not self._PATTERN.match(ssn):
           raise ValueError('ssn is not valid')
       self.__name = name
       self.__ssn = snn

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, value):
        self.__name = value

    @property
    def ssn(self):
        return self.__ssn

>>> p = Person('aname', 'abcd-efgh-ssn')
>>> p.ssn
'abcd-efgh-ssn'
>>> p.ssn = 'mistake'
AttributeError: 'can't set attribute'

通常的方法是使用以下划线开头的“private”属性和用于公共访问的只读属性:

import operator

class Person(object):
    def __init__(self, name, ssn):
        self.name = name
        self._ssn = ssn
    ssn = property(operator.attrgetter("_ssn"))

请注意,这并不会真正妨碍任何人更改属性_ssn,而是前面的_说明该属性是私有的。在

相关问题 更多 >