How call method from a method in same class?

Dave dboland9 at offilive.com
Mon Apr 1 22:37:42 EDT 2019


On 4/1/19 10:29 PM, Cameron Simpson wrote:
> On 01Apr2019 22:02, Dave <dboland9 at offilive.com> wrote:
>> As classes get more complex, it is good to call a function to do some 
>> of the processing, and make the code easier to follow.  My question is 
>> how to do that?  I've attached some silly code to illustrate the 
>> point.  The error is: name 'validScale' is not defined.  Well, yes it 
>> is, but maybe not the correct way.  Suggestions?
> 
> It is and it isn't. See below:
> 
>> class TempConverter():
>>    """ Temperature Converter converts a tempeature from one scale
>>        to another scale.  For example: 32, F, C will return
>>        0 degrees C
>>    """
> [...]
>>    def validScale(self, scaleName):
>>        if scaleName.upper == 'F' or 'C' or 'K':
>>            return True
>>        else:
>>            return False
>>
>>    def convertTemp(self):
>>        """ Converts temperature scale if scales valid."""
>>        if validScale(self.scale):
>>            scaleValid = True
> [...]
> 
> It is an instance method, so:
> 
>     if self.validScale(self.scale)
> 
> would resolve the name. However, there are several things worth 
> discussing here.
> 
> First up, validScale itself returns a Boolean, so just return the test 
> result. Change:
> 
>     if scaleName.upper == 'F' or 'C' or 'K':
>         return True
>     else:
>         return False
> 
> into:
> 
>     return scaleName.upper == 'F' or 'C' or 'K'
> 
> Second, the condition is buggy. You want this:
> 
>     return scaleName.upper() in ('F', 'C', 'K')
> 
> i.e. you need to call (the "()") the .upper method, and you need to 
> check if the result is in your collection of valid results.
> 
> This expression:
> 
>     value == A or B or C
> 
> means: True if value == A, otherwise B if B is true, otherwise C.
> 
> The next thing to observe is that you're testing whether self.scale is 
> valid. Normal practice would be to make that test in __init__, and raise 
> a ValueError if it is not so:
> 
>     def __init__(self, .....scale...):
>       if scale.upper() not in ('F', 'C', 'K'):
>         raise ValueError("invalid scale %r: expected one of F, C or K" % 
> (scale,))
> why recite the scale in the message? Because it makes the offending 
> value obvious. In particular, if for example you called this incorrectly 
> and had the temperature in there instead of the scale that will be 
> trivial to debug from the message.
> 
> Of course, you actually want to be able to test any scal evalue for 
> validity, not just the one stuffed into your instance (.scale). So lets 
> revisit the validScale method:
> 
>     def validScale(self, scale):
>       return scaleName.upper() in ('F', 'C', 'K')
> 
> You'll notice that it doesn't depend in "self". Or, for that matter, the 
> class. So this is a "static" method: a function defined in the class for 
> conceptual clarity, but not with any dependence on the class itself or a 
> particular class instance. So:
> 
>     @staticmethod
>     def validScale(scale):
>       return scaleName.upper() in ('F', 'C', 'K')
> 
> In __init__, and elsewhere, you can still call this from the instance:
> 
>     def __init__(self, .....scale...):
>       if not self.validScale(scale):
>         raise ValueError("invalid scale %r: expected one of F, C or K" % 
> (scale,))
> You can also call this from _outside_ the class, for example for other 
> validation:
> 
>     scale = input("Enter a temperate scale name (F, C or K): ")
>     if not TempConverter.validScale(scale):
>       print("Bad! Bad user!")
> 
>>            newScaleValid = True
> 
> Again, validScale returns a Boolean. So you could have just gone:
> 
>     newScaleValid = self.validScale(newScale)
> 
>>        if scaleValid and newScaleValid:
>>            print('Scale converted')
>>        else:
>>            msg = "There was and error with the scales entered.\n"
>>            msg = msg + "You entered: " + self.scale
>>            msg = msg + ' ' 'and' + self.newScale
>>            print(msg)
>>
>> if __name__ == "__main__":
>>    myclass = TempConverter(32, 'f', 'c')
>>    myclass.convertTemp()
> 
> My personal inclination would be do define a Temperature class with a 
> convert function to be used like this:
> 
>     temp = Temperature(32, 'f')
>     tempC = temp.convert('c')
> 
> This reduces the complexity of the class and IMO makes it easier to use 
> elsewhere.
> 
> 
> BTW, you get an instance back from tempConverter(...), not a class. So 
> don't call it "myclass".
> 
> Cheers,
> Cameron Simpson <cs at cskk.id.au>

Cameron,

I'm going to need a while to work through this.  As I mentioned, this 
was quick and dirty code just to illustrate a point - not intended to be 
good code.  So I'll take a close read tomorrow.  Thanks again!!

Dave,


More information about the Python-list mailing list