9

This program modifies objects of the class "myclass" _x and _y, but I don't pass it as a parameter to the function try_block. How do the objects get modified?

class AddSub:
    def _init_(self): #how do default parameters work? 
        self._x, _y

    def set_x(self, num):
        self._x = num

    def set_y(self, num):
        self._y = num   

    def add(self):
        return self._x + self._y

    def sub(self):
        return self._x - self._y

def try_block():
    try:
        ch = int(input("type 1 to add, and 2 to subtract: "))

        myclass.set_x(int(input("enter an x value: "))) #how does myclass get modifed?

        myclass.set_y(int(input("enter a y value: ")))

        return ch

    except ValueError:
        print("Invalid entry.")

        ch = try_block()

        return ch


myclass = AddSub()

choice = try_block()

if choice == 1:
    print(myclass.add())

elif choice == 2:
    print(myclass.sub())
Zoe
  • 27,060
  • 21
  • 118
  • 148
Sal Rosa
  • 551
  • 2
  • 8
  • 12
  • 8
    **why** in the name of the almighty flying spaghetti monster do you use setter methods? doing so is **highly inappropriate** in python. Use public fields and in case you ever need setter logic use *properties*. – ThiefMaster Nov 21 '12 at 07:29
  • 1
    Second this. Let go of that getter-setter mumbo-jumbo. Do not code Java in Python. Until you prove that you need anything more than a simple attribute access, don't write getters and setters. – GSP Nov 21 '12 at 07:37
  • 1
    @ThiefMaster: I still remember times when I was a beginner :) – pepr Nov 21 '12 at 07:40
  • @pepr: Beginner coming from which language? – GSP Nov 21 '12 at 09:42
  • @GSP: Possibly from mother language? I did not say ThiefMaster is wrong. Just a possible explanation. When opening programming books, there are strange things sometimes that beginners are able to consume, but they do not have a critic eye, yet. :) – pepr Nov 21 '12 at 10:58

4 Answers4

14

Before I go into answering your question, I want to mention some things about terminology. Your myclass value is an instance, not a class. You do have a class in your code, named AddSub. When you called AddSub() you created an instance of that class. It's important to learn the right terminology for things like this, so you can ask good questions and understand the answers you get back.

Your code comes close to working because you're saving an instance of the AddSub class to a global variable named myclass. Later, you call some methods on that global variable from the try_block function. This is legal in Python, though generally not recommended.

Instead, you should pass the object as an argument:

def try_block(value):
    try:
        value.set_x(whatever())
    except ValueError:
        pass

You'd call it by passing an instance of your AddSub class to the function:

myAddSub = AddSub() # create the instance
try_block(myAddSub) # pass it to the function

This is much nicer because it doesn't depend on a global variable having a specific value to work and you can call it with many different AddSub instances, if you want.

One part of your code that's currently broken is the AddSub class's constructor. There's no need to declare variables. You can just assign to them whenever you want. If you want to have default values set, you can do that too:

def __init__(self):
    self._x = 0
    self._y = 0

If instead you want to be able to set the values when you construct the object, you can add additional parameters to the __init__ method. They can have default values too, allowing the caller to omit some or all of them:

def __init__(self, x=0, y=0):
    self._x = x
    self._y = y

With that definition, all of these will be valid ways to construct an AddSub instance:

a = AddSub()     # gets default 0 value for both _x and _y
b = AddSub(5)    # gets default 0 value for _y
c = AddSub(y=5)  # gets default 0 value for _x
d = AddSub(2, 3) # no defaults!

Finally a point that is mostly independent of your main question: Your try_block function is both poorly named, and implemented in a more complicated way than necessary. Instead of being recursive, I think it would make more sense as a loop, like in this psuedocode version:

def exception_prone_task():
    while True: # loops forever, or until a "return" or "break" statement happens
         try:
             result = do_stuff_that_might_raise_an_exception()
             return result # you only get here if no exception happened

         except WhateverExceptions as e:
             report_about_about_the_exceptions(e)
Blckknght
  • 100,903
  • 11
  • 120
  • 169
  • 1
    Thank you this was a big help! Still getting the hang of things – Sal Rosa Nov 21 '12 at 20:05
  • 1
    Can you also answer the question in the title, since this shows up at the top of Google search. That is, are class instance objects passed by value or reference? – Nostalg.io Jan 24 '19 at 22:48
  • From my initial testing, it appears that class instance objects behave as though passed by reference. (i.e. properties changed on instances passed as arguments appear outside the function scope). – Nostalg.io Jan 24 '19 at 22:52
  • The title is a bad one for this question, as how arguments get passed is irrelevant if you're not passing any arguments at all. For the title's question, see [this question and its excellent answers](https://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference) – Blckknght Jan 25 '19 at 20:34
  • Does this really answers the question? Doesn't help for future reference. – T.Nel Aug 29 '19 at 14:52
  • Despite the title, this question is mostly "Why does this code work the way it does?". Pass by reference is completely a red herring, so I don't address it in my answer. As I commented just above you (back in January), you can find actual answers about pass by reference on [another question](https://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference). – Blckknght Aug 29 '19 at 17:57
4

Short answer: everything in Python is passed by reference. (Some people like to add "by reference value").

Longer answer is that your code is a bit confusing. (No problem, it can be improved.)

Firstly, the myclass should not be called that way, because it is not a class. It is an instance of the AddSub class -- i.e. the object of that class.

Secondly, classes should not be given names of the verb. They should be nouns.

The first argument of each class method should be self (for simplicity). The next arguments are the ones that were passed when the class is created (i.e. when the class name is used as if you were calling a function).

Whenever you want to give the argument a default value, you just write =value just after the argument.

Everything inside the method definitions that is part of the future object, must be prefixed by self. (simplified). This way, your __init__ should look like:

    def _init_(self, x=1, y=2): #how do default parameters work? 
        self._x = x
        self._y = y

In my opinion, it is not neccessary to use the _ (underscore) prefix for the object variables.

pepr
  • 20,112
  • 15
  • 76
  • 139
3

myclass is defined at the module top level, so it is accessible as a global variable.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384
-3

Everything in Python is an object. Therefore : Reference

dariyoosh
  • 604
  • 1
  • 4
  • 12
  • 4
    Well, other languages also use objects. But it does not mean that they must use references. (But this was not me who voted down :) – pepr Nov 21 '12 at 07:39