Get access
Coding 8 min read

Tips, Tricks, and Tools for Java Developers Programming in Python

How to avoid mistakes in loosely-typed programming languages: The obstacles and some of the tips and methods when moving from Java or other statically-typed programming languages to Python.
Fariborz Mafakehri

I’ve been a Java/Kotlin developer for almost 5 years and transitioned to Python when I started working at Reasonal. There are benefits and drawbacks to all programming languages and I don't want to make a general comparison here. Python is a beautiful high-level programming language. You can learn the syntax fast and implement simple scripts right away. But that’s just the beginning: Down the road, you’ll find some obstacles that you didn’t expect.

What I want to share are some of the special quirks that Python has, some hurdles you will face when moving from Java to Python, as well as some tricks that I used to overcome them.

The obvious issue: Naming in Python

The first hurdle that most non-Python developers stumble upon when using Python is the naming. Arrays are called array in almost every language - not so in Python, where they are called list! To use a library you're usually using the include keyword, but in python it’s import. The array list of naming confusions is long, but those are just minor obstacles and you can get used to them quickly.

Let's continue onto the bigger issues.

No data types for variables in Python

Defining data types for variables is optional. You can simply use a variable and assign a string (so, somehow the variable type is implicitly set to string) but in the middle of coding you can assign a number to it and change it to a number type. Between programmers, that is bad practice, but the language allows you to do it.

That means your expectation and behavior of this variable have completely changed now: It was supposed to be a string but suddenly changed to a number. What if you assign another variable to it, which you don’t know the type of? What if it’s coming as the input of a function?

Generally, it’s better to define the data type for each variable, it will make the code much more readable and maintainable. My tip is: One of the libraries that is helpful here is typing and one of the classes that I like is Optional which is good for handling None objects.

Retrieving the parameters of the REST API's

We are using flask to implement our web application. One of the challenges I had was understanding the flask query strings and the request body variables in a glance, so you know what input the API expects. In the middle of the code you can simply say request.get.args(“another_variable”) and ask for a new query string. This is also true for the request body of POST requests.

The solutions that I found is using the marshmallow or flask.expects_json libraries - I prefer marshmallow. By using marshmallow in Python, you can define complex bodies, e.g:

class RequestBodySchema(Schema):
	class MessageSchema(Schema):
	type = fields.Str(required=True, validate=Length(max=MAX_SIZE))
	    class Content(Schema):
	        type = fields.Str(required=True, validate=Length(max=MAX_SIZE))

	        class NestedContent(Schema):
	            title = fields.Str(required=True, validate=Length(max=MAX_SIZE))
	            subtitle = fields.Str(required=False, validate=Length(max=MAX_SIZE))

	            class Meta:
	                # Include unknown fields in the deserialized output
	                unknown = INCLUDE

	        user_text = fields.List(
	            fields.Nested(NestedContent, required=True), required=False

	        class Meta:
	            # Include unknown fields in the deserialized output
	            unknown = INCLUDE

	    content = fields.List(fields.Nested(Content))

	    class Meta:
	        # Include unknown fields in the deserialized output
	        unknown = INCLUDE

	user_name = fields.Str(required=True, validate=Length(max=MAX_SIZE))
	action_type = fields.Str(required=True, validate=Length(max=MAX_SIZE, min=1))
	corporation_id = fields.Int(required=True)
	message = fields.Nested(MessageSchema(), required=True)

As you see it's quite complicated and a bit error prune, but it's better than not having anything.

Python modules follow a Singleton pattern

This one is not necessarily a pain, but it is important to be aware of this difference to Java and other programming languages:

Modules are Singleton in Python, so if two different Python modules call another module, the scripts of the latter one will run just once. Be aware of setting some variables there. In order to get more familiar with Singleton design patter, I suggest you this link:, you can also see some examples therein.

Back to data types again!

When variables are simple data types like string, int, etc., life is still pretty manageable. However, when variables in a Python code are supposed to be instances of classes, you sometimes want to find out which class they are - suddenly, life is not easy anymore. You can not simply see the internal functions/attributes of that object and this becomes a real problem. Especially, when they become the input to a function and you have no idea to what class this variable belongs to.

Pylance is one of the VS code extensions that can be helpful if you want to set or find the data type of variables.

But, I want to stress that it’s better to explicitly determine the data type of variables in Python :)

Let me give you an example: When inside a function and there are inputs like request or db_session, where, e.g, db_session is supposed to be an instance of Session in sqlalchemy.orm . You can simply call the internal functions of that object, and during runtime it will work perfectly, but if you call a wrong function, you'll only get an error during runtime!

So try to use data types as much as possible to make the life of others and future "you" easier :)

Is it pass by value or pass by reference?

None and both! It’s a mystery. In Python, you can say it's both pass by value or pass by reference. Life would be simpler if Python had picked one of them, just like other programming languages. Python is pass by object reference. I suggest this article to get more familiar with the concept and also see how mutable and immutable objects are related to it.

DB migrations

This one is not a big deal at all, but worth mentioning. We use Alembic for our MySql DB migrations, and we were not able to use Enum for our DB columns because the changes of Enum were not detected by Alembic. Enum is supported by Alembic but it picks the values just once - be aware.

What to take away when using Python as a Java developer

I hope I could shed some light onto some of the difficulties or things to watch out for when using Python as a non-Python developer. Do let me know if you have questions, or if you found other obstacles and/or tips to overcome them.

Of course, we are also always looking for talent, too, find job openings here or contact us via our homepage.


Fariborz Mafakehri

Fariborz Mafakehri
Software Engineer



Enjoy the read?

Receive our monthly digest of future-of-work topics, coding insights, and Reasonal updates. Be the first to get early-access offers for our tool.

Unsubscribe anytime.

More from Reasonal

Sign up and stay in the loop.

Receive our monthly digest of future-of-work topics, coding insights, and Reasonal updates. Be the first to get early-access offers for our tool.
Unsubscribe anytime.