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.
Free Bonus: Click here to get a Python Cheat Sheet and learn the basics of Python 3, like working with data types, dictionaries, lists, and Python functions.
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.
Note: Just for clarity, from a Java perspective, Python functions are like static methods, and you don’t necessarily need to define them within a class. Later on, you’ll see an example of a Python function definition.
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):
>>> 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.
Note: The Python read–eval–print loop is explained later on in this tutorial.
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.
Note: Make sure you’ve installed a recent version of Python. At the time of writing this tutorial, the most recent version is the latest patch version of the 3.10.x series. The code fragments shown in this tutorial should all work with this version of Python.
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:
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
defstatement starts the definition of a new function namedparity(), which accepts an argument callednumber. Note that if thedefstatement 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 theresultvariable. - Line 3: Here you see the start of an
ifstatement. - Line 4: The extra indent starts a new block. This block is executed when the conditional expression of the
ifstatement,number % 2 == 0, evaluates to true. In the example, it only consists of a single line where you assign"even"to theresultvariable. - Line 5: The dedent that precedes the
returnstatement marks the end of theifstatement and its associated block. - Line 7: Likewise, you see the dedent that precedes the beginning of the
forloop. Consequently, theforloop 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
forloop. The firstprint()function call is part of theforloop block. - Line 9: This second dedented
print()function call isn’t part of theforloop 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:
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.
Note: The style guide is an example of a Python Enhancement Proposal, or PEP for short. PEPs don’t only contain the proposals, but they also reflect specifications for implementation, so you can sort of compare PEPs to the union of Java’s JEPs and JSRs. PEP 0 lists the index of PEPs.
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.
Note: You can compare the Python REPL with Java’s JShell (JEP 222), which has been available since JDK 9.
The following fragment shows how Python’s REPL works:
>>> 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.
Note: Python 3.8 introduced an assignment expression operator (:=), which is also known as the walrus operator. It assigns values to variables, but unlike a regular assignment, it evaluates them as if in an expression. That’s similar to the assignment operator in Java. Note, however, that it’s not completely interchangeable with the regular assignment statement. Its scope is actually quite limited.
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:
>>> 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:
>>> 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.
Note: As stated above, the Python runtime makes type annotations available for introspection by the code. Some libraries make use of this information, such as FastAPI.
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:
- 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
javaccompiles a.javafile into a.classfile. - Execution: The CPython bytecode interpreter—in other words, CPython’s virtual machine (VM)—subsequently executes the bytecode from the first step.
Note: Unlike in Java, you can’t assume that the same Python bytecode will work with other Python implementations or even between different versions of the same Python implementation. It helps, however, in reducing the time needed to load a module.
The compiled modules are, if possible, stored in a cache directory.
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.
Note: In this context, you can consider eligible functions and operators to be those that allow you to overload their behavior.
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:
- Numeric values
- Documentation strings
- Functions and methods
- Modules
- Stack tracebacks
- Byte-compiled code objects
- Classes themselves
Because they’re objects, you can store all of these in variables, pass them around, and introspect them at runtime.
Note: As you read above, classes are objects. Since objects are instances of classes by definition, classes must be instances of something as well.
Indeed, these are instances of a metaclass. The standard metaclass is type, but you can create alternative metaclasses, usually by deriving from type, to alter the way classes are created.
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.
Note: You’ll see more on tuples and dictionaries later on in this tutorial.
The following session shows some examples:
>>> "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: