If I understand your question correctly, you should be able to reference class A within class A by putting the type annotation in quotes. This is called forward reference.

class A:
  # do something
  def some_func(self, a: 'A')
  # ...

See ref below

  1. https://github.com/python/mypy/issues/3661
  2. https://www.youtube.com/watch?v=AJsrxBkV3kc
Answer from Chin Pang Yau on Stack Overflow
🌐
Python documentation
docs.python.org › 3 › tutorial › classes.html
9. Classes — Python 3.14.8 documentation
5 days ago - Objects can contain arbitrary amounts and kinds of data. As is true for modules, classes partake of the dynamic nature of Python: they are created at runtime, and can be modified further after creation. In C++ terminology, normally class members (including the data members) are public (except see below Private Variables), and all member functions are virtual. As in Modula-3, there are no shorthands for referencing the object’s members from its methods: the method function is declared with an explicit first argument representing the object, which is provided implicitly by the call.
Top answer
1 of 4
20

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)

To answer the question posed in the title (in case that is still bringing people to this question):

Python objects are passed in and out of functions by pointer value. That's a lot like being passed by reference, but it's not exactly the same as how references work in other languages (like C++). You can mutate a value being passed in, as long as you do it in-place. You cannot, however, rebind the value of the object and see the same rebinding outside the function.

Here are some examples that demonstrate the differences:

value = [1, 2, 3]

def foo(x):
    x.append(4)           # mutate x in place
    print('inside', x)

foo(value)                # prints 'inside [1, 2, 3, 4]'
print('outside', value)   # prints 'outside [1, 2, 3, 4]'

def bar(x):
    x = [9, 8, 7]         # this rebinding is allowed, but may not do what you want
    print('inside', x)

bar(outside_value)        # prints 'inside [9, 8, 7]'
print('outside', value)   # still prints 'outside [1, 2, 3, 4]'
2 of 4
6

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.

🌐
W3Schools
w3schools.com › python › python_classes.asp
Python Classes
Almost everything in Python is an object, with its properties and methods. A Class is like an object constructor, or a "blueprint" for creating objects.
🌐
Real Python
realpython.com › videos › object-references
Object References (Video) – Real Python
What actually happens is that I create a reference to an object. 01:25 I’m creating a Python object with the value 300 and then I’m pointing the variable name n to that object. That’s what’s going on here. What happens now if I say m = n? All right, so I say m = n.
Published: December 10, 2019
🌐
Python documentation
docs.python.org › 3 › reference › datamodel.html
3. Data model — Python 3.14.8 documentation
A class has a namespace implemented by a dictionary object. Class attribute references are translated to lookups in this dictionary, e.g., C.x is translated to C.__dict__["x"] (although there are a number of hooks which allow for other means of locating attributes).
🌐
Python Like You Mean It
pythonlikeyoumeanit.com › Module4_OOP › ClassInstances.html
Instances of a Class — Python Like You Mean It
# `d2` is a new instance of our Dummy class. # It resides at a distinct memory address (0x2ae8f666f60) >>> d2 = Dummy() >>> d2 <__main__.Dummy at 0x2ae8f666f60> >>> d2 is d1 # `d2` and `d1` are distinct instances of `Dummy` False >>> isinstance(d2, Dummy) True · Python’s rules for referencing objects with variables still apply here: assigning an object to a variable, be it a class object or an instance, does not create a distinct copy of that object.
Top answer
1 of 2
5

That reference isn't describing a special case of the language rules, it's a natural result of everything being an object.

The special case is that MyClass(args...) is wired up to create a new object and call MyClass.__init__ (among other things).

It allows you to change the state of the class after it is defined. This can be as simple as changing "static" data based on some configuration.

class EggsApiClient:
    default_url = "example.com"
    def connect(self):
        # do stuff with default_url

if __name__ = "main":
    EggsApiClient.default_url = parse_args("default_url")
2 of 2
3

This is not something that I think most Python users will ever need to do and almost surely shouldn't but it does have a distinct purpose and it's worth understanding.

Consider the following example:

class Foo:
    def set_a(self, a):
        self.a = a

class Bar:
    def set_b(self, b):
        self.b = b

foo = Foo()

foo.set_a(1)

print(foo.a)

bar = Bar()

