开发者

Using unitialized variables in Python

开发者 https://www.devze.com 2023-03-27 13:07 出处:网络
Background: I have a class modeling a chip with registers, the chip has a bunch of registers, one of them is a high temperature limit for the built-in temperature sensor.

Background: I have a class modeling a chip with registers, the chip has a bunch of registers, one of them is a high temperature limit for the built-in temperature sensor.

I have the following:

class foo():
  def __init__(self):
    # does not set self._hiTemp!
    ...
  def setHiTemp(self, t):
    self._hiTemp = t
  def getHiTemp(self):
    return self._hiTemp
  def checkHiTemp(self):
    return self._temp > self._hiTemp

The reason that I don't declare self._hiTemp in the __init__ is because the user may not care about the temp-sensing capabilities of the chip. The user can be using the chip in different ways, and there is no meaning in giving this variable a meaningless value. However, if the user tries to use self._hiTemp without first setting it, the error of using undeclared variables is much easier to debug/backtrace than some obscure 开发者_如何学Cerror like comparing numbers and None (or in some case even no errors at all).

This is all going fine until I start pylint, and of course I get W0201: Attribute defined outside init just about everywhere. I'm just wondering if this style of coding is frowned upon, and if so, what the "Pythonic way" is.

Thanks


The way I'd do it is set it to None or some other sentinel value that doesn't occur 'in nature'. Then for operations that require it to be set, use an assert to fail fast in case the caller is trying to use your object inappropriately.

def __init__(self):
    self._hiTemp = None

def checkHiTemp(self):
    assert self._hiTemp is not None, 'Why you no set _hiTemp before checking it?'
    return self._temp > self._hiTemp


Python's not Java, so don't write getters and setters like that. You can solve your problem like this

class Foo(object):
    def __init__(self, hiTemp=None):
        self._hiTemp = hiTemp

    @property
    def hiTemp(self):
        if self._hiTemp is None:
            raise AttributeError("You have not initialized hiTemp")
        return self._hiTemp

    @hiTemp.setter
    def hiTemp(self, value):
        self._hiTemp = value

    def checkHiTemp(self):
        return self._temp > self._hiTemp

foo=Foo()
foo.hiTemp = 50
print foo.hiTemp # Prints 50

foo=Foo(hiTemp=20)
print foo.hiTemp # Prints 20

foo=Foo()
print foo.hiTemp # Raises exception


If you want a particular attribute of the object to be set via a method, then there could always be reason for it be available in the initializer. You can just use self._hiTemp=None You are already declaring it as private by leading _, so users will understand as not to rely on that.


It's customary to use the value None to mean no real value. You can initialize it to that in __init__. You might also use a meaningless value in this case, such as a negative number, and check for that in the checkHiTemp method, and raise a custom exception if used without a properly initialized value. That is an even more meaningful error.


I think from the user's perspective it would be better to have a proper error message than an undeclared variable error. I would do:

def __init__(self):
    self._hiTemp = None

def setHiTemp(self, t):
    self._hiTemp = t

def getHitemp(self):
    if self._hiTemp is None:
        raise Exception('You need to setHiTemp() before using it.')
    else:
        return self._hiTemp

def checkHiTemp(self):
    if self._hiTemp is None:
        raise Exception('You need to setHiTemp() before using it.')
    else:
        return self._temp > self._hiTemp
0

精彩评论

暂无评论...
验证码 换一张
取 消