On 07Mar2018 16:57, C W <tmrs...@gmail.com> wrote:
I am new to OOP. I'm a bit confused about the following code.

class Clock(object):
   def __init__(self, time):
       self.time = time
   def print_time(self):
       time = '6:30'
       print(self.time)

clock = Clock('5:30')
clock.print_time()
5:30

I set time to 6:30, but it's coming out to 5:30. I guess it's because I
passed in 5:30, so, it's replaced?

No, it is because the scope isn't what you think. In the print_time() method, the variable "time" is just a local variable. It is unrelated the the instance ("self")'s "self.time" value. So you're printing self.time, which is unchanged from when the object was initialised. Try adding:

   print(time)

to the method and compare the values.

How does line-by-line execution run inside a frame? How does __init__ work?
I understand you must have __init__. Is it run before print_time(), if so,
why don't I just set self.time = '6:30' instead of self.time = time?

A "frame" is normally what we refer to as a "stack frame": if it a little record which the language implementation uses to keep track of nested function calls. When you call a function, a new stack frame is pushed, which amongst other things contains a reference to the local variables alive during the call. When you return from a function the frame is popped and discarded.

The __init__ method is called as the initial setup of an object, just after it is created. When you program went:

 clock = Clock('5:30')

a new "Clock" instance was made. Then that instance's __init__ method was called with the '5:30' which you passed to the class name. That is how the string '5:30' gets stored as the .time attribute of the instance.

The reason you say "self.time = time" is that you want to store the value passed to the constructor. It might be any time.

 clock1 = Clock('5:30')
 clock2 = Clock('5:45')

Now you have to distinct Clock instances, one holding the time '5:30' and one holding the time '5:45'.

Your print_time method is a little odd. Normally such a function would not take an argument, just print the internal value from the Clock instance. So typically it would look like this:

 def print_time(self):
   print(self.time)

See that is doesn't take a time parameter?

Regarding setting self.time directly to '6:30', that depends what you want to do with it. A "Clock" might have different purposes, and you should decide what the purpose of yours actually is.

As an example, Python's "datetime" module contains classes for dates and times and "datetimes" containing a date and a clocklike time. Normally these are made once and NOT CHANGED. So they're like a special kind of number. They have various methods for computing, for you, things like the day of the week or writing the date or time out in particular formats, or comparing two dates.

But a sometimes you don't want a fixed timestamp. You might be modelling a clock, whose value changes as time passes. In that case you may well want to adjust the values inside it.

You're print_time method seems odd because it does 2 things: it prints a time, but it also seems to want to change the internal time. It is usually good to separate such things.

Finally, setting the time attrubute directly is a reasonable thing to do, but it varies with (a) your needs and (b) the OOP paradigm you're following and how strict you're being.

In a "pure" OOP environment one never sets the internal state of an object directly, so one never goes:

 clock1.time = '5:55'

Instead you would always go:

 clock1.set_time('5:45')

and be _unaware_ of how the object may be storing that vaue internally. Some languages will enforce this, and provide no way to modify an object except via "setter" methods. This has some advantages:

You can switch out objects implementations provided they provide the same setter methods - your calling code doesn't know or care how the clock manages the internal values.

In principle you can make objects "remote" i.e. not local im-memory things at all, if that is sensible. This is why some OOP descriptions treat methods as messages: you send a "set_time" request to the clock with a new time, or you send a "get_time" request to a clock the retrive the current time.

Also, because everything is done through setter or getter methods, you can't accidentally damage the object internal state by setting to nonsense. The setter methods should sanity check the incoming values, and the getters will always return sensible values. If the caller expects to directly modify the internals then they might set the minutes to negative values, or values >= 60, or some other nonsensical value. By using methods all the responsibility is inside the class where it is easy to keep correct.

Python lets you use that paradigm, but it doesn't prevent you directly accessing or changing the internals. The philosophy is that you should exercise restraint. So you _can_ directly set the clock.time value; whether that is a good idea depends on the clock implementation and your program.

In Python there is a naming convention: values which may be directy accessed are given ordinary names (like ".time") and values which are part of the internals, subject to change, or tricky to keep correct are given names starting with underscores (like "._time"). If you're accessing a _name that is a clue that you're probably doing the wrong thing (if your outside the class - obviously the class itself must work on these values).

Cheers,
Cameron Simpson <c...@cskk.id.au> (formerly c...@zip.com.au)
--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to