# interesting part here!
Foo.set_a(bar, 2)

print(bar.a)

Through this feature, we have effectively called set_a on a Bar instance, despite the fact that Bar doesn't have a set_a method defined. That is, if we try:

bar.set_a()

We get an error: AttributeError: 'Bar' object has no attribute 'set_a'.

You might (quite reasonably) ask, "OK, but why would I do that?" Personally, I think I did something like this many moons ago but there was probably a simpler solution to whatever I was trying to accomplish.

I can imagine this be useful in various frameworks e.g. something like unit testing. But the main reason I think you might end up doing this is when you are using a more functional style. For example, you might have a function like this which has no knowledge of Foo or Bar:

def apply(obj, func, *params):
    func(obj, *params)

Which you can then call like so:

apply(bar, Bar.set_b, 3)

print(bar.b)

A real example of the kind of thing you might actually do:

class Person:
    def __init__(self, name: str, student: bool):
        self.name = name
        self.student = student

    def is_student(self):
        return self.student
    
    def __repr__(self):
        return f"{self.name} - student: {self.student}"
    
people = [Person("bob", False), Person("alice", True), Person("carl", True)]

def display(iter):
    print("---")
    for i in iter:
        print(i)


display(people)

display(filter(Person.is_student, people))

Or maybe something like this:

people = map(Person, ["dave", "edith", "frank"], [True, False, True])

display(people)

Check out the functools module for more interesting functional-style approaches like this.

Find elsewhere
🌐
Readthedocs
python-textbok.readthedocs.io › en › 1.0 › Classes.html
Classes — Object-Oriented Programming in Python 1 documentation
The class will not be defined until Python has executed the entirety of the definition, so you can be sure that you can reference any method from any other method on the same class, or even reference the class inside a method of the class. By the time you call that method, the entire class will definitely be defined. Explain what the following variables refer to, and their scope: ... It is important to note that the attributes set on the object ...
🌐
Open Book Project
openbookproject.net › thinkcs › python › english3e › classes_and_objects_I.html
15. Classes and Objects — the Basics — How to Think Like a Computer Scientist: Learning with Python 3
Every class should have a method with the special name __init__. This initializer method is automatically called whenever a new instance of Point is created. It gives the programmer the opportunity to set up the attributes required within the new instance by giving them their initial state/values. The self parameter (we could choose any other name, but self is the convention) is automatically set to reference the newly created object that needs to be initialized.
Top answer
1 of 5
11

Whatever is associated with a variable name has to be stored in the program's memory somewhere. An easy way to think of this, is that every byte of memory has an index-number. For simplicity's sake, lets imagine a simple computer, these index-numbers go from 0 (the first byte), upwards to however many bytes there are.

Say we have a sequence of 37 bytes, that a human might interpret as some words:

"The Owl and the Pussy-cat went to sea"

The computer is storing them in a contiguous block, starting at some index-position in memory. This index-position is most often called an "address". Obviously this address is absolutely just a number, the byte-number of the memory these letters are residing in.

@12000 The Owl and the Pussy-cat went to sea

So at address 12000 is a T, at 12001 an h, 12002 an e ... up to the last a at 12037.

I am labouring the point here because it's fundamental to every programming language. That 12000 is the "address" of this string. It's also a "reference" to it's location. For most intents and purposes an address is a pointer is a reference. Different languages have differing syntactic handling of these, but essentially they're the same thing - dealing with a block of data at a given number.

Python and Java try to hide this addressing as much as possible, where languages like C are quite happy to expose pointers for exactly what they are.

The take-away from this, is that an object reference is the number of where the data is stored in memory. (As is a pointer.)

Now, most programming languages distinguish between simple types: characters and numbers, and complex types: strings, lists and other compound-types. This is where the reference to an object makes a difference.

So when performing operations on simple types, they are independent, they each have their own memory for storage. Imagine the following sequence in python:

>>> a = 3
>>> b = a
>>> b
3
>>> b = 4
>>> b
4
>>> a
3      # <-- original has not changed

The variables a and b do not share the memory where their values are stored. But with a complex type:

>>> s = [ 1, 2, 3 ]
>>> t = s
>>> t
[1, 2, 3]
>>> t[1] = 8
>>> t
[1, 8, 3]
>>> s
[1, 8, 3]  # <-- original HAS changed

