Python vs Mojo: Are we there yet?

Python vs Mojo: Are we there yet?

Hey there! I am new to both Python and Mojo languages. In this repository, I went on a mission to explore and compare these two languages from scratch, knowing only the basics of programming (I started off knowing only the basics of C++).

As I continue learning both languages, I'll be tracking my progress and updating the benchmarks in the following repository. Do give it a star ⭐️: https://github.com/grayhatdevelopers/mojo-vs-python-benchmarks/

Why did I do it?

I've always wanted to explore Python (because of how better it was than C++ according to many friends at university). During my internship at Grayhat, I was advised to learn Python alongside Mojo, given that they had a similar syntax.

I took the time to read through Mojo's documentation. It seemed promising and interesting. The team at Modular has designed Mojo to be a superset of Python, and it's specifically built for complex mathematical coding, something that would be required in Artificial Intelligence (What I'm currently studying in University, and the current market boom 🤯). Since it's a newer language, I can also expect it to offer new features and improvements, aligned with modern-day requirements.

This made me wonder:

Can Mojo be my daily driver? Can I use it to learn programming?

It gives the community a good chance to see how well Mojo can really replace Python, especially for its adoption by newcomers. It's often said that:

If you can't explain it to a six-year-old, you don't understand it yourself.”

Let's see how well Mojo and Python can explain themselves to, well, me!

Metrics for judging both the languages

I set out with the following metrics to judge between the two:

  1. (Which one of them was) User-friendly
  2. (Which one of them was) Easier to use
  3. (Which one of them is better in) Performance and stability

The environment which I tested all this in:

  1. OS: Ubuntu WSL on Windows 11
  2. Editor: VS Code
  3. Version of Python: Python 3.10.12
  4. Version of Mojo: Mojo 0.7.0 (af002202)
  5. My laptop specifications (Dell XPS 13):
  • Core i7 1165G7 @2.8GHz
  • 8GB DDR4 RAM
  • Integrated Graphics

Now that we've gotten that out of the way... Let's get technical with some experiments!


Experiments

Check the results below if you prefer not to go into the experiment details.

Results

For all the codes, Python ran significantly faster than Mojo and beat Mojo, in speed, by a huge margin (at least in my case).

Comparing the advantages of both

1: Python installation was much simpler compared to Mojo. Installing Mojo was not user-friendly; it would have been better if there was a one-click installation option for Mojo on Windows, similar to Python.

2: The syntax of Mojo and Python was quite similar, with the main difference being that in Mojo, you need to use Python functions by importing them. For example, to take user input, you have to import the "input" function from Python. This made Python easier to learn.

For example to use the input function, I first need to import it from Python and then use it in Mojo:

from python import Python
py = Python.import_module("builtins")
py.input("Enter your name")

3: Mojo provided helpful explanations with each error, making it easier for me to understand and identify my mistakes. Python, on the other hand, lacked this feature, which is an advantage of Mojo.

4: The code itself requires a main() function to be called in Mojo for it to run while Python runs as is.

i.e:

While Python can run without adding this main() function. Interesting design choice!

5: The Discord community of Mojo is very active and helpful. Their Discord has a chatbot which guides through every inconvenience with ease and is up to date with all the errors that I encountered while coding in Mojo

For example:

This bot is equipped with the latest info regarding Mojo, so was a very helpful feature

6: Python proved to be more user-friendly for me, mainly due to its proper documentation (because of it being older than Mojo). Moreover, the commands in Python were straightforward and simple to use, unlike Mojo, where there were some instances like for example me clearly stating the variable type (requiring explicit variable declarations), a step which I didnt have to do in Python

Programs

  1. Length of last word: returning the length of the last word in the string.
  2. Student attendance record: Whether or not the student is eligible for an attendance award
  3. Remove repeating letters: Removing the adjacent letters (one being capital) in a string.
  4. Detect Capital letter usage : Returning true if the usage of capitals in it is right.
  5. Find the difference: Returning the extra letter among 2 strings

Benchmarking and Testing

The performance of both languages was benchmarked using Hyperfine. Programs were tested and outputs were compared to see which one of them was faster (ran an additional code for testing the Memory)


Question 1

Given a string s consisting of words and spaces, return the length of the last word in the string. word is a maximal substring consisting of non-space characters only.

Python Code:

class Solution(object):
    def lengthOfLastWord(self, s):
        """
        :type s: str
        :rtype: int
        """
        enterword=s
       
        count=0
        for i in range(len(enterword)-1,-1,-1):
            

            if enterword[i] != " ":
                count+=1
            elif count>0:
                break
        return count

Mojo code:

from python import Python

def lengthOfLastWord(enterword: String):
    py = Python.import_module("builtins")
    
    count = 0
    for i in range(len(enterword)-1, -1, -1):
        if enterword[i] != " ":
            count += 1
        elif count > 0:
            break
    
    print("Length of the last word:")
    print(count)

def main():
    input_string = "Hello World" 
    lengthOfLastWord(input_string)

Link: https://leetcode.com/problems/length-of-last-word/description/

Benchmarks

Benchmark 1 (Python): python3 problem-1.py

Time (mean ± σ): 11.1 ms ± 1.6 ms [User: 9.4 ms, System: 1.8 ms]

Range (min … max): 8.8 ms … 22.1 ms 212 runs Avg memory: 8412k

Benchmark 2 (Mojo): mojo problem-1.mojo

Time (mean ± σ): 222.3 ms ± 9.7 ms [User: 238.4 ms, System: 28.6 ms]

Range (min … max): 205.5 ms … 238.0 ms 14 runs

Avg memory: 38548k

Which performed better?

The Python code ran 19.95 ± 3.02 times faster than Mojo code

Question 2

Given an integer x return true if x is a palindrome and false otherwise

Python Code:

def checkRecord(attendance_record):
    
    attendance_record_str = str(attendance_record)

    absent_count = 0
    late_count = 0

    for i in range(len(attendance_record_str)):
        
        if attendance_record_str[i] == 'A':
            absent_count += 1
            late_count = 0
        elif attendance_record_str[i] == 'L':
            late_count += 1
        else:
            late_count = 0

        if late_count >= 3 or absent_count >= 2:
            print("The attendance record is not acceptable.")
            return False

    print("The attendance record is acceptable.")
    return True

#
def main():
    checkRecord("PAALP")
    
main()

Mojo Code:

from python import Python

def checkRecord(attendance_record: String):
    py = Python.import_module("builtins")
    attendance_record_str = attendance_record

    absent_count = 0
    late_count = 0

    for i in range(len(attendance_record_str)):
        
        if attendance_record_str[i] == 'A':
            absent_count += 1
            late_count = 0
        elif attendance_record_str[i] == 'L':
            late_count += 1
        else:
            late_count = 0

        if late_count >= 3 or absent_count >= 2:
            print("The attendance record is not acceptable.")
            return False

    print("The attendance record is acceptable.")
    return True

def main():
    checkRecord("PAALP")

Link: https://leetcode.com/problems/student-attendance-record-i/description/

Benchmarks

Benchmark 1 (Python): python3 problem-2.py

Time (mean ± σ): 11.9 ms ± 2.2 ms [User: 9.8 ms, System: 2.2 ms]

Range (min … max): 8.8 ms … 23.0 ms 316 runs

Avg memory: 8392k

Benchmark 2 (Mojo): mojo problem-2.mojo

Time (mean ± σ): 236.4 ms ± 5.3 ms [User: 259.6 ms, System: 21.9 ms]

Range (min … max): 228.0 ms … 243.9 ms 12 runs

Avg memory: 39080k

Which performed better?

The Python code ran 19.78 ± 3.59 times faster than the Mojo code

Question 3

Given a string s of lower and upper case English letters. A good string is a string which doesn't have two adjacent characters s[i] and s[i + 1] where:
  • 0 <= i <= s.length - 2
  • s[i] is a lower-case letter and s[i + 1] is the same letter but in upper-case or vice-versa.
To make the string good, you can choose two adjacent characters that make the string bad and remove them. You can keep doing this until the string becomes good. Return the string after making it good. The answer is guaranteed to be unique under the given constraints. Notice that an empty string is also good.

Python Code:

def makeGood(s):
    result = ""

    i = 0
    while i < len(s):
        
        if i < len(s) - 1 and abs(ord(s[i]) - ord(s[i + 1])) == 32:
            
            i += 2
        else:
           
            result += s[i]
            i += 1

    return result

def main():
    
    input_str = "leEeetcode"
    output_str = makeGood(input_str)
    print(output_str)

main()

Mojo Code:

from python import Python

def makeGood(s: String):
    py = Python.import_module("builtins")
    result = str("")

    i = 0
    while i < len(s):
        
        if i < len(s) - 1 and py.abs(ord(s[i]) - ord(s[i + 1])) == 32:
            
            i += 2
        else:
           
            result = result + s[i]
            i += 1

    print(result)

def main():
    
    input_str = "leEeetcode"
    makeGood(input_str)

Link: https://leetcode.com/problems/make-the-string-great/

Benchmarks

Time (mean ± σ) Range (min … max) Avg.Memory Runs Python 10.0 ms ± 2.4 ms 7.2 ms … 26.2 ms 8240k 111 runs Mojo 176.9 ms ± 17.0 ms 161.6 ms … 216.5 ms 39000k 13 runs

Which performed better?

The Python code ran 17.67 ± 4.61 times faster than the Mojo code.

Question 4

You are given a string s representing an attendance record for a student where each character signifies whether the student was absent, late, or present on that day. The record only contains the following three characters:
  • 'A': Absent.
  • 'L': Late.
  • 'P': Present.
The student is eligible for an attendance award if they meet both of the following criteria:
  • The student was absent ('A') for strictly fewer than 2 days total.
  • The student was never late ('L') for 3 or more consecutive days.
Return true if the student is eligible for an attendance award, or false otherwise.

Python Code:

def detectCapitalUse(word):
    
    
    uinput = str(word)

    number_of_capital_letters = 0
    for i in range(len(uinput)):
        letter = uinput[i]
        if ord(letter) < 97:
            number_of_capital_letters += 1

    number_of_small_letters = len(uinput) - number_of_capital_letters

    if number_of_capital_letters == len(uinput) or number_of_small_letters == len(uinput) or (ord(word[0]) < 97 and number_of_capital_letters == 1):
        return True
    else:
        return False

def main():
    result = detectCapitalUse("USA")
    print("Result:")
    print(result)
main()

Mojo Code:

from python import Python

def detectCapitalUse(word: String):
    py = Python.import_module("builtins")
    
    uinput = word

    number_of_capital_letters = 0
    for i in range(len(uinput)):
        letter = uinput[i]
        if ord(letter) < 97:
            number_of_capital_letters += 1

    number_of_small_letters = len(uinput) - number_of_capital_letters

    if number_of_capital_letters == len(uinput) or number_of_small_letters == len(uinput) or (ord(word[0]) < 97 and number_of_capital_letters == 1):
        return True
    else:
        return False

def main():
    result = detectCapitalUse("USA")
    print("Result:")
    print(result)

Link: https://leetcode.com/problems/detect-capital/description/

Benchmarks

Benchmark 1 (Python): python3 problem-4.py

Time (mean ± σ): 11.1 ms ± 1.3 ms [User: 9.6 ms, System: 1.7 ms]

Range (min … max): 9.8 ms … 17.4 ms 260 runs

Avg memory: 8420k

Benchmark 2 (Mojo): mojo problem-4.mojo

Time (mean ± σ): 230.1 ms ± 10.1 ms [User: 249.7 ms, System: 26.7 ms]

Range (min … max): 215.3 ms … 252.0 ms 13 runs

Avg memory: 38820k

Which performed better?

The Python code ran 20.64 ± 2.52 times faster than the Mojo code

Question 5

You are given two strings s and t. String t is generated by random shuffling string s and then add one more letter at a random position. Return the letter that was added to t.

Python Code:

def findTheDifference(s, t):
    
    for i in range(len(t)):
        if s[i] != t[i]:
            result = t[i]
            break

    print("The difference is:", result)

def main():
    findTheDifference("abcd", "abced")
main()

Mojo Code:

from python import Python

def findTheDifference(s:String, t:String):
    py = Python.import_module("builtins")
    
    for i in range(len(t)):
        if s[i] != t[i]:
            result = t[i]
            print("The difference is:")
            print(result)
            break

def main():
    findTheDifference("abcd", "abced")

Link: https://leetcode.com/problems/find-the-difference/description/

Benchmarks

Time (mean ± σ) Range (min … max) Avg.Memory Runs Python 9.7 ms ± 1.3 ms 7.3 ms … 15.6 ms 8420k 304 runs Mojo 178.0 ms ± 10.9 ms 167.2 ms … 205.7 ms 8500k 14 runs

Which performed better?

The Python code ran 18.31 ± 2.70 times faster than the Mojo code.


Final Remarks

This is the conclusion I came up to after experimenting with both Python and Mojo, from installation up until their usage.

  1. User Friendly: For someone like me who doesn't know much about programming languages, I found Python to be more user-friendly. From installing the software to writing code, Python was easier to understand. Installing Python was a simple one-click process, while it took me some time to figure out how to install Mojo, especially because I'm not familiar with terminals and Ubuntu. When it comes to writing code, Python was straightforward and easy to grasp, whereas with Mojo, I had to pay attention to small details to make sure the code worked correctly. So Mojo was harder for me and other new users to adopt and understand
  2. Easier to Use: Mojo and Python have similar ways of writing code, so it wasn't too difficult to understand both of them. However, Mojo uses functions from Python, even for simple tasks like "taking input." In Mojo, I had to use a prefix like "py.input" instead of just "input" in Python. This got confusing, and I had to make sure to use the right prefixes for each command, making Python seem simpler and more straightforward. Additionally, a feature I really liked in Mojo was that it explained why an error occurred inside the code. This made it easier for me to figure out exactly what went wrong, which is a feature lacking in Python.As for the REPL, the REPL of Mojo showed the line number for each line of code while Python didn’t. However, I couldn’t use Python-based functions in Mojo when I tried it from REPL. For example when I tried the input function in MOJO, the REPL would stop responding:

While it worked perfectly on Python:

I didn’t do a lot on REPL but when I did, this is what I found. Also, the speed of Mojo was slower even in the REPL. It took longer for Mojo to print a simple “Hello World” than Python.

3. Performance and Stability: I noticed a small delay in how quickly the code ran between Python and Mojo. The difference was more noticeable, especially when I coded directly in the terminal instead of using VS Code. So, when it comes to performance, Python is significantly faster than Mojo. The reason I believe made Python faster than Mojo was that Mojo needs to import functions from Python for it to use them. So that importing might be the reason for it to run a bit slower while Python uses it’s own function hence the speed difference.

In terms of stability, both languages worked well during my usage. However, I did encounter a strange error when I tried to import Python variables inside a function (which is supposed to be done globally, outside the function). Here's an error I faced:

Quite a raw error, considering it mentions LLVM. Maybe it's for the big guys.

Regarding stability, I don’t have a solid answer to it. Both of the languages ran smoothly without me having to face bugs or glitches.

Overall, I had tonnes of fun and learned a lot about programming languages. I really hope this breakdown helps more noobs on their way to keyboard-breaking glory, and inspires them to try out new tech, specially in its early stages. Peace!