Java vs Python: What Should a Java Developer Know About Python?

Java vs Python: Basic Python for Java Developers

Python is a general-purpose programming language. You can understand its growth in the last couple of years by considering its approachability for learning and its high suitability for data analysis, machine learning, and web development. But what kind of programming language is it? What are some differences when you compare Java vs Python? What can you do with it? And is it really as “easy to learn” as some people claim?

You’ll explore Python from a Java perspective in this tutorial. After you’ve read it, you’ll be able to decide whether Python is a viable option to solve your use cases and to appreciate when you can use Python in combination with Java for certain types of problems.

In this tutorial, you’ll learn about:

  • The general Python programming language syntax
  • The most relevant standard data types
  • The differences and similarities in Java vs Python
  • Resources for high-quality Python documentation and tutorials
  • Some of the Python community’s favorite frameworks and libraries
  • Approaches for getting started with Python programming from scratch

This tutorial is for software developers who are familiar with Java’s inner workings, concepts, terminology, classes, types, collections framework, and so on.

You don’t need to have any Python experience at all.

Where Does Python Come From?

Python is a programming language that was developed by Guido van Rossum. He was looking for a hobby programming project that would keep him occupied during the Christmas holiday in 1989, so that’s when he started developing the Python interpreter.

Python has its origins in a number of languages: ABC, C, and Modula-3. It’s basically an object-oriented, imperative programming language.

Depending on your preference and desired functionality, it can be applied in a full object-oriented style or in a procedural programming style with functions. The object-oriented capabilities are addressed later in this tutorial.

Additionally, a more functional programming style is also perfectly possible. To learn more, you’ll want to explore Python’s functional programming capabilities.

In early 2021, TIOBE announced Python as the programming language of the year for the fourth time. As of the 2021 Octoverse report, Python ranks as the second most popular language on GitHub by repository contributors.

What Is the Philosophy of Python?

Soon, you’ll get hands-on with Python in the sections following this one. First, however, you’ll explore why it’s worth getting to know Python better by going through some features that you can trace back to Python’s philosophy.

Some ideas behind Java and Python are similar, but every programming language has its own unique characteristics. The philosophy of Python is captured as a collection of nineteen guiding principles, the Zen of Python. Python hides a few Easter eggs, and one of them is the Zen of Python. Consider what happens when you issue the following command in the Python read–eval–print loop (REPL):

Python
>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

While you shouldn’t take the statements above too literally, a few of these relate directly to the characteristics that you’ll walk through next.

By considering the guiding principles of the Zen of Python, you’ll get a good idea about how you can approach working with the language.

Python Code Is Readable

If you come from a Java background and you look at a typical fragment of Python code, you might think that you’re looking at pseudo-code. There are a few factors that contribute to this:

  • Indentation is used for statement grouping. This makes code blocks shorter and promotes a uniform coding style. You’ll find more on this topic later on.
  • A few built-in high-level data structures, combined with a modest set of operator symbols, make Python very expressive.
  • The choice of using exceptions as the primary way to deal with errors keeps the code clean.
  • Python programmers prefer a coding style inspired by the concept that it’s Easier to Ask for Forgiveness than Permission (EAFP) instead of the Look Before You Leap (LBYL) concept. This style puts emphasis on the normal, happy path of your program, and you’ll figure out how any anomalies are handled afterward. For more information on these two coding styles, check out LBYL vs EAFP: Preventing or Handling Errors in Python.

You can find a few examples of how this appears in practice during this tutorial, as well as in other linked resources.

Python Comes With Batteries Included

The aim of Python is that you can solve the majority of everyday problems with just the standard distribution of Python. To that purpose, Python includes what’s called the standard library. Just like the Java Class Library, it’s an extensive collection of useful facilities consisting of constants, functions, classes, and frameworks.

For further acquaintance with the Python standard library, check out the first part and the second part of the Brief Tour of the Standard Library in the Python docs’ Python tutorial.

Python Promotes Code Reuse

Python provides several features that enable you to develop code that you can reuse in different places to apply the Don’t Repeat Yourself (DRY) principle.

One feature is that you typically decompose your code into modules and packages within Python. Note, however, that Python modules and packages are different from Java modules and packages. If you want to learn more about these concepts from the perspective of a Python developer, you can read about Python modules and packages.

Another technique that you can use within Python is object-oriented programming. You’ll explore this later on in this tutorial.

You can also use decorators to modify Python functions, classes, or methods. This is yet another technique so that you can program functionality only once, after which it can be used from any function, class, or method that you’ve decorated.

Python Is Easily Extensible

The support of modules and packages is one of the ingredients that makes it easy to extend Python with new functionality. You can also define new or adapted behavior to Python standard operators and functions by overloading them. It’s even possible to influence how classes are created.

The most straightforward way to extend Python is to write your code in pure Python. You can also define modules by using bindings in a stripped-down dialect of Python, called Cython, or in C or C++.

How Can You Start Discovering Python?

In this tutorial, you’ll find examples that might encourage you to explore certain things or to try out Python code fragments for yourself. As a Java developer, you might remember your first steps in getting acquainted with Java and installing your first Java Development Kit. Likewise, if you want to get started with Python, you’ll first need to install it and then create a sandbox where you can safely experiment.

