【问题标题】:What's the best way to check if class instance variable is set in Python?检查是否在 Python 中设置了类实例变量的最佳方法是什么?
【发布时间】:2020-03-13 13:32:31
【问题描述】:

我有一个变量,它可能会或可能不会在实例中获得值:

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 进行比较,而不是与内部变量混为一谈。

【问题讨论】:

  • 查看getattr函数。
  • 我试过了,它有同样的问题(python 2.6.6)。我必须使用 getattr(self, '_EC__var')

标签: python


【解决方案1】:

你忘记了EAFP principle

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

如果你决定使用哨兵,你可以将它与类变量结合起来:

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

【讨论】:

    【解决方案2】:

    只需使用 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
    >>>
    

    【讨论】:

    • 这适用于单下划线,但不适用于双下划线
    • 我认为你没有正确阅读这个问题,或者理解 Python 对类上的 __var 双下划线属性做了什么。不,没那么简单。
    • 从我的扩展答案中可以看出,单下划线和双下划线在这里都可以正常工作。
    • 双下划线前缀-and-suffixed 成员不会被破坏;它们被视为魔术方法。
    • 每天学习一些新东西 - 不过我会提出 2 分 - 1) 如果您需要从外部访问一个属性,最好不要以一种神奇的方式来命名它,特别是为了保留它私有,最好不要这样做 2) 如果您绝对必须使用该命名约定,那么使用覆盖__getattr__ 的类可能会更好并且更清晰,如中所述stackoverflow.com/questions/2405590/…
    【解决方案3】:

    只需将其设置为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 应该只用于你想要命名空间到你的特定类的属性,这样子类就不会意外地用它们自己的属性破坏它。

    换句话说,不要使用双下划线名称,除非您真正了解它们的用途并且确实需要它。任何不属于未知第三方广泛使用的框架的代码?改用单下划线即可。

    【讨论】:

      【解决方案4】:

      我想有一个简单的方法来检查这个。这是我尝试过的方式。

      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 中试过这个。它成功了。如果对答案有任何误解,请通过评论反馈。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-10-13
        • 2021-04-28
        • 2010-09-27
        • 2017-08-23
        • 2014-11-18
        • 2014-09-24
        • 1970-01-01
        相关资源
        最近更新 更多