Skip to content

Moe’s Homepage

Knows how to provide Solution

Menu
  • Home
  • About
    • About Me
Menu

Migrating To Python From Java

Posted on November 9, 2025November 9, 2025 by mabouali

I have always said that:

if you know how to program, you can code in any language.

Well, while I still stay by the above statement, I want to add something to it though.

Yes, you can absolutely code in any language, but make sure that you learn about the peculiarity of each coding language.

One of these peculiarities that I want to write about in this post is a very simple concept: “Defining Variables in a class“. Particularly if you are coming to Python coding from Java.

Table of Contents

Toggle
  • Pay Attention To Coding Style
  • So, What should we learn from this?
  • Defining A Variable In A Class
    • So, what is the issue with Person Class?
  • What are Class and Instance Variables?
    • Class Variables
    • Instance Variables
  • How do I use these variables?
  • Sub Classing With Class Variable
  • Let’s check their IDs

Pay Attention To Coding Style

During a regular day, depending on what ticket number I am working on I might work on multiple languages at a time. Usually these languages are:

  • Python
  • Java
  • Typescript (for AWS CDK; have a look at what CDKs are here.)
  • C/C++

Occasionally, I need to do Bash/ZSH shell scripting, or deal with a Go and/or Rust code. Sometimes even writing SQL code (or embed a SQL Query in a Python/Java code).

So, on a regular basis, I have to deal with a mixture of coding languages, within a day.

When switching from one coding language to another, the first thing that I do is: Taking a deep breath and reminding myself that now I am switching a coding language.
It is some sort of context-switching if you like. Or like that scene in matrix movie that she was uploading how to fly a helicopter. I need to take a moment to load that coding language in my mind.

Working on these different code basis, sometimes I see certain pattern from one coding language showing up in another language. One of these patterns are how objects are built.

Sometime in a Python code I see this pattern:

a_python_class_instance = (
	APythonClass().builder()
		.withParam_1(some_value)
		.withParam_2(some_value)
		...
		.withParam_n(some_value)
		.build()
)

If you have coded only in Python, the above pattern will look strange to you. But if you are from Java world, this looks completely natural to you. However, in Python the more natural looking way would be:

a_python_class_instance = APythonClass(
	param_1=some_value,
	param_2=some_value,
	...
	param_n=some_value,
)

Likewise, if you are from Java world, the second approach will look odd to you. Particularly, if there are more than 3 or 4 arguments that needs to be set, while creating an instance.

So, What should we learn from this?

First thing you need to learn is that to stop arguing with your co-workers what style you should go about. One style appearing strange to you might be absolutely normal to another person.

While you should stop arguing too much about the style, that doesn’t mean every person could choose whatever style that they want. Choose one style and make sure that you are consistent about it.

Add a style checking to part of your build, release, and deployment procedure. In a long run, it helps a lot if all the codes in one project are using the same style, it helps a lot in long run particularly when debugging.

In Python, there is a formal style guide called PEP 8 (here). Try to use that and deviate as little as possible. Yes, you can deviate from PEP8; but, you better have a good reason for it or you will be scorched by Python community. The Python community is not as flexible as the Python language itself. Take it from someone who was chased down for some style changes. OK! I was not really chased.

Fortunately, there are many styling packages available out there that you can use to automatically style your code. May be I write about them in another post.

Defining A Variable In A Class

If you are from Java world, this is usually how your code will look like:

public class AJavaClass {
    String firstName;
    String lastName;
    SomeOtherType someOtherVariable;
    ...
    SomeOtherType someOtherOtherVariable;

    public AJavaClass(...) {
        // Constructor goes here
        // btw __init__ in Python is not a constructor. It is Initializer. 
    }

    public/private OutputType somePrivateOrPublicMethods(...) {
        // Method implementations goes here.
    }
}

Of course, in a production code, there are a lot of injections happening that I personally absolutely think they are abomination; but hey, they are so common in Java world that at this point just suck it up and get used to it. Yes, the good point about it is that you will get used to them. Let’s say I still hate those injections and I think they do more harm in long run than good, but we have come to some sort of agreement to live in peace together.