There are already a couple of tutorials that explain how to do this, so the next subsections will point you to these resources.

Installing Python

The first step is to install a recent version of Python. In order to do that, follow this Python 3 installation and setup guide.

Another place you can look for installation instructions is the official Python download page.

Many Python developers contribute to libraries that support various Python versions, and they often prefer to try out a pre-release of Python without disturbing their regular Python work. In those situations, it’s convenient to have access to multiple versions of Python on the same machine. A tool that provides that functionality is pyenv, which is comparable to Java’s jEnv.

Creating a Sandbox and Using It

As a second step, you should set up a virtual environment so that you can safely take advantage of the open source Python ecosystem. This section explains how and why you should do that.

Although Python comes with an extensive standard library with all kinds of functionality, there’s even more functionality available in the form of external packages, of which the vast majority are open source. The Python Package Index, or PyPI for short, is the main central repository that collects and provides these packages. You can install packages with the pip command. Before you do that, however, first read the next two paragraphs.

To avoid dependency version conflicts, you generally shouldn’t share your global or personal Python installation between projects. In practice, you accompany each project or experimentation sandbox with a virtual environment.

This way, your projects stay independent from one another. This approach also prevents version conflicts between packages. If you want to know more about this process, then you can read in detail about how to create and activate your virtual environments.

Choosing an Editor or Integrated Development Environment

As a final step to getting set up, decide on which editor or IDE you’d like to use. If you’re used to IntelliJ, then PyCharm seems to be the logical choice because it belongs to the same line of products. Another popular editor on the rise is Visual Studio Code, but you can also choose from many other options.

After you’ve installed Python, learned how to install external packages into a virtual environment, and chosen an editor or IDE, you can start experimenting with the language. As you read through the rest of this tutorial, you’ll find plenty of opportunities to experiment and practice.

How Is Python Different From Java?

You can quickly get a feel for what kind of programming language Python is by looking at where the most striking differences are. In the following subsections, you’ll get to know the most important ways that Python is different from Java.

Indentation for Code Block Grouping

Perhaps the most striking feature of Python is its syntax. In particular, the way you specify its functions, classes, flow-control constructs, and code blocks is quite different from what you might be used to. In Java, you indicate code blocks with the well-known curly braces ({ and }). In Python, however, you indicate code blocks by the indent level. Here you see an example that demonstrates how the indentation determines code block grouping:

Python
 1def parity(number):
 2    result = "odd"                              # Function body
 3    if number % 2 == 0:
 4        result = "even"                         # Body of if-block
 5    return result                               # Not part of if-block
 6
 7for num in range(4):                            # Not part of function
 8    print("Number", num, "is", parity(num))     # Body of for-loop
 9print("This is not part of the loop")           # Not part of for-loop

The code displays a few new concepts:

  • Line 1: The def statement starts the definition of a new function named parity(), which accepts an argument called number. Note that if the def statement had appeared within a class definition block, it would have started a method definition instead.
  • Line 2: Within parity(), the function body starts on an indented level. The first statement is an assignment of the "odd" string to the result variable.
  • Line 3: Here you see the start of an if statement.
  • Line 4: The extra indent starts a new block. This block is executed when the conditional expression of the if statement, number % 2 == 0, evaluates to true. In the example, it only consists of a single line where you assign "even" to the result variable.
  • Line 5: The dedent that precedes the return statement marks the end of the if statement and its associated block.
  • Line 7: Likewise, you see the dedent that precedes the beginning of the for loop. Consequently, the for loop starts at the same indent level as the start of the function definition block back on the first line. It marks the end of the function definition block.
  • Line 8: You see the same happening again within the for loop. The first print() function call is part of the for loop block.
  • Line 9: This second dedented print() function call isn’t part of the for loop block.

You might have noticed that a colon (:) at the end of a line introduces a new sub-block of code, which should be indented one level. This code block ends when the next statement is dedented again.

A code block must consist of at least one statement. An empty code block is simply not possible. In the rare occasion that there isn’t any statement needed, you can use the pass statement, which does nothing at all.