We assigned t to be s, but obviously in this case t is s - they share the same memory. Wait, what! Here we have found out that both s and t are a reference to the same object - they simply share (point to) the same address in memory.

One place Python differs from other languages is that it considers strings as a simple type, and these are independent, so they behave like numbers:

>>> j = 'Pussycat'
>>> k = j
>>> k
'Pussycat'
>>> k = 'Owl'
>>> j
'Pussycat'  # <-- Original has not changed

Whereas in C strings are definitely handled as complex types, and would behave like the Python list example.

The upshot of all this, is that when objects that are handled by reference are modified, all references-to this object "see" the change. So if the object is passed to a function that modifies it (i.e.: the content of memory holding the data is changed), the change is reflected outside that function too.

But if a simple type is changed, or passed to a function, it is copied to the function, so the changes are not seen in the original.

For example:

def fnA( my_list ):
    my_list.append( 'A' )

a_list = [ 'B' ]
fnA( a_list )
print( str( a_list ) )
['B', 'A']        # <-- a_list was changed inside the function

But:

def fnB( number ):
    number += 1

x = 3
fnB( x )
print( x )
3                # <-- x was NOT changed inside the function

So keeping in mind that the memory of "objects" that are used by reference is shared by all copies, and memory of simple types is not, it's fairly obvious that the two types operate differently.

2 of 5
5

Objects are things. Generally, they're what you see on the right hand side of an equation.

Variable names (often just called "names") are references to the actual object. When a name is on the right hand side of an equation1, the object that it references is automatically looked up and used in the equation. The result of the expression on the right hand side is an object. The name on the left hand side of the equation becomes a reference to this (possibly new) object.

Note, you can have object references that aren't explicit names if you are working with container objects (like lists or dictionaries):

a = []  # the name a is a reference to a list.
a.append(12345)  # the container list holds a reference to an integer object

In a similar way, multiple names can refer to the same object:

a = []
b = a

We can demonstrate that they are the same object by looking at the id of a and b and noting that they are the same. Or, we can look at the "side-effects" of mutating the object referenced by a or b (if we mutate one, we mutate both because they reference the same object).

a.append(1)
print a, b  # look mom, both are [1]!

1More accurately, when a name is used in an expression

🌐
pythontutorials
pythontutorials.net › blog › are-class-objects-instances-in-python-3-passed-by-reference
Are Python 3 Class Instances Passed by Reference? Explaining Object Modification Without Parameters — pythontutorials.net
When you pass a variable to a function, Python passes the reference to the object (not a copy of the object or a reference to the variable itself). ... The function receives a new local variable (parameter) that points to the same object as the original variable. If the object is mutable (e.g., lists, dictionaries, class instances), modifying its contents (e.g., attributes, elements) through the function’s parameter will affect all references to that object.
🌐
Stack Overflow
stackoverflow.com › questions › 56340311 › how-to-reference-to-the-existing-object-of-class-in-python-from-string
How to reference to the existing object of class in Python from string? - Stack Overflow
I've got the problem with reference to the object. Function returns string="nameofexistingclass" and I would like to pass the string as an object and not as a class. User choose in the GUI of the existing instance of Person(self.name, self.ID) --> string with name of choosen class --> set another object of different class demanding choosen class.: Classify(person) Python demands to set the self.name, self.ID, but they exist before even choosing.
🌐
Python.org
discuss.python.org › python help
How to refer to current class object - Python Help - Discussions on Python.org
August 16, 2026 - Is there some way I can refer to the current class object from within itself before it’s definition is completed? I have found a number of times where it would be very useful to be able to reference the currently runnin…
🌐
docs.python.org
docs.python.org › 3 › c-api › class.html
Python/C API reference manual — Python 3.14.6 documentation
This manual documents the API used by C and C++ programmers who want to write extension modules or embed Python. It is a companion to Extending and Embedding the Python Interpreter, which describes...
🌐
Programiz
programiz.com › python-programming › class
Python Classes and Objects (With Examples)
Here, __init__() is the constructor function that is called whenever a new object of that class is instantiated. The constructor above initializes the value of the name attribute. We have used the self.name to refer to the name attribute of the bike1 object.