如何限制Python类上可用的属性

Dan*_*ish 7 python

参加以下课程

class Person(object):

def __init__(self, first_name, last_name):
    self.first_name = first_name
    self.last_name = last_name
Run Code Online (Sandbox Code Playgroud)

如何防止以下使用?

p1 = Person('Foo', 'Bar')
p1.firstname='Fooooooo'
Run Code Online (Sandbox Code Playgroud)

上面的代码将在Python中成功执行,但是,使用属性的名称进行了错误,即它_first和之间缺失name

更新:这听起来像"猴子修补",我为什么要这样做?

我的目的是简单地帮助避免用户设置错误的属性,让代码执行,并看到意外的行为,而不是立即意识到错误.

Pythonic的推荐方式是什么?

Krz*_*icz 9

首先,做这样的事情几乎总是一个坏主意.如果只是你想要的原因是确保你不打字 - 有更好的工具(想想IDE或pylint).如果你100%肯定你需要这样的东西,这里有两种方法:

第一种方法 - 您可以使用__setattr__方法执行此操作.请参阅python __setattr__文档

class Person(object):

    def __init__(self, first_name, last_name):
        self.__dict__['first_name'] = first_name
        self.__dict__['last_name'] = last_name
    def __setattr__(self, name, value):
        if name in self.__dict__:
            super(Person, self).__setattr__(name, value)
        else:
            raise AttributeError("%s has no attribute %s" %(self.__class__.__name__, name))
Run Code Online (Sandbox Code Playgroud)

并输出:

In [49]: a = Person(1, 2)

In [50]: a.a = 2
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/usr/local/lib/python2.7/dist-packages/django/core/management/commands/shell.pyc in <module>()
----> 1 a.a = 2

/usr/local/lib/python2.7/dist-packages/django/core/management/commands/shell.pyc in __setattr__(self, name, value)
      8             super(Person, self).__setattr__(name, value)
      9         else:
---> 10             raise AttributeError("%s has no attribute %s" %(self.__class__.__name__, name))

AttributeError: Person has no attribute a
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用__slots__(python __slots__文档)执行此操作:

class Person(object):
    __slots__ = ("first_name", "last_name")

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name
Run Code Online (Sandbox Code Playgroud)

输出:

In [32]: a = Person("a", "b")

In [33]: a.first_name
Out[33]: 'a'

In [34]: a.a = 1
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/usr/local/lib/python2.7/dist-packages/django/core/management/commands/shell.pyc in <module>()
----> 1 a.a = 1

AttributeError: 'Person' object has no attribute 'a'
Run Code Online (Sandbox Code Playgroud)

第一种方式更灵活,因为它允许通过__dict__直接使用来进一步破解此代码,但这将比现在更加错误.第二种方法为一定数量的实例变量(引用)预分配空间,这意味着更少的内存消耗.