Anyway, finally getting to the main point of this post, i.e. defining variables in a class using Python. I noticed that in some Python packages, written by professionals that came from Java world, the following style was used:

class Person:
    first_name: str
    last_name: str

    def __init__(self, first_name: str, last_name: str):
    	self.first_name = first_name
    	self.last_name = last_name

    def introduce(self):
        print(f"Hello! My name is {self.first_name} {self.last_name}.")

    # the rest of the code 

At first glance this looks ok. If you create an instance you will get something like this:

> p = Person(first_name="John", last_name="Doe")
> p.introduce()

Hello! My name is John Doe.

The code is working and everything is fine; or better to say seems fine. But, of course, there is an issue here.

So, what is the issue with Person Class?

Well, for all practical purposes, there is no issue with that Person class. But there is an issue.

remember we said that __init__ is not the constructor. Well, while the above style seems normal to you if you are from Java world, that is not normal in Python world, and in fact the above code is not exactly what you think it is.

The issue is that you might think that you have defined just two variables for that class, but you have actually defined 4. You have defined:

  • Two Class Variables
    • first_name defined on line 2
    • last_name defined on line 3
  • Two Instance Variables
    • first_name defined on line 6
    • last_name defined on line 7

Currently, the code is not making any use of Class Variables, and you are only using the two instance variables.

Let’s dig into this further.

What are Class and Instance Variables?

Class Variables

The class variables are defined outside of the __init__ block. If you define any variable outside of the __init__ method/block they become class variables.

If you have annotated your class with @dataclass or if you are extending BaseModel of Pydantic or another class that is a Pydantic model, then although you are defining the variables outside of the __init__ block, they are still not a class variable.

As you might guess, since these are class variables (i.e. belonging to the class rather than a specific instance) these variables are shared across all the instances of that class.

Instance Variables

Are those variable that you define inside __init__ method and you attach it directly to “self”, i.e. the specific instance. These variables are not shared across multiple instances of a class and they are unique to each instance.

How do I use these variables?

Let’s start with an example:

class MyClass:
    count: int = 0  # Use to count the number of instance

    def __init__(self, name: str, count: int):
        self.name = name
        self.count = count
        MyClass.count = MyClass.count + 1

    def print(self):
        print(f"name: {self.name:>22}, instance count: {self.count}, class count: {MyClass.count}")

    def print_ids(self):
        print(f"{self.name:22}        id(self.count): {id(self.count)}") 
        print(f"{self.name:22}     id(MyClass.count): {id(MyClass.count)}") 

As you can see we have three variable defined:

  • a class variable called count,
  • An instance variable called name, and
  • Another instance variable called also count just the same as our class variable.

So, while inside a class, you reference an instance variable with “self.{instance variable name}”. To reference a class variable, the best practice is to use the class name and the variable: “{Class Name}.{class variable}”.

For example in the above code we referenced the instance variable called count using “self.count”; and the class variable called count using: “MyClass.count”.

In our example, MyClass is defined in such a way that the instance variable “count” has the exact name as that of class variable; hence, essentially the instance variable count is masking the class variable count.

If your class variables are not masked by the instance variables (i.e. they don’t have the same name) you would be able to reference a class variable using self (i.e. “self.{class variable name}”). However, preferably do not do that.

Let’s see what happens when we instantiate two objects of MyClass:

> o1 = MyClass(name="First Object", count = 10)
> o1.print()

name:           First Object, instance count: 10, class count: 1

> o2 = MyClass(name="Second Object", count = 42)
> o1.print()
> o2.print()

name:           First Object, instance count: 10, class count: 2
name:          Second Object, instance count: 42, class count: 2

As you can see there is class variable count that is shared across all instances. When we create the first instance “o1”, that class variable is increased by one and set to 1. Later, when we create the second instance “o2”, the class variable count is increased one more time and set to 2; but since that variable is shared across all instances, the number 2 is reflected even on “o1”.

