Python中检查类实例变量是否设置的最佳方法是什么?

10

我有一个变量,这个变量在实例中可能会或者不会得到值:

class EC():
   __init__(self, a=False):
   ...
   if a: self.__var = ...

稍后我想检查实例中是否存在__var。因为在名称前加上__会将内部名称更改为_EC__var,检查代码变得有点混乱:

if ''.join(['_',self.__class__.__name__,'__name']) in self.__dict__: ...

上面的代码算是正常的吗?如果不是,有什么更好的替代方法呢?

我能想到的一个选择是无论如何都给__var赋值,例如:

_no_value = object()
...
   def __init__(self, a):
      self.__var = _no_value
      ...
      if a: self.__var = ...

这样我就可以将__var_no_value进行比较,而不是使用内部变量的混乱。


2
请查看getattr函数。 - Some programmer dude
我已经尝试过了,它有相同的问题(Python 2.6.6)。我必须使用getattr(self,'_EC__var')。 - Phoenix
4个回答

15

只需使用hasattr(self, '_var')来查看它是否存在 - 它可能设置为None,但如果hasattr说它存在,它就会存在。

例如:

>>> class a():
...   def __init__(self):
...      self.a = 3
...      self._a_ = 4
...      self.__a__ = 'Fred'
...
>>> A=a()
>>> hasattr(a, 'a')
False
>>> hasattr(A, 'a')
True
>>> hasattr(A, '_a_')
True
>>> hasattr(A, '__a__')
True
>>> hasattr(A, '__b__')
False
>>>

1
这对于单个下划线可以工作,但对于双下划线不起作用。 - Phoenix
我认为你没有正确阅读问题,或者不理解Python对类中的__var双下划线属性所做的操作。不,这并不简单。 - Martijn Pieters
从我的详细回答中可以看出,使用单下划线和双下划线都能正常工作。 - Steve Barnes
双下划线前缀和后缀的成员不会被混淆;它们被视为魔法方法。 - ecatmur
每天学点新东西 - 我想提出两点建议 - 1)如果您需要从外部访问属性,则最好不要以某种方式命名它,以使其被私有化并且可能更好地遵循最佳实践;2)如果您绝对必须使用该命名约定,则最好使用一个覆盖__getattr__的类,如https://dev59.com/2HE95IYBdhLWcg3wN7Ov中所讨论的那样,这样会更清晰明了。 - Steve Barnes

14

你忘记了EAFP原则

try:
    value = self.__var
except AttributeError:
    # do something else

如果您决定使用哨兵,可以将其与类变量组合使用:

class EC():
    __var = object():
    ...
    if self.__var is not EC.__var:
        ...

4

只需在类上将其设置为 None

 class EC():
    __var = None

    __init__(self, a=False):
        ...
        if a: self.__var = ...

然后测试 if self.__var is not None

如果None应该是属性的有效值,请使用一个不同的单例标记:

_sentinel = object()

 class EC():
    __var = _sentinel

    __init__(self, a=False):
        ...
        if a: self.__var = ...

测试一下if self.__var is not _sentinel

这种方式可以正确地将对__var的所有引用重写为包括类名。

另一种方法是不要使用双下划线名称作为属性名。__var只应用于您想要为其指定命名空间的属性,以便子类不会意外地用自己的属性覆盖它。

换句话说,除非您真正理解双下划线名称的作用并实际需要它,否则不要使用双下划线名称。任何不面向未知第三方进行更广泛消费的框架之外的代码?只需使用单下划线即可。


1

我猜应该有一种简单的方法来检查这个问题。这是我尝试过的方法。

class Test:

    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

        if self.c:
            self.d = "The variable exists"
        if 'd' in self.__dict__:
            print(self.d)

现在实例化上述类:

t = Test('123', 'asd', True)

上述代码的输出结果类似于:
The variable exists

如果你想查看 self.__dict__ 的内容。只需输入:print(self.__dict__)。 上述代码的输出如下:
{'a': '123', 'b': 'asd', 'c': True, 'd': 'The variable exists'}

所有实例变量都以字典格式存储在self.dict中。 我在Python 3.8.1和Python 2.6.6中尝试了这个方法,它可以正常工作。如果答案有任何误解,请通过评论反馈。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接