Python is a strongly typed language with dynamic semantics. It's usually executed via an interpreter but it can be JIT compiled. Python works, more or less, equally well on the major desktop and server environments: Linux, Windows, and OS X. Python is a powerful, scalable, and expressive language. Some notable companies that use Python include DropBox (client and server), YouTube, Reddit, Digg, Instagram, Rdio, Pintrest, Google, and Microsoft.

Although we in the .NET community tend to stay focused on the Windows platform and Visual Studio space, it's worth noting how popular and successful Python is becoming in the broader tech industry.

Heidar Bernhardsson analyzed the Hack News announcements for startups during the second half of 2013 and graphed the main language or platform that the announced startup was built on. You can find his full article at http://www.iseld.org/blog/2013/12/13/what-programming-languages-are-technology-startups-using/. (Editor's note: This site URL is no longer working.) See the graph in Figure 1 to see just that Python consistently ranks among the top three and, in December, it was the most popular language used.

Figure 1: Job postings, by technology, for startups on HackerNews in December 2013
Figure 1: Job postings, by technology, for startups on HackerNews in December 2013

Another metric you might choose to evaluate the popularity and vibrancy of a tech ecosystem is the number and size of their user group community. Thanks to www.meetup.com, this is easy to do. Figure 2 shows the relative popularity of .NET and Python in seven metro locations in the US.

Figure 2: The size of .NET and Python user groups by location
Figure 2: The size of .NET and Python user groups by location

There are definitely locations where .NET is more popular than Python. LA's user groups have 1,292 .NET developers versus 918 Python developers. Chicago's user groups have 588 .NET developers versus 266 Python developers. But the general trend is Python significantly outpacing .NET. San Francisco has 3,820 Python developers versus 1,010 .NET developers and New York has a whopping 4,503 Python developers versus 1,116 .NET developers! Finally, it probably won't surprise you that Python is more popular in Silicon Valley. But it's kind of shocking to see that it's 28 times more popular.

It's shocking to see that Python is 28 times more popular than .NET in Silicon Valley.

