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
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
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
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:
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: https://refactoring.guru/design-patterns/singleton, you can also see some examples therein.
Back to data types again!
When variables are simple data types like
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.
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
db_session, where, e.g,
db_session is supposed to be an instance of
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
immutable objects are related to it.
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
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.