Finally, you’ve probably also noticed that you can use the hash sign (#) for comments.

The above example will result in the following output:

Shell
Number 0 is even
Number 1 is odd
Number 2 is even
Number 3 is odd
This is not part of the loop

Although this way of defining blocks may seem weird at first sight and might even scare you off, experience shows that people get used to it sooner than you might be thinking right now.

There’s a helpful style guide for Python code called PEP 8. It recommends using an indent level of four positions, using spaces. The style guide doesn’t recommend using tabs in the source code files. The reason is that different editors and system terminals might use inconsistent tab stop positions and render the code differently for various users or between various operating systems.

You can find a lot of interesting information in PEP 8, including Python naming conventions. If you read over them, you’ll see that these are slightly different from Java’s.

A Read-Eval-Print Loop From the Beginning

From its inception onwards, Python has always had a built-in read–eval–print loop (REPL). The REPL reads the shortest possible complete statement, expression, or block, compiles it into bytecode, and has it evaluated. If the evaluated code returns an object other than the None object, it outputs an unambiguous representation of this object. You’ll find an explanation of None later in this tutorial.

The following fragment shows how Python’s REPL works:

Python
>>> zero = int(0)
>>> zero
0
>>> float(zero)
0.0
>>> complex(zero)
0j
>>> bool(zero)
False
>>> str(zero)
'0'

As you can see, the interpreter always attempts to show the resulting expression values unambiguously. In the example above, you can see how the integer, floating point, complex, Boolean, and string values are all displayed differently.

A difference between Java and Python involves the assignment operator (=). A regular Python assignment, which uses a single equals sign, is a statement rather than an expression, which would yield some value or object.

This explains why the REPL doesn’t print the assignment to the variable zero: statements always evaluate to None. The line following the assignment contains the variable expression, zero, to instruct the REPL to display the resulting variable regardless.

In the REPL, the underscore special variable (_) holds the value of the last expression, provided it’s not None. The following fragment shows how you can use this special variable:

Python
>>> 2 + 2
4
>>> _
4
>>> _ + 2
6
>>> some_var = _ + 1
>>> _
6
>>> some_var
7

After you assign the value 7 to some_var, the special variable _ still holds the value 6. That’s because the assignment statement evaluates to None.

Dynamically Typed and Strongly Typed

An important characteristic of a programming language is when, how, and to what extent the language interpreter or compiler performs type verification.

Python is a dynamically typed language. This means that the types of variables, function parameters, and function return values are checked at runtime rather than at compile time, unlike Java.

Python is at the same time a strongly typed language:

  • Every object has a specific type associated with it.
  • Explicit conversion is needed between incompatible types.

Here, you’ll explore how Python checks type compatibility at runtime and how you can make types compatible:

Python
>>> 40 + "2"
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
>>> 40 + int("2")  # Add two numbers
42
>>> str(40) + "2"  # Concatenate strings
'402'
>>> 40 * "2"       # Repeat string "2" forty times
'2222222222222222222222222222222222222222'

You’ll notice that you can’t just add an integer value to a string value. This is guarded during runtime. When the interpreter detects a runtime error, it generates an exception. The REPL catches Exception instances and shows the traceback leading to the erroneous expression.

To resolve the issue, you convert one type to the other. If you want to add the two objects together as numbers, you convert the string representing the number into a plain number by using the int() constructor. If you’d like to concatenate the two objects as strings instead, then you convert the number into a string by using the str() constructor.

The last line of the Python session above shows another feature. By multiplying a sequence with a number, you get the concatenated result of the original sequence, repeated by the given number.

Although Python is a dynamically typed language, it’s possible to provide the code with type annotations.

During runtime, Python does nothing with these annotations except for making them available for introspection. However, static type checker tools exist that can detect inconsistencies between the type declarations and the actual use of type-annotated functions, classes, and variables.

Type annotations help you detect errors at an early stage of the code development cycle. Especially in large-scale software projects, they help you make the code more maintainable and keep the codebase in good shape. You typically invoke a static type checker as part of the verification step in the build pipeline. Most IDEs make use of type annotations as well.

CPython vs the JIT Compiler

Unlike Java, Python’s reference implementation has no JIT compiler. By far, the most used Python implementation is CPython. This is also the reference implementation. CPython is a compiler and interpreter that’s been written in C and is pretty much available on every conceivable platform.

CPython loads a source file, which is called a module, in two steps:

  1. Compilation: First, CPython reads the code and compiles it into bytecode, which is a sequence of instructions that the CPython bytecode interpreter can execute. To a limited extent, you can compare the compilation phase with how Java’s javac compiles a .java file into a .class file.
  2. Execution: The CPython bytecode interpreter—in other words, CPython’s virtual machine (VM)—subsequently executes the bytecode from the first step.

Unlike the mainstream Java VM implementations, CPython does not subsequently compile the bytecode into native object code. There are, however, other Python implementations that work differently:

  • There’s a Python implementation for the Java platform called Jython. It runs in the JVM, and there’s a direct interoperability between Java and Python.
  • Likewise, there’s a version called IronPython that runs on the .NET platform.
  • There’s an implementation using a Just-in-Time (JIT) compiler called PyPy. On average, PyPy is 4.2 times faster than CPython.
  • Finally, GraalVM is a high-performance runtime that supports many programming languages. It provides experimental support for a fairly recent Python version.

The list above isn’t exhaustive. The Python site contains a list of alternative implementations and distributions.

Built-in Function and Operator Overloading

As a Java developer, you might know the term overloading from method overloading. While there’s a dynamic equivalent, @singledispatchmethod, available in Python that provides a somewhat similar functionality, there exists yet another kind of overloading in Python that you may find much more useful.

You can define new behavior of your custom-built classes for any eligible Python built-in functions and operators.

Python provides an accessible way to achieve function and operator overloading.

You can try this by defining specially named methods in your class. The name of such a method starts and ends with two underscores, like .__len__() or .__add__(). An identifier having such a name is called a dunder, short for double underscore (__).

When you call an eligible built-in function with an object for which a corresponding dunder method is present, Python delegates the behavior to this method. Likewise, when you use an operator for which one or more of the operands contain a corresponding dunder method, Python delegates the behavior to that method.

For example, you can define .__len__() to provide behavior to the built-in len() function. Likewise, you can define .__add__() to provide behavior to the addition operator (+).

This feature makes it possible to apply the nice, expressive, and terse syntax of Python code not only to the standard objects but to custom objects as well.

Nice Syntax for Functional Processing of Collections

In Java, you might have constructed lists by combining calls of map(), filter(), and lambda expressions. You can do the same in Python, using the same functions and techniques. Using these constructs doesn’t always result in the most readable pieces of code.

Python provides an elegant alternative syntax for this basic functional manipulation of lists and other collections. You’d use list comprehensions for lists and other kinds of comprehensions for other collections. If you want to know more about comprehensions in Python, then you can explore when to use a list comprehension.

Everything Is an Object

In Java, not everything is an object, despite the fact that the only place where you can put your code is inside a Java class. For example, the Java primitive 42 isn’t an object.

Just like Java, Python also fully supports an object-oriented style of programming. Different from Java is that everything is an object in Python. Some examples of Python objects are:

Because they’re objects, you can store all of these in variables, pass them around, and introspect them at runtime.

Metaclasses, combined with the ability to overload built-in functions and operators, are part of what makes Python a versatile programming toolkit. They allow you to create your own programmable universe of additional or alternative behavior of classes and instances.

What Aspects of Java and Python Are Similar?

Despite the differences, you’ve probably also spotted some similarities between Java and Python already. That’s because Python and Java were both inspired by the C programming language. During your continuing exploration of Python, you’ll discover a lot more similarities to Java.

Class-Based Object Orientation

Python is a class-based, object-oriented programming language, which is also one of the main features of Java. However, the set of object-oriented features differ between both languages and to address these in sufficient detail deserves a tutorial of its own.

Fortunately, you can dig deeper into object-oriented programming in Python vs Java to get an overview of the differences between Java and Python regarding object-oriented programming constructs. You can also check out an overview of object-oriented programming in Python 3 to expand your knowledge about this topic.

Operators

One aspect where you might notice the languages’ shared heritage is in how they use operators. Many of them have the same meaning in both languages.

To start off, compare the well-known arithmetic operators in Java vs Python. The addition operator (+), subtraction operator (-), multiplication operator (*), division operator (/), and modulo operator (%) have almost the same purpose in both languages—except for the division operator on integer-like operands.

The same holds true for the bitwise operators: the bitwise OR operator (|), the bitwise AND operator (&), the bitwise XOR operator (^), and the unary bitwise NOT operator (~), as well as the bitwise shift operators for left shift (<<) and right shift (>>).

You can use the square bracket syntax ([]) in Python to access an element of a sequence, just like how you can work with Java’s array access.

The later sections on data types provide more detail on these and some additional operators. Or, if you want to know more about them right now, you can read about operators and expressions in Python.

String Formatting

Initially, Python offered string formatting functionality based on how the printf family of functions handles this in the C programming language. This is similar to Java’s String.format(). In Python, the % operator performs this function. The left-hand side of the operator contains the format string, and the right-hand side contains either a tuple of positional parameters or a dictionary of keyed parameters.

The following session shows some examples:

Python
>>> "Hello, %s!" % "world"             # %-style, single argument
'Hello, world!'
>>> "The %s is %d." % ("answer", 42)   # %-style, positional
'The answer is 42.'
>>> "The %(word)s is %(value)d." \
... % dict(word="answer", value=42)    # %-style, key-based
'The answer is 42.'

More recently, Python has embraced other ways of formatting strings. One is to use the .format() string method, where the replacement fields are indicated with curly braces ({}). An example of this is "The {word} is {value}.".format(word="answer", value=42).

Since Python 3.6, you can also use formatted string literals, also known as f-strings. Suppose you have two variables in scope named word and value. In that case, the expression f"The {word} is {value}." renders the same string for you as the .format() example above.

Control Flow Constructs

The control flow constructs are similar when comparing Java vs Python. This means that you probably intuitively recognize many of the control flow constructs. On a more detailed level, however, there are also differences.

A Python while loop is similar to Java’s:

Python
while (word := input("Enter word: ")) != "END":
    print(word)

print("READY")

Line by line, the code fragment copies the standard input to the standard output until the line equals "END". That line isn’t copied, but the text "READY" is written instead, followed by a newline.

You’ve probably noticed the added value of the walrus operator in a construct like this. The precedence of this assignment expression operator is the lowest of all operators. This means that you frequently need to add parentheses around the assignment expression when it’s part of a larger expression, just like in Java.

The Python for loop is similar to the Java for-each loop. This means that if you want to iterate over a list of the first five Roman numerals, for example, you could code it using a similar logic:

Python
>>> roman_numerals = "I II III IV V".split()
>>> roman_numerals
['I', 'II', 'III', 'IV', 'V']
>>> for numeral in roman_numerals:
...     print(numeral)
...
I
II
III
IV
V

You might notice that using str.split() is a convenient way to create a list of words.

Occasionally, you might need a running counter instead. In that case, you’d use range():

Python
>>> for i in range(5):
...     print(i)
...
0
1
2
3
4

In this example, i references the next value of the requested range with every iteration. That value is subsequently printed.

In the rare case where you want to iterate over a collection and at the same time want to have a running counter alongside it, you can use enumerate():

Python
>>> for i, numeral in enumerate("I II III IV V".split(), start=1):
...     print(i, numeral)
...
1 I
2 II
3 III
4 IV
5 V

The example above shows the functionality of the two preceding examples combined in one single loop. By default, the accompanying counter starts at zero, but with the optional keyword argument start, you can specify another value.

Python also understands the break and continue statements.

Another control flow construct similar to Java is the if statement:

Python
>>> for n in range(3):
...     if n <= 0:
...         adjective = "not enough"
...     elif n == 1:
...         adjective = "just enough"
...     else:
...         adjective = "more than enough"
...     print(f"You have {adjective} items ({n:d})")
...
You have not enough items (0)
You have just enough items (1)
You have more than enough items (2)

As demonstrated above, the Python if ... else construct also supports an elif keyword, which is helpful because there’s no plain switch ... case statement.

While many coding constructs look similar on the surface, there are still many differences. For example, Python loops, as well as exception catch constructs, support an else: part. Furthermore, Python provides a with statement for context managers.

Java vs Python: What Are the High-Level Native Data Types?

In the following subsections, you’ll find a condensed overview of Python’s standard types. The focus is on where these types or their associated operators differ from Java or how they compare to the corresponding Java collection class.

Numeric Types and Their Operators

Python offers a variety of numeric types to choose from to suit your particular field of application. It has three numeric types built in:

Type Type name Example literal
Integer int 42
Floating-Point float 3.14
Complex complex 1+2j

If you compare both languages, then you’ll find that Python integers can contain arbitrary long values only limited by the amount of (virtual) memory your machine has available for you. You can think of them as an intelligent blend of fixed-precision native integers—or primitive integer types, as Java calls them—and Java’s BigInteger numbers, with the following consequences:

  1. You have all the conveniences of arbitrary-precision integers, and you can use all the well-known symbolic operators on them.
  2. Python applies fast fixed-precision integer arithmetic on the provided values when the values are small enough to allow for that.

By using the prefixes 0x, 0o, and 0b, you can specify the Python integers as hexadecimal, octal, and binary constants, respectively.

Comparing well-known arithmetic operators +, -, *, /, and % in Java vs Python, they have the same meaning in both languages, except for the division operator on integer-like types. The truediv operator (/) applied on int operands yields a float value in Python, which is different from Java. Python has the floordiv operator (//) for division that rounds down to the nearest integer, comparable to the division operator (/) in Java:

Python
>>> 11 / 4          # truediv
2.75
>>> 11.0 // 4       # floordiv, despite float operand(s)
2.0

Furthermore, Python provides the double-asterisk operator (**) for exponentiation as an alternative to the two-argument pow() function. The matmul operator (@) is reserved as an additional operator for types provided by external packages, intended as a convenience notation for matrix multiplication.

Both Python and Java adopted the bitwise operators from the C programming language. This means that the bitwise operators (|, &, ^, and unary ~) have the same meaning in both programming languages.

If you want to use these operators on negative values, then it’s good to know that in Python, integers are represented as two’s complement values in a conceptually infinite large space to hold the bits. This means that negative values conceptually have an infinite amount of leading 1 bits, just like positive numbers conceptually have an infinite amount of leading 0 bits:

Python
>>> bin(~0)
'-0b1'
>>> bin(~0 & 0b1111)       # ~0 is an "infinite" sequence of ones
'0b1111'

The code fragment above indicates that regardless of the value you choose, if you bitwise-AND this value with the constant ~0, then the resulting value is equal to the chosen value. This implies that the constant ~0 conceptually is an infinite sequence of 1 bits.

The bit-shift operators (<< and >>) are also available. There is, however, no equivalent of Java’s bitwise zero-fill right shift operator (>>>), since that makes no sense in a number system with arbitrary long integers. There’s no most significant bit within reach. Another difference between both languages is that Python doesn’t allow shifting bits with a negative shift count.

The Python standard library provides other numerical types as well. There’s decimal.Decimal for decimal fixed-point and floating-point arithmetic, which is comparable to Java’s BigDecimal. There’s a fractions.Fraction class for rational numbers, which is comparable to Apache Commons Math Fractions. Note that these types are not classified as built-in numeric types.

Basic Sequence Types

Sequence types are containers in which you can access their elements using integer indices. Strings and byte sequences are also sequence types. These are presented a few sections later. Python has three basic sequence types built in:

Type Type name Example literal
List list [41, 42, 43]
Tuple tuple ("foo", 42, 3.14)
Range range range(0, 9, 2)

As you can see, the syntactic difference between list and tuple initializers are the square brackets ([]) versus the parentheses (()).

A Python list is similar to Java’s ArrayList, and it’s mutable. You typically use this kind of container for a homogeneous collection, just like in Java. In Python, however, it’s possible to store objects of unrelated types.

A tuple, on the other hand, is more similar to an immutable version of a Pair-like class in Java, except it’s for an arbitrary number of entries instead of two. Empty parentheses (()) denote an empty tuple. A construct like (3,) denotes a tuple containing a single element. In this case, the single element is 3.

A range yields a sequence of numbers that you typically use in loops. You’ve seen an example of this earlier in this tutorial. If you want to learn more about ranges in Python, you can check out this guide to the range() function.

To select an element from a sequence, you can specify the zero-based index between square brackets, as in some_sequence[some_index]. Negative indices count backward from the end, so -1 denotes the last element.

You can also select a slice from a sequence. This is a selection of zero, one, or more elements, yielding an object of the same kind as the original sequence. You can specify a start, stop, and step value, also known as the stride. An example of slicing syntax is some_sequence[<start>:<stop>:<step>].

All these values are optional, and practical defaults are taken when they’re not otherwise specified. Reading about lists and tuples in Python will be helpful if you want to know more about lists, tuples, indices, and slices.

For positive indices, Python syntax is similar to how you select elements in Java arrays.

You can concatenate most sequences using the plus sign operator (+) and repeat them by using the asterisk operator (*):

Python
>>> ["testing"] + ["one", "two"] * 2
['testing', 'one', 'two', 'one', 'two']

You can’t accomplish concatenation or sequence repetition with ranges, but you can slice them. For example, try out range(6, 36, 3)[7:2:-2] and consider what you get as a result.

Dictionaries

A dictionary in Python, dict, is similar to Java’s LinkedHashMap. The syntax of a dict initializer constant is a sequence of comma-separated key: value entries between curly braces ({}). An example of this is {"pi": 3.14, "e": 2.71}.

To select an element from a dict or any other mapping, you can specify the key between square brackets ([]), as in math_symbols["pi"]. Both keys and values can be any object, but keys need to be hashable, which means that they’re usually immutable—or should behave like immutable objects, at least. Keys don’t necessarily need to be all of the same type, although they usually are. The same applies to values.

For additional info, you can read more about dictionaries in Python or check out the Python documentation on mapping types.

Sets

Python also provides sets. You can initialize a set with a syntax like {"pi", "e"} or by using the set() constructor syntax, using an iterable as an argument. To create an empty set, you use the expression set() since the literal {} was already given to dictionaries.

Sets use hashing in the underlying implementation. When you iterate over a set, take into account that the items will appear in apparently random order, just like in Java. Moreover, the order might even change between distinct Python invocations.

Some operators have been overloaded for operations on sets. For details, you can read more about sets in Python.

Strings

Just like in Java, strings in Python are immutable sequences of Unicode elements. String literals are specified between double quotes ("), or you can also specify them between single quotes ('), which is different from Java.

Two examples of strings are "foo" and 'bar'. The different quotation marks don’t necessarily have any different meaning when defining a string. You should note, however, that if you’re using any quotation marks themselves as part of the string, you’ll have to escape them if they also happen to be the delimiters of the string.

Like in Java, the backslash (\) in Python is the character that introduces an escape sequence. The Python interpreter recognizes escape sequences also known in Java, like \b, \n, \t, and a few additional ones from the C programming language.

By default, Python assumes UTF-8 encoding of your Python source files. This means that you can put a Unicode literal directly in a string, like in the case of "é". You can also use the 16- or 32-bit hexadecimal representation of its code point. For "é", you would do this by using the \u00E9 or \U000000E9 escape sequences. Note the difference between the lowercase \u and uppercase \U escape sequences. Finally, it’s also possible to provide its Unicode description, like \N{Latin Small Letter E with acute}.

You can use Unicode characters even in Python identifiers, but then there’s the question of whether or not that’s an advisable thing to do.

In case you’re prefixing the string with r, like in r"raw\text", then the backslash loses its special meaning. This is especially convenient when you want to specify regular expressions.

You can also triple-quote your strings as a convenient way to create multiline strings, like in the following example:

Python
>>> s = """This is a
...        multiline
...        string.
...        """
...
>>> for line in s.splitlines():
...     print(repr(line))
...
'This is a'
'       multiline'
'       string.'
'       '

You can compare this type of string with Java text blocks (JEP 378), although with other syntactic restrictions and with another preservation of whitespace (tabs, spaces, and newlines).

Bytes

Within Java, if you need to store binary data as opposed to text, you’d probably use ByteBuffer, which gives you mutable objects. Within Python, bytearray objects provide similar functionality.

Unlike Java, Python also offers a bytes type to store immutable binary data. Bytes literals look very similar to string literals, except you prefix the literal with a b. Strings contain an .encode() method to convert them to a sequence of bytes, and a bytes object contains a .decode() method to convert it to a string:

Python
>>> bytes(4)                     # Zero-filled with a specified length
b'\x00\x00\x00\x00'
>>> bytes(range(4))              # From an iterable of integers
b'\x00\x01\x02\x03'
>>> b = "Attaché case".encode()  # Many different codecs are available
>>> b
b'Attach\xc3\xa9 case'
>>> b.decode()                   # Decode back into a string again
'Attaché case'

If the codec isn’t specified, the default UTF-8 codec is used for encoding strings and for decoding bytes. When you need to, you can choose from a large list of codecs that provide all sorts of text and bytes conversions.

Python bytes objects also have a .hex() method that produces a string that will list the contents as hexadecimal. For the reverse operation, you can use the .fromhex() class method to construct a bytes object from a hexadecimal string representation.

Booleans

False and True are the two bool instance objects in Python. In a numeric context, True evaluates to 1 and False to 0. This means that True + True evaluates to 2.

The Boolean logical operators in Python are different from Java’s &&, ||, and ! operators. In Python, these are the reserved keywords and, or, and not.

You see this summarized in the table below:

Java Python Description
a && b a and b logical and
a || b a or b logical or
!a not a logical not

Similar to Java, there’s a short-circuiting evaluation behavior of the Boolean operators and and or, where the Python interpreter lazily evaluates the operands left to right until it can determine the truthiness of the whole expression.

Another similarity to Java is that the interpreter yields the last evaluated subexpression as the outcome. Consequently, you should be aware that the outcome of an and or or expression does not necessarily yield a bool instance object.

All Python objects either have a falsy or truthy value. In other words, when you convert Python objects to bool, the outcome is clearly defined:

  • Numerical values that are equal to 0 convert to False, and True otherwise.
  • Empty containers, collections, strings, and bytes objects convert to False, and True otherwise.
  • The None object converts to False as well.
  • All other objects evaluate to True.

If you want to test whether a container or string is non-empty, then you simply provide that object in a Boolean context. This is regarded to be a Pythonic approach.

Check out the following different ways to check for a non-empty string:

Python
>>> s = "some string"
>>> if s != "":                 # Comparing two strings
...     print('s != ""')
...
s != ""

>>> if len(s) != 0:             # Asking for the string length
...     print("len(s) != 0")
...
len(s) != 0

>>> if len(s):                  # Close, but no cigar
...     print("len(s)")
...
len(s)

>>> if s:                       # Pythonic code!
...     print("s")
...
s

In the last example, you just provide the string in a Boolean context. If the string isn’t empty, then it evaluates to true.

You can follow the Write More Pythonic Code learning path if you want to know more about the most typical Python constructs.

In Python, you code the conditional expression, written in Java with the conditional operator (? :), as an expression with the keywords if and else:

Java Python
cond ? a : b a if cond else b

Consider an example of this type of expression in Python:

Python
>>> for n in range(3):
...     word = "item" if n == 1 else "items"
...     print(f"Amount: {n:d} {word}")
...
Amount: 0 items
Amount: 1 item
Amount: 2 items

The REPL outputs "item" only when n equals 1. In all other cases, the REPL outputs "items".

None

In Python, None is a singleton object that you can use to identify null-like values. In Java, you’d use the literal null for similar purposes.

The most frequent use of None within Python is as a default parameter value within function or method definitions. Furthermore, functions or methods that don’t return any value actually return the None object implicitly.

In general, it’s regarded as a code smell when you rely on the implicit conversion of None in a Boolean context because of the risk that you’ll code unintentional behavior for other kinds of objects that happen to return a falsy value.

Consequently, if you want to test whether an object really is the None object, then you should do that explicitly. Because there’s only one None object, you can do that by using the object identity operator is or the opposite operator is not:

Python
>>> some_value = "All" or None

>>> if some_value is None:
...     print(f"is None: {some_value}")

>>> if some_value is not None:
...     print(f"is not None: {some_value}")
...
is not None: All

Keep in mind that the word not here is an inseparable part of the is not operator, and it notably isn’t the same as the logical not operator. In this example, the string "All" has a truthy value in a Boolean context. You may also recollect that the or operator has this short-circuiting behavior and just returns the last expression as soon as the outcome is known, which is "All" in this case.

More Container Data Types

Java offers its standard container types through its collections framework.

Python takes a different approach. It offers the basic container types that you’ve explored earlier in this section as built-in types, and then Python’s standard library provides some more container data types through the collections module. There are many useful examples of container types that you can access through the collections module:

  • namedtuple provides tuples where you can also access the elements through field names.
  • deque provides double-ended queues with fast append and removal at both ends of the collection.
  • ChainMap lets you fold multiple mapping objects into a single view on the mapping.
  • Counter provides a mapping for counting hashable objects.
  • defaultdict provides a mapping that calls a factory function to supply missing values.

These data container types have been implemented just in plain Python.

At this point, you have a good foundation for understanding the similarities and differences between the features, syntax, and data types of Java vs Python. Now it’s time to take a step back and explore the available Python libraries and frameworks and find out how suitable they are for specific use cases.

What Resources Are There for Specific Usages?

You can use Python in many areas of use. Below you’ll find some of these areas, together with their most useful and popular related Python libraries or frameworks:

  • Command-line scripts: argparse provides functionality to create a command-line argument parser.
  • Web frameworks:
    • Django offers a bit more of a shrink-wrapped approach when it comes to developing complete and potentially complex websites. It includes the ability to define models, offers its own ORM solution, and provides a full admin functionality. You can add additional plugins to further extend the admin.
    • Flask advertises itself as a microframework that concentrates on doing one thing well, which is serving web requests. You can combine this core functionality with other already existing components of your own choice, such as ORM and form validation. Many extensions, known as Flask plugins, are available to nicely integrate those components for you.
    • Requests makes sending HTTP requests extremely convenient.
  • Data modeling and analysis: pandas, which is based on NumPy, is a fast, powerful, flexible, and straightforward open source data analysis and manipulation tool. Some people have called pandas a “programmable spreadsheet on steroids.”
  • Machine learning: TensorFlow, Keras, and PyTorch are a few popular frameworks in the area of machine learning.
  • SQL toolkits and object-relational mappers (ORM): SQLAlchemy is a very popular Python SQL toolkit and ORM framework.
  • Workload distribution: Celery is a distributed task queue system.

Python also has some noteworthy tools related to quality assurance:

  • pytest is a great alternative for the standard unittest library.
  • behave is a popular behavior-driven development (BDD) tool. You can combine it with PyHamcrest for more expressive assert checks.
  • Flake8 is a coding style guide checker.
  • Pylint is a tool that checks for errors in Python code and identifies code smells and coding standard deviations.
  • Black is the uncompromising, opinionated, hardly-configurable code reformatter. Although this may sound terrible, in real life, it’s a great tool for any larger-scale software project.
  • mypy is the most widely used static type checker.
  • Bandit finds common security issues.
  • Safety checks your installed dependencies for known security vulnerabilities.
  • tox is a command-line tool that helps in running the automated tests and QA tool checks defined for your project in one single command and for multiple Python versions and dependency configurations.

The lists above are only a small selection of the many packages and frameworks available. You can browse and search the Python Package Index (PyPI) to find just that special package you’re looking for.

When Would Python Be More Useful Than Java, and Why?

Often, you want to choose a programming language for one use case and a different programming language for another use case. When comparing Java vs Python, you should take the following aspects into consideration:

  • Both Java and Python are successfully used in the world’s largest web applications.
  • You can also use Python for writing shell tools.
  • Python’s elegant syntax, code readability, extensive library, and vast collection of external packages allow for rapid development. You’d probably need less than half of the number of lines of code to achieve the same functionality as you would in Java.
  • Because standard Python requires no compile or link steps, you see immediate results when you update the code. This further speeds up development cycle times.
  • In most cases for general applications, standard Java execution speed is higher than Python’s.
  • You can extend Python with C or C++ with relatively little effort. To a certain extent, this mitigates the differences in execution speed.

For certain usages, such as data modeling, analytics, machine learning, and artificial intelligence, execution speed really matters. The popular third-party packages created for this functionality are defined in a programming language that’s compiled to native code. For these areas, Python seems to be the most logical choice.

Conclusion

In this tutorial, you got acquainted with Python and you got a clear picture of the properties of this programming language. You’ve explored the similarities and differences between Java and Python.

You now have some experience for quickly getting started with Python. You also have a good foundation for understanding which situations and for which problem domains it’s useful to apply Python, as well as an overview of what helpful resources you can look to next.

In this tutorial, you learned about:

  • The syntax of the Python programming language
  • Quite a few standard data types in Python
  • How Python is different from Java
  • What aspects are similar between Java and Python
  • Where you can look for Python documentation and topic-specific tutorials
  • How you can get started with Python
  • How you can see immediate results by using the Python REPL
  • Some favorite frameworks and libraries

Maybe you’re sure that you’ll be working more with Python in the future, or maybe you’re still deciding whether to dig deeper into the language. Either way, with the information summarized above, you’re well equipped to explore Python and some of the frameworks introduced in this tutorial.

Additional Resources

When you’re ready to learn more about Python and its packages, there’s a large collection of resources available on the web:

  • You can find written tutorials, video courses, quizzes, and learning paths that cover many topics on Real Python.
  • The external Python utilities, libraries, and frameworks usually provide good documentation.
  • PyVideo.org provides a huge indexed collection of freely available presentations from Python-related conferences all over the world.
  • And last but certainly not least, the official Python documentation maintains a high standard of accurate and complete information for everything about the Python programming language, its standard library, and its ecosystem.

Now that you’ve gotten an idea of what kind of programming language Python actually is, you’re hopefully getting enthusiastic about it and thinking about picking it up for your next project, be it small or large. Happy Pythoning!

🐍 Python Tricks 💌

Get a short & sweet Python Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.

Python Tricks Dictionary Merge

About Jan-Hein Bührman

Jan-Hein Bührman Jan-Hein Bührman

Jan-Hein is a software developer who witnessed Python's first baby steps up very close. While working in different software development roles, he always kept an eye on Python's development. He's now back at the work he loves most: Python programming!

» More about Jan-Hein

Each tutorial at Real Python is created by a team of developers so that it meets our high quality standards. The team members who worked on this tutorial are:

Master Real-World Python Skills With Unlimited Access to Real Python

Locked learning resources

Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:

Level Up Your Python Skills »

Master Real-World Python Skills
With Unlimited Access to Real Python

Locked learning resources

Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:

Level Up Your Python Skills »

What Do You Think?

Rate this article:

What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.

Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students. Get tips for asking good questions and get answers to common questions in our support portal.


Looking for a real-time conversation? Visit the Real Python Community Chat or join the next “Office Hours” Live Q&A Session. Happy Pythoning!

Keep Learning

Related Tutorial Categories: career intermediate