For all the success and growth that Python has experienced since its creation by Guido Van Rossum (https://en.wikipedia.org/wiki/Guido_van_Rossum) in 1989, it hasn't been widely adopted by the .NET community. I believe this is a significant mistake being made by our slice (specifically, the Microsoft-developer slice) of the industry. That is a generalization of course, but I believe it is basically accurate.

So that naturally leads to the question: Why is Python adoption relatively low among .NET developers? I have some ideas on why this is the case. Before I get started on the tour, let's see if I can dispel some myths. Could it be that:

  • .NET and C# are simply superior environments and there is no need to look outside the Visual Studio box.
  • Python uses whitespace and indentation (rather than curly braces) to arrange code and that's just got to be tedious.
  • Python apps are often distributed as a loose set of text files (rather than compile EXEs and DLLs). That can't be safe.
  • Python code is interpreted (not JIT compiled or natively compiled) and so Python must be slow and error-prone.
  • The Python community is heavily biased toward Linux and thus little attention has been given to Python on Windows.
  • Python developers don't really use IDEs and giving up a tool like Visual Studio is simply something .NET developers are unwilling to do.

The above list highlights some of the perceptions of Python from .NET developers. But do they match reality? Here are the answers: No, No, No, No, Somewhat, No.

Allow me to explain.

.NET is just superior: No. You will see throughout this article that many of the features and capabilities that you value as .NET developers also exist in Python, and many times, in a clearly superior form. However, let's put aside the direct comparisons of the languages for a moment. The ability to write truly cross-platform Python code is a huge advantage over .NET. With the diversity of devices, operating systems, and cloud providers, cross-platform capabilities are only becoming more important, not less important. Without discounting the great work the Xamarin guys have done allowing C# code on other devices (http://www.xamarin.com), choosing Python for cross-platform capabilities over .NET is obvious.

Python's use of significant whitespac is painful and tedious. No. This one surprised me when I was learning Python. You'll see that quality Python editors and IDEs make defining code blocks via whitespace very simple. So, no, using whitespace for code blocks isn't tedious. What will surprise you is, in fact, the reverse perspective. After spending some time writing Python and not worrying about parentheses, curly braces, semicolons, and other syntactical noise, returning to C# is outright dreary.

Python apps are often distributed as a loose set of text files (rather than compile EXEs and DLLs). No. You may encounter the stray *.py file standing in for a proper application in Python, but this is not the only option. For distributing reusable libraries, it's not even the recommended option. Python allows you to build packages that you can think of more or less like .NET DLLs (no, they are not technically compiled, but they are bundled and versioned). For applications, you can go even further. Utilities like cx_Freeze allow you to create full stand-alone, dependency-free EXEs from a set of Python files. These EXEs contain the Python runtime and all Python libraries you have used in your application.

That is pretty amazing. Imagine how much more successful .NET on the client would have been if you could have done this with IL (intermediate language). Of course, you can't because .NET apps require the correct version of the CLR to be preinstalled on the client.

Python code is interpreted (not compiled) making Python slow. No. The idea of how Python code executes (and manages memory, accesses external code, etc.) is very interesting. The default implementation (CPython, see http://python.org/downloads/ ) is interpreted and, nonetheless, very high-end systems have been built upon it (such as Dropbox, YouTube, Pintrest, etc.).

After spending some time writing Python and not worrying about parentheses, curly braces, semicolons, and other syntactical noise, returning to C# is outright dreary.

Moreover, beyond CPython, there's a whole world of variations. There's IronPython, which runs Python code on the .NET runtime. There's Jython, which does similar things on top of Java. You have PyPy (www.pypy.org), which JIT compiles Python and executes it natively. Finally, there is Stackless Python (www.stackless.com), which is an implementation specifically focused on concurrency. There are many more for you to explore discussed on the Python wiki (https://wiki.python.org/moin/PythonImplementations).

Little attention has been given to Python on Windows. Maybe. There is a grain of truth to this myth. The Python community has been traditionally focused on Linux (and to some degree OS X given the shared OS foundation). There is a very interesting presentation by Jessica McKellar entitled “The Future of Python: Choose Your Own Adventure” (https://www.youtube.com/watch?v=d1a4Jbjc-vU). I encourage you to watch the video (it's only 30 minutes, and the Windows part starts at minute 5). The premise of her keynote speech is that there are decision points that the Python community faces that will ultimately decide how successful Python will be in the coming years. One of these points is to make working with Python on Windows better, even delightful.

Python developers don't really use IDEs. No. There are many solid IDEs available for Python on all OSs. The current front-runner is PyCharm, from JetBrains, available at http://www.jetbrains.com/pycharm/ . PyCharm is not only the best IDE for Python, It's also the best IDE for Python on Windows.

More than once, I've wondered how awesome an IDE I'd have if the guys who make Resharper for Visual Studio were to reset the stage and build an IDE from the ground up for .NET without all the backward compatibility cruft in Visual Studio. Well, they did that for Python and it's called PyCharm!

There are also other great IDE options beyond PyCharm. Python Tools for Visual Studio is also free and quite excellent. Download PTVS at https://microsoft.github.io/PTVS/. Others choose PyDev, which is an Eclipse plug-in.

A Lightning Introduction to the Python Language

Let's start with variables and comments. Python objects are strongly-typed but the variables pointing at them are not. To declare and assign a variable, you simply state the name and assign it.

# declare and assign a user variable
active_user = db.get_active_user()

# access and store a property of the user object
first_name = active_user.first_name

Next up: code blocks (sometimes called code suites). Python uses colons and white space rather than curly braces to define code blocks. The following snippet is an if statement. Notice how the first two print statements are part of the if branch.

# get the age from the current user
age_input = input('Please enter your age: ')
age = int(age_input)

# decide if they are eligible for the after party
if age >= 21:
    print("Hey, we're having an after party.")
    print('Drop by 123 Vine St at 8pm')
else:
    print('Nice to meet you')

Methods are straightforward and use the same technique to define them as other code blocks. All methods have untyped return values, so there's no reason to declare the return type explicitly. This leads to code such as the snippet below that defines two methods: main and verify_reg_status:

def main():
    print("app starting up...")
    is_registered = verify_reg_status(True)

    if not is_registered:
        print('app not registered')
        return

    print('Running as registered...')

def verify_reg_status(required):
    # check status ...
    return True

Finally, let's see about classes. In the code snippet below, you'll see how to define classes, inheritance, member methods, and member variables (sometimes referred to as attributes).

class Cat(Animal):
    def __init__(self, name, friskiness=50):
        super().__init__()
        self.name = name
        self.friskiness = friskiness

    def wake_up(self):
        print(self.name + " says 'meow...'")

Notice that you have a class called Cat that derives from Animal (not listed). You define a constructor using the __init__ magic method. All methods are defined the same way as stand-alone methods, but they take a self parameter as the first argument. The self parameter is like the this pointer in C# and C++ but it's explicitly defined as an argument in Python. Finally, you define member variables by dynamically adding them to the instance via the self argument (such as self.friskiness).

Just like that, you now know the basics of the Python language. Of course, there's much more to learn, and I'll dig into the details throughout this article. Using this simple foundation above, you're ready to start exploring the finer points of Python.

What Makes .NET Special and Can Python Compete?

Let's talk about .NET and C# for a moment. When C# came onto the scene in 2001, it was a great leap forward for statically typed languages. Since its introduction, C# has consistently added amazing new language features, such as LINQ and lambda expressions. The .NET ecosystem has evolved to generally embrace open-source as a culture and, more specifically, through the wide-spread adoption of NuGet. When people stop me on the street and ask, “Michael, what makes .NET and C# so awesome? Why do you prefer it over some other languages like Java?” I list off great features like the ones included in Table 1. These include the features that I think make C# and .NET truly shine.

You may be surprised to learn that Python (Python 3 in particular) has every single one of these features in one form or another. In the following sections, I'll explore them by comparing a .NET feature to Python's version of that same feature.

All Objects Share a Common Base Class

One of the first things you learn about .NET is that it's a very object-oriented system. Perhaps the key indicator is that everything derives from System.Object. A typical class could be defined as:

// C#
public class Animal : System.Object
{
    // details...
}

Here, there is an Animal class that derives from System.Object. You can even omit any base class and C# still makes the Animal derive from System.Object. The benefits here are significant. You can always leverage a common set of operations (such as ToString()). You can always dig into the type via reflection starting with GetType(). Finally, prior to Generics in C# 2, the entire collection system in .NET leveraged this fact.

In Python, there's an almost identical situation:

# Python 3
class Animial( object ):
    # details ...

Again, you can omit the base class and it's still an object.

IEnumerable and Foreach Loops

Foreach loops have saved C# developers countless hours of dreaded off-by-one errors, invalid cast exceptions, and degraded code readability. In the next code snippet, there's a list of numbers that you can iterate through in the cleanest possible way by using foreach:

// C#
int[] nums = { 2, 3, 5, 7 };
foreach ( int n in nums )
{
    Console.WriteLine("{0}^2 is {1}.", n, n*n);
}

Python also has a clean foreach-style loop. In fact, Python has no index-based looping structure equivalent to C#'s for loop whatsoever. Python's iteration-style loop should be very comfortable for you.

# Python 3
nums = [2, 3, 5, 7]
for n in nums:
    print("{0}^2 is {1}.".format(n, n*n))

In both languages, the output is identical:

2^2 is 4.
3^2 is 9.
5^2 is 25.
7^2 is 49.

Of course, C# has a ton of flexibility with foreach loops beyond basic collections. Any type that implements IEnumerable<T> can be efficiently used in foreach. Let's do that with a hypothetical ShoppingCart class that contains CartItems (not shown for brevity).

// C#
class ShoppingCart : IEnumerable<CartItem> {
    List<CartItem> items = new List<CartItem>();

    public void Add(CartItem item) {
        this.items.Add( item );
    }

    public IEnumerator<CartItem> GetEnumerator(){
        return items.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator() {
        return this.GetEnumerator();
    }
}

With this ShoppingCart defined, you can now loop across its items just as if it were a list. Implementing IEnumerable<CartItem> is kind of painful. But it can be worthwhile when you want to provide a simple mechanism for consumers of your class to process a set of elements linearly.

Can Python do something like this? The answer is yes. In fact, Python's version is cleaner and easier to implement (which means fewer bugs).

# Python 3
class ShoppingCart:
    items = []

    def __iter__(self):
        return self.items.__iter__()

Which language would you rather use to implement custom iterable objects? In Python, you simply define an __iter__ magic method that returns something iterable (or a generator, as you will see later). Note: You would likely define the items member variable in the constructor (init method), but for parity with C#'s version, I chose the syntax above, which is also valid.

Properties

C#'s use of properties is pure genius. Consumers of classes want to work with data, not methods that allow you access to data. Code that uses getters and setters (such as user.GetFirstName() or user.SetFirstName("Michael")) is unnatural. One becomes numb to it after years of programming, but that's no excuse. In some languages, such as C++, these getters and setters are necessary evils. Luckily, C# and Python are not among those languages.

Here is a simple computed property and a typical use-case in C#:

public class Person
{
    // details elided

    public string FullName {
        get
        {
            return this.FirstName + " " + this.LastName;
        }
    }
}

// usage
Person person = new Person("Michael", "Kennedy");
string name = person.FullName;

Here's the same scenario in Python.

# Python 3
class Person:
    # details elided

    @property
    def full_name(self):
        return self.first_name + " " + \
               self.last_name

# usage
person = Person('Michael', 'Kennedy')
name = person.full_name

You can also define read-only properties as well as read/write properties. In both languages, having protected or computed data that is as straightforward to consume as basic fields is a huge boost to users consuming the classes available to them.

In some languages, such as C++, these getters and setters are necessary evils. Luckily C# and Python are not among those languages.

Anonymous Types

Anonymous types were introduced to C# in version 3.0, which may well be the most important release of C# to date beyond version 1.0. This release included LINQ, anonymous types, lambda expressions, and extension methods.

Anonymous types are best understood in the context of LINQ. They allow you to do object-oriented, strongly-typed projections in ORMs and LINQ without the need to create a new class for each set of columns you're projecting.

That said, let's look at anonymous types by themselves for this comparison. Python's equivalent is also used frequently around ORMs as well.

The following code creates a class with an integer Age property and a string Name property.

// C#
var dog = new
{
    Age = 7,
    Name = "Rover"
};

if (dog.Age > 5) {
    // treat dog as older
}

Console.WriteLine(dog);
// Outputs: { Age = 7, Name = Rover }

To use Anonymous types in Python, you need to define a new type to gain full parity with C#. Python's Dictionary type is very flexible and almost fills this role, except the named usage in the if statement (in this example, dog.Age) won't work. So first, let me define a class named AnonType that shows the crazy flexibility Python has:

# Python 3
class AnonType(dict):
    __getattr__ = dict.get
    __setattr__ = dict.__setitem__

With AnonType in place, here is the corresponding code for creating an anonymous dog as above (ironically, this anonymous dog has a name).

# Python 3
dog = AnonType(
    age=7,
    name="Rover"
)

if dog.age > 5:
    # treat dog as older

print(dog);
# Outputs: {'name': 'Rover', 'age': 7}

Although there isn't 100% parity between the two implementations, they are essentially the same. You can also get a glimpse of what's possible with Python if you deconstruct how I implemented Anonymous types in the AnonType class above.

Namespaces and Using Statements

Platforms like .NET have huge base class libraries. According to one measure [http://blogs.msdn.com/b/brada/archive/2008/03/17/number-of-types-in-the-net-framework.aspx], .NET 3.5 has 11,417 types! Even so, .NET is not nearly as overwhelming as it could be. This is because they cleverly leverage namespaces and assemblies to group types by functionality. .NET only exposes the functionality you opt into via Using statements and references.

The following C# code snippet pulls in just what you need. You can even redefine a name of a type to suit your situation.

// C#
using System;
using System.Collections.Concurrent;
using System.IO;
using MutableString = System.Text.StringBuilder;

The Python community also has a large base class library (known as the standard library) (https://docs.python.org/3.3/library/). The Python community even has a great phrase to describe this. They say Python comes with batteries included, by which they mean you already have most of the classes you need to accomplish a task. There is also the same sense of consuming a set of group types with packages (Python's assemblies).

The Python code snippet below brings types from two packages (io and sys). The import statement can be thought of as a Using statement combined with an add reference operation. You can see many similarities to C#'s Using statement (importing the library sys, redefining the BufferedReader as buffer, and so on).

# Python 3
import sys
from io import StringIO
from io import BufferedReader as buffer

Lambda Expressions and Delegates

As I stated above, I believe C# 3.0 was the golden release for C#. Lambda expressions are definitely a key reason. Lambda expressions allow you to define very concise blocks of code which can be passed around as parameters. They play a key role in threading and LINQ, just to name a few uses.

I believe C# 3.0 was the golden release for C#. and lambda expressions are definitely a key reason.

Here's an example of how you can use lambdas to add custom sorting to a list:

// C#
var people = new List<Person>() {
    new Person("jeff", 40),
    new Person("zoe", 27),
    new Person("tod", 19),
    new Person("bill", 50),
    new Person("ted", 44),
};

people.Sort((p1, p2) => p1.Age.CompareTo(p2.Age));

Does Python have a feature as clean and useful as lambdas in C#? You bet, and they're also called lambdas. Here's the same code in Python (note that the way sorting is done varies slightly from C#):

# Python 3
people = [
    Person('jeff', 40),
    Person('zoe', 27),
    Person('tod', 19),
    Person('bill', 50),
    Person('ted', 44),
]

people.sort(key=lambda p: p.age)

Observe the similarities: You specify the arguments and use a goes to symbol ( => in C# and : in Python) to separate the expression from the inputs. Python uses a lambda keyword at the beginning, which C# doesn't need due to the type inference and the static typing.

LINQ

LINQ might be the single most significant idea introduced by C#. Not only does it allow developers to treat in-memory data as if it were a database, it unifies virtually all data sources that choose to integrate with it.

A query against a List<Book>, a SQL database with a book table, and a MongoDB collection of books may be indistinguishable by only reading the LINQ query. Once you learn how to access one system, you can access most of them via LINQ.

Here's a C# example of finding all people who match some criteria. Consider the set of people from the previous example. If you wanted to find all the people 21 or older, you could write this code.

// C#
var partiers =
    from p in people            // iteration
    where p.Age >= 21           // filtering
    orderby p.Age               // ordering
    select new {p.Name, p.Age}; // projection

It turns out that Python has a remarkably similar syntax. However, its capabilities are spread across multiple features, so working with databases requires a different API (e.g., SQLAlchemy) than working with in-memory objects.

Here's what's called a list comprehension that performs the same query (note that the sort cannot be as easily combined). It includes a declarative iteration, filtering, and a projection.

# Python 3
partiers = [
    AnonType(name=p.name, age=p.age) # projection
    for p in people                  # iteration
    if p.age >= 21                   # filtering
]
partiers.sort(key=lambda p: p.age)   # ordering

If you want to run the same basic query against a database of people in Python, you need to use SQLAlchemy. You'll see that style later during the discussion of Entity Framework and ORMs.

Iterator Methods

Iterator methods may be the least well-known killer feature of C#. Introduced in C# 2.0, iterator methods allow you to define significantly simpler and higher-performance custom iteration sources.

For example, here's the C# code to implement the Fibonacci series efficiently. Note that the returned set is infinite, so the consuming foreach loops are meant to break out at some point.

// C#
public static IEnumerable<int> Fibonacci()
{
    int current = 0;
    int next = 1;
    while (true)
    {
        yield return next;
        int temp = current;
        current = next;
        next = temp + current;
    }
}

If you thought that was impressive, check out the Python version.

# Python 3
def fibonacci():
    current, nxt = 0, 1
    while True:
        current, nxt = nxt, nxt+current
        yield current

In almost every way, this Python code is identical to the C# above. In fact, I would argue that this is cleaner and easier to read. That's not surprising, as Python was designed for readability. Note that next is a Python built-in method so, to avoid confusion (and overriding it), I chose nxt for the variable name.

Attributes and Declarative Programming

Attributes are another thing that C# nailed out of the gate (in version 1.0). The ability to declaratively modify code is very powerful.

Here's an example of converting a regular interface into a WCF service contract using the ServiceContract and OperationContract attributes.

// C#
[ServiceContract]
public interface ICalculator
{
    [OperationContract]
    double Add(double n1, double n2);

    [OperationContract]
    double Subtract(double n1, double n2);
}

Python has functionality very similar to .NET attributes that's used for declarative programming, called decorators. Your intuition to map them to attributes will generally serve you well even though they are implemented totally differently.

Python has functionality very similar to .NET attributes that's used for declarative programming, called decorators.

The show method below is a view handler (think action method from MVC) in a Pyramid controller (one of Python's Web frameworks). The decorator is the part before the method definition that starts with @.

# Python 3
@pyramid_handlers.action(
    renderer='mywebapp:templates/books/show.pt')
def show(self):
    bookId = self.request.matchdict['id']
    repo = Repository()
    book = repo.books_by_id(bson.ObjectId(bookId))
    return book.to_dict()

By using the action decorator, you control the view template rendered when the method is run as well as the route that (implicitly) maps the /controller/show.

Dynamic Keyword

C# 4.0 was all about dynamic programming. That version introduced the dynamic keyword to the language. A major impetus of this was to enable C# (a static language) to be friendlier to dynamic language interop (via the DLR), which was being added to .NET around that time - including Python, via IronPython, coincidentally. Learn more about the DLR at https://en.wikipedia.org/wiki/Dynamic_Language_Runtime.

Types in languages such as Python, Ruby, and JavaScript are built more than they are defined by their code. Thus, any form of static typing is not available for interop between C# and those languages.

Here are a few examples of dynamic access in C#:

// C#
// Can access ISBN property of ANY return type:
dynamic data = GetDataFromService();
string isbn = data.ISBN;

// Add arbitrary fields to an object:
dynamic expando = new ExpandoObject();
expando.Name = "Michael";
expando.Age = 40;

As you might expect, Python's dynamic semantics can parallel these features and many more. Here's what this might look like in Python:

# Python 3
data = get_data_from_service()
isbn = data.ISBN

There is nothing special to indicate dynamic access because that is how Python always works. And to dynamically append data to any type (as long as it's a custom class), you just set the properties.

# Python 3
class AnyCustomType:
    pass

any_type = AnyCustomType()
any_type.name = "Michael"
any_type.age = 40

Notice that this ability to dynamically declare fields (known as attributes in Python) from outside the class is analogous to how classes designate their member variables from their constructors (i.e., the __init__ magic method):

# Python 3
class Car:
    def __init__(self, year, top_speed):
        self.year = year
        self.top_speed = top_speed

NuGet

NuGet has revolutionized how .NET developers share and consume code, especially in the open-source space. Prior to NuGet, you might find an occasional project using log4net or NUnit or some other open-source library. Now, open-source and .NET are inseparable. The new ASP.NET MVC projects ship with many open-source libraries including JSON.NET, jQuery, Knockout, and more. They're kept up-to-date with NuGet with a single command. A quick visit over to https://www.nuget.org/ shows there are currently 22,749 libraries, and this number grows every day. It's indeed a golden age.

NuGet is awesome indeed. But it didn't come into existence in a vacuum. In fact, it was inspired by other ecosystems that had amazing package management tools such as Ruby (with Ruby Gems) and Python (with PyPI).

Everything you love about .NET and NuGet can be found in Python with the Python Package Index.

Everything you love about .NET and NuGet can be found in Python with the Python Package Index (also known as PyPI or even sometimes as “the cheese shop”). Today, PyPI has 43,573 packages! Just like with NuGet, packages track and manage their dependencies. They can be installed via command-line commands or via GUIs within IDEs such as PyCharm. Figure 3 shows package management within the PyCharm IDE on OS X.

Figure 3: Package management via PyCharm's GUI
Figure 3: Package management via PyCharm's GUI

If you're working in Python and need some piece of functionality that isn't built-in, PyPI should be your first stop! You can browse the package index online at https://pypi.python.org/pypi.

You do need to exercise a bit of care when working with either NuGet or PyPI. Packages are developed by third-party developers (welcome to the open source world!) and they come with a variety of OSS licenses. This can include GPL, which may make your project GPL as well. If you don't want this, just be aware of the licenses for the projects you're consuming.

Side-by-Side Execution

Think back to the year 1998. On the Microsoft developer scene, COM was king. Although there were many benefits from the binary compatibility that COM brought to the platform, one very painful aspect was versioning. The dark side of COM's code reusability even got a scary name: DLL hell!

The very abridged story of the problem goes like this: App 2 is installed and requires v2 of COM component A and so installs v2 of A.dll. Next, App 1 is built on v1 of COM component A and when installed, installs v1 of A.dll. It turns out that v1 and v2 of A.dll are not binarily compatible and thus App 2 no longer runs. It crashes with a mysterious page fault! Of course, the developer cannot reproduce the error in support. There is very little App 2 can do to protect itself. It has entered DLL hell.

With this very real challenge plaguing many COM applications, .NET was built to avoid DLL hell altogether. Multiple versions of the .NET Framework can be installed side-by-side on the same computer without (much) interference. Moreover, multiple versions of .NET DLLs can be installed on the same computer using the global assembly cache (AKA the GAC). While not perfect, this has solved most of the DLL hell issues.

With Python, they've also considered their own versioning issues and there are several clever solutions. Python has chosen to solve the problem in a different way. With .NET, you have one global registry per framework version. For example, there is one .NET 4.5 on your system.

In Python, there are two solutions. First of all, you can install Python multiple times into different locations. You can also install multiple versions side-by-side (e.g., Python 3 32-bit, Python 3 64-bit, and Python 2 32-bit). Building on that, Python has virtual environments. With virtual environments, you can clone any Python version into a local working copy and use that copy as your runtime. Into this virtual environment, you can install all of the dependencies needed to run your app. For example, if you are writing a Web app with Pyramid, which uses MongoDB, you can you can use PyPI and PIP to install pymongo for MongoDB support and Pyramid and its dependencies for the MVC Web framework (specifying the version as necessary).

An added benefit of these virtual environments is that they provide a list of dependencies for deployment. What does your server need to run this app? Look in the virtual environment and see what's installed. That's it. With .NET, you may say that the packages folder from NuGet serves the same purpose, but it's not quite equivalent. With .NET, you always have some items coming from the GAC (e.g., System.Web.MVC in early versions of MVC), thus knowing the dependencies is still tricky.

Entity Framework and Relational ORMs

Long gone are the days of writing inline SQL for the majority of .NET applications. Almost all developers use Entity Framework (EF) to access relational databases in .NET. In EF, you create classes that model the data and then express queries using those classes.

The days of writing inline SQL for the majority of applications are long gone.

Let's take an example of a book shop implemented in EF. You might find code like this that finds books in a given category that are in stock, and sorts them by title.

// C#
string category = "Programming";

var books = db.Books
              .Where(
                  b => b.CopiesInStock > 0 &&
                  b.Category == category)
              .OrderBy(b => b.Title);

The thought of returning to writing raw SQL probably makes you want to curl up in a ball and hide. So if you are going to write data-intensive applications in Python, it had better have something comparable. It does!

The Python equivalent of EF is a clever and mature library called SQLAlchemy. With SQLAlchemy, you will find code that is very similar to EF code. You define classes and use them to model the data and you use them as the basis for queries. You can find SQLAlchemy at https://www.sqlalchemy.org/.

Here is that same example from above in Python.

# Python 3
category = "Programming"

books = session.query(Book) \
        .filter(Book.category == category)\
        .order_by(Book.title.desc())

That is pretty clean RDBMS code in any language. Anyone comfortable with EF and (the fluent version of) LINQ should be right at home in SQLAlchemy.

People often wonder which databases are supported by SQLAlchemy. It supports most of them including: PostgreSQL, MySQL, Oracle, Microsoft SQL Server, and SQLite.

ASP.NET MVC

In the .NET world, there is a very solid Web framework with ASP.NET MVC. You can write clean code, separate views and logic, and consume data using ORMs such as Entity Framework.

You may be wondering what the equivalent of ASP.NET MVC is in the Python world. Python has a whole set of Web frameworks from which to choose. The top three are Pyramid, Django, and Flask. Each one of these has their own flavor of MVC-style separation of concerns.

You will find them at http://www.pylonsproject.org/, https://www.djangoproject.com/, http://flask.pocoo.org/ respectively.

Django is full-featured framework. It comes with its own ORM (active-record style, similar to Ruby on Rails). It has a built-in CRUD admin back-end for managing your data. It features a massive set of packaged apps that you can plug into your website. Visit Django Packages [https://djangopackages.org/] and you'll find over 2,000 reusable building blocks (although sadly most are not Python 3 compatible).

Notable sites built with Django include:

  • Discus
  • Instagram
  • Pintrest
  • Rdio

Pyramid and Flask have a different approach than Django. These are what are called Web micro frameworks. You only bring in the functionality as needed and you have greater flexibility in choosing that functionality. They don't prescribe a preferred set of subsystems. Consider data access: they don't come with a built-in ORM or data management admin section. If you need data access, you can choose SQLAlchemy for as a relational ORM, or you can choose PyMongo for a NoSQL/MongoDB back-end. If you need a data admin section, you write it yourself. You have the freedom and responsibility to put the building blocks together.

It's worth mentioning that Pyramid has much better support for Python 3 than does Flask.

Notable sites built with Pyramid include:

  • Dropbox
  • Reddit
  • Digg

Rather than try to take these Web frameworks apart and compare them to ASP.NET, I'll just encourage you to visit their websites. They have tutorials and good documentation. You'll find most of what you love about ASP.NET MVC in these Web frameworks!

JIT Compilation

At first, you might distinguish Python and .NET by saying that Python is interpreted and .NET is JIT compiled (with the typical performance benefits you get with JIT-compiled execution). However, the truth is much more interesting and nuanced than this and it's important to know your options which choosing a Python implementation (runtime) for your project.

You might distinguish Python and .NET by saying that Python is interpreted and .NET is JIT. However the truth is much more interesting and nuanced.

The default implementation for Python is CPython. This is the interpreted version of Python (the official implementation found at https://www.python.org/ ). In this version, most Python code is interpreted. However, performance-critical sections of external packages and built-in types are implemented and executed in C via C-extensions. A good example is PyMongo (the official MongoDB access library for Python), which has optional C speed-ups that may be installed as part of the PyMongo library. That means the performance critical part of database access for MongoDB is executed in fully complied C, not interpreted Python. All of a sudden, this interpreted versus JIT-compiled comparison starts to blur.

Looking beyond standard Python (CPython), there's a whole array of alternate implementations. There's PyPy, which is a JIT-based Python runtime that happens to also be implemented in Python (hence the name). There's IronPython from Microsoft, which runs Python code on the CLR. With IronPython, you can expose your Python code to .NET/C# code and you can consume .NET libraries in your Python code. Closely related to IronPython, there's Jython (the Java equivalent of IronPython). Finally, there's Stackless Python, which allows programmers to reap the benefits of thread-based programming without the performance and complexity problems associated with conventional threads.

Native Apps, GUI Apps, and Visual Designers

You've seen that Python is a pretty amazing language. You may even want to try it for your next project. However, if that project is a client-side application, especially if it's a GUI, using Python can seem impractical. The idea of taking a set of Python scripts, handing them to your users, and requiring them to ensure that the right version of Python is installed, that Python is in the path, and that it has the supporting packages installed, is pretty much a non-starter. End users need a native app.

Python has you covered here as too! With libraries like cx_Freeze for dependency-free Windows EXEs and py2app for native OS X apps, you can build truly redistributable applications. Find cx_Freeze at https://cx-freeze.readthedocs.io/en/latest/ and py2app at https://py2app.readthedocs.io/en/latest/.

Moreover, with libraries like PyQt/PySide (available at https://pypi.python.org/pypi/PySide) and wxPython, you can build GUI-based applications. There is even a visual designer for the Qt framework that can be used with PyQt and PySide. See Figure 4 for a sense of what the QT Designer looks like.

Figure 4      : The Qt Designer, a visual designer for UIs
Figure 4 : The Qt Designer, a visual designer for UIs

In addition to the Qt cross-platform and wxPython cross-platform options, you can also write natively for the OS while sharing the custom logic across platforms.

These libraries enable you to keep your app logic in a single Python package, which can be consumed by your OS X and Windows UI applications.

PyObjC is a native wrapper for the Cocoa Objective-C APIs in OS X (similar to what Xamarin is doing for iOS/C#). IronPython supports WPF and Windows Forms apps written in Python and running on .NET. You can use it to build native Windows UIs. Taken together, these libraries enable you to keep your app logic in a single Python package that can be consumed by both your PyObjC and IronPython UI applications, giving you the best of both worlds: cross-platform code reuse and fully native UI applications.

Summary

You've taken a tour of almost every major feature of .NET framework and the C# language. You have compared those features to their closest equivalent in the Python language and found amazing parity between the two ecosystems and languages.

I hope this tour has inspired you to learn more about Python. It's a very clean and expressive language that should be quite comfortable for .NET developers.

Now the question is: What are you going to build in Python? With Pyramid, you can build amazing Web apps. With a combination of PyObjC, IronPython, and some shared core modules, you can build native GUI applications on OS X and Windows. You can even put a bow around those UI apps with py2app and cx_Freeze that can turn both into native redistributables (app bundles and EXEs). Finally, with the rich data access capabilities of SQLAlchemy for RDBMSes and PyMongo for MongoDB, you can build some amazing data-driven applications. The choice is yours. Pick a small project to learn on and take Python for a spin.

Table 1: Feature highlights of C# and .NET

System.Object: Everything is an object.LINQ
IEnumerable + foreach loopsVisual Studio/IDEs
Class properties ( int Age {get; set;} )Side-by-side execution (isolation)
Anonymous types`Iterator` methods/yield return
Add referenceAnonymous methods/lambdas/closures
NuGet package management`Base` class libraries
Entity Framework/ORMsJIT compilation
Great debugging toolsResharper and IDE plugins
ASP.NET MVCGUI designers
Attributes and declarative programmingdynamic keyword
Back to article