osdir.com


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

How call method from a method in same class?


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,