Both variable have their own instance variable count, that is not affected.

Sub Classing With Class Variable

Let’s create a sub-class of MyClass as follows:

class MySubClass(MyClass):
    count: int = 0  # used to count number of sub-classes.
    not_masked: int = 42
    def __init__(self, name: str, count: str):
        super().__init__(name=name, count=count)
        MySubClass.count = MySubClass.count + 1

    
    def print(self):
        super().print()
        print(f"\t- sub-class count: {MySubClass.count}")

    def print_ids(self):
        super().print_ids()
        print(f"{self.name:22}  id(MySubClass.count): {id(MySubClass.count)}") 

    def print_not_mask(self):
        # Preferably avoid referencing class variables using self.
        print("not_mask:", self.not_masked)

First, we introduced a new class variable called “not_masked”, just to show that if you do not have another instance variable with the same name, you can indeed reference a class variable using “self”. But again, preferably don’t do that.

But the main point we want to discuss in this section is the count that was reintroduced in the sub class. Now we have three variables with the same name called “count”:

  • An instance variable called “count” that is unique to each instance,
  • A class variable count that is shared across all instances of MyClass and/or its subclasses, and finally
  • Another class variable count that is shared across all isntances of MySubClass (and its subclasses, if there were any); but instances that are only of type MyClass (and not MySubClass) they don’t have access to this.

Essentially, we are using the count in MyClass to count the number of instances created that have MyClass or MySubClass type, and another count that only counts how many MySubClass’s instances are created.

Let’s create some instance and see what happens:

> so1 = MySubClass(name="First SubClass Object", count = 100)
> o1.print()
> o2.print()
> so1.print()

name:           First Object, instance count: 10, class count: 3
name:          Second Object, instance count: 42, class count: 3
name:  First SubClass Object, instance count: 100, class count: 3
	- sub-class count: 1

> so2 = MySubClass(name="Second SubClass Object", count = 420)
> o1.print()
> o2.print()
> so1.print()
> so2.print()

name:           First Object, instance count: 10, class count: 4
name:          Second Object, instance count: 42, class count: 4
name:  First SubClass Object, instance count: 100, class count: 4
	- sub-class count: 2
name: Second SubClass Object, instance count: 420, class count: 4
	- sub-class count: 2

Let’s check their IDs

Finally, to really see that these variables are indeed different, let’s check their ids:

> o1.print_ids()
> o2.print_ids()
> so1.print_ids()
> so2.print_ids()

First Object                  id(self.count): 4367625432
First Object               id(MyClass.count): 4367625240
Second Object                 id(self.count): 4367626456
Second Object              id(MyClass.count): 4367625240
First SubClass Object         id(self.count): 4367628312
First SubClass Object      id(MyClass.count): 4367625240
First SubClass Object   id(MySubClass.count): 4367625176
Second SubClass Object        id(self.count): 4495073712
Second SubClass Object     id(MyClass.count): 4367625240
Second SubClass Object  id(MySubClass.count): 4367625176

1 thought on “Migrating To Python From Java”

  1. Ali says:
    November 9, 2025 at 4:47 pm

    Nice post and good examples.

    If I see that issue in our team I’ll tell them to come and read this

    Reply

Leave a Reply to Ali Cancel reply

Your email address will not be published. Required fields are marked *

Search Posts

Latest Posts

  • Are you “Failing Fast” properly?
  • Migrating To Python From Java
  • Complicated or Complex
  • Face The challenges Heads On
  • Miranda Warning On Social Media In The Age of AI

Categories

  • Fundamentals
  • Linear Algebra
  • Mathematics
  • Memories
  • opinion
  • Piecewise-Linear
  • Programming
  • Python
  • SQL
  • Stories
  • Uncategorized

Archive

  • November 2025
  • October 2025
  • September 2024
  • March 2024
  • February 2024
  • January 2024
  • December 2023
© 2025 Moe’s Homepage | Powered by Minimalist Blog WordPress Theme