Posted on Leave a comment

How to Filter a Dictionary in Python? (… The Most Pythonic Way)

Problem: Given a dictionary and a filter condition. How to filter a dictionary by …

  • key so that only those (key, value) pairs in the dictionary remain where the key satisfies the condition?
  • value so that only those (key, value) pairs remain where the value satisfies the condition?

In this tutorial, you’ll learn four methods and how they compare against each other. It’s loosely based on this tutorial but extends it by many additional examples and code explanations.

If you’re too busy to read this tutorial, here’s the spoiler:

Method 4 — Dictionary comprehension {k:v for (k,v) in dict.items() if condition} is the most Pythonic and fastest way to filter a dictionary in Python.

However, by reading this short 8-minute tutorial, you’re going to learn a lot about the nuances of writing Pythonic code. So keep reading!

Method 1: Simple Iteration to Filter Dictionary

You should always start with the simplest method to solve a problem (see Occam’s razor) because premature optimization is the root of all evil!

So let’s have a look at the straightforward loop iteration method to filter a dictionary.

You start with the following dictionary of names:

names = {1: 'Alice', 2: 'Bob', 3: 'Carl', 4: 'Ann', 5: 'Liz'}

Filter Python Dictionary By Key (Simple Loop)

You want to keep those (key, value) pairs where key meets a certain condition (such as key%2 == 1).

newDict = dict() # Iterate over all (k,v) pairs in names
for key, value in names.items(): # Is condition satisfied? if key%2 == 1: newDict[key] = value

Let’s have a look at the output:

print(newDict)
# {1: 'Alice', 3: 'Carl', 5: 'Liz'}

Only the (key, value) pairs where the key is an odd integer remain in the filtered dictionary newDict.

But what if you want to filter the dictionary by a condition on the values?

Filter Python Dictionary By Value (Simple Loop)

To filter by value, you only need to replace one line in the previous code snippet: instead of writing if key%2 == 1: ..., you use the value to determine whether to add a certain (key, value) pair: if len(value)<5: ....

newDict = dict() # Iterate over all (k,v) pairs in names
for key, value in names.items(): # Is condition satisfied? if len(value)<5: newDict[key] = value print(newDict)
# {2: 'Bob', 3: 'Carl', 4: 'Ann', 5: 'Liz'}

Only the dictionary (key, value) pairs remain in the filtered dictionary newDict where the length of the name string value is less than five characters.

Try It Yourself in Our Interactive Cod Shell (Click “run”):

Now, you know the basic method of filtering a dictionary in Python (by key and by value). But can we do better? What if you need to filter many dictionaries by many different filtering conditions? Do we have to rewrite the same code again and again?

The answer is no! Read on to learn about a more generic way to make filtering a dictionary as easy as calling a function passing the dictionary and the filter function.

Method 2: Generic Function to Filter Dictionary

How can you use different filtering functions on different dictionaries without writing the same code again and again? The answer is simple: create your own generic filtering function!

Your goal is to create a function filter_dict(dictionary, filter_func) that takes a dictionary to be filtered and a filter_func to determine for each (key, value) pair whether it should be included in the filtered dictionary.

You start with the following dictionary of names:

names = {1: 'Alice', 2: 'Bob', 3: 'Carl', 4: 'Ann', 5: 'Liz'}

Let’s create the generic filter function!

def filter_dict(d, f): ''' Filters dictionary d by function f. ''' newDict = dict() # Iterate over all (k,v) pairs in names for key, value in d.items(): # Is condition satisfied? if f(key, value): newDict[key] = value return newDict

The function takes two arguments: the dictionary d to be filtered and the function f that decides if an element should be included in the new dictionary.

You create an empty dictionary newDict and decide for all elements of the original dictionary d whether they should be included. To accomplish this, you iterate over each original (key, value) pair and pass it to the function f: key, value --> Boolean. The function f returns a Boolean value. If it evaluates to True, the (key, value) pair is added to the new dictionary. Otherwise, it’s skipped. The return value is the newly created dictionary newDict.

Here’s how you can use the filtering function to filter by key:

Filter Python Dictionary By Key Using Generic Function

If you want to accomplish the same thing as above—filtering by key to include only odd keys—you simply use the following one-liner call:

print(filter_dict(names, lambda k,v: k%2 == 1))
# {1: 'Alice', 3: 'Carl', 5: 'Liz'}

That was easy! The lambda function you pass returns k%2 == 1 which is the Boolean filtering value associated to each original element in the dictionary names.

Similarly, if you want to filter by key to include only even key, you’d do the following:

print(filter_dict(names, lambda k,v: k%2 == 0))
# {2: 'Bob', 4: 'Ann'}

In fact, it’s equally convenient to filter by value using this exact same strategy:

Filter Python Dictionary By Value Using Generic Function

Here’s how you use our function filter_dict to filter by value:

print(filter_dict(names, lambda k,v: len(v)<5))
# {2: 'Bob', 3: 'Carl', 4: 'Ann', 5: 'Liz'}

In the previous code snippet, you filter the dictionary so that only those (key, value) pairs remain where the value has less than five characters.

print(filter_dict(names, lambda k,v: v.startswith('A')))
# {1: 'Alice', 4: 'Ann'}

In this code snippet, you filter the dictionary so that only those (key, value) pairs remain where the value starts with character 'A'.

Try It Yourself in Our Interactive Cod Shell (Click “run”):

But is this the most Pythonic way? Hardly so! Read on to learn about a functional approach to accomplish the same thing with less code!

(More with less in Python is usually a good thing… Check out my book “Python One-Liners” to master the art of compressing complicated code into a single line.)

Method 3: filter() Function on Dictionary

The filter(function, iterable) function takes a function as input that takes one argument (an element of an iterable) and returns a Boolean value whether this element should pass the filter. All elements that pass the filter are returned as a new iterable object (a filter object).

You can use the lambda function statement to create the function right where you pass it as an argument. The syntax of the lambda function is lambda x: expression and it means that you use x as an input argument and you return expression as a result (that can or cannot use x to decide about the return value). For more information, see my detailed blog article about the lambda function.

Filter Python Dictionary By Key Using filter() + Lambda Functions

Here’s how you can filter a dictionary by key using only a single line of code (without defining your custom filter function as in method 2):

# FILTER BY KEY
print(dict(filter(lambda x: x[0]%2 == 1, names.items())))
# {1: 'Alice', 3: 'Carl', 5: 'Liz'}

You may recognize the same filter lambda function lambda x: x[0]%2 == 1 that returns True if the key is an odd integer. Note that this lambda function takes only a single input as this is how the filter() function works (it requires that you pass a function object that takes one argument and maps it to a Boolean value).

You operate on the iterable names.items() that gives you all (key, value) pairs (an element of the iterable is a (key, value) tuple).

After filtering, you convert the filter object back to a dictionary using the dict(...) constructor function.

Another example:

print(dict(filter(lambda x: x[0]%2 == 0, names.items())))
# {2: 'Bob', 4: 'Ann'}

Let’s see how this works for filtering by value:

Filter Python Dictionary By Value Using filter() + Lambda Functions

You can use the same basic idea—filter() + lambda + dict()—to filter a dictionary by value. For example, if you want to filter out all (key, value) pairs where the value has less than five characters, use the following one-liner:

print(dict(filter(lambda x: len(x[1])<5, names.items())))
# {2: 'Bob', 3: 'Carl', 4: 'Ann', 5: 'Liz'}

And a second example:

print(dict(filter(lambda x: x[1].startswith('A'), names.items())))
# {1: 'Alice', 4: 'Ann'}

Try It Yourself in Our Interactive Cod Shell (Click “run”):

So, far so good. But can we do any better? I mean, a single line of code is a single line of code, right? How can we possible improve on that?

Method 4: Filter By Dictionary Comprehension

The best way to filter a dictionary in Python is to use the powerful method of dictionary comprehension.

Dictionary comprehension allows you to transform one dictionary into another one—by modifying each (key, value) pair as you like.

Filter Python Dictionary By Key Using Dictionary Comprehension

The general framework for dictionary comprehension is { expression context }.

  • expression defines how you would like to change each (key, value) pair.
  • context defines the (key, value) pairs, you’d like to include in the new dictionary.

Here’s a practical example that filters all (key, value) pairs with odd keys:

print({k:v for (k,v) in names.items() if k%2 == 1})
# {1: 'Alice', 3: 'Carl', 5: 'Liz'}

And here’s an example that filters all (key, value) pairs with even keys:

print({k:v for (k,v) in names.items() if k%2 == 0})
# {2: 'Bob', 4: 'Ann'}

Let’s look at dictionary filtering by value! Is it any different?

Filter Python Dictionary By Value Using Dictionary Comprehension

No! It’s exactly the same:

print({k:v for (k,v) in names.items() if len(v)<5})
# {2: 'Bob', 3: 'Carl', 4: 'Ann', 5: 'Liz'}

This powerful framework is not only fast and easy to understand, it’s also concise and consistent. The filtering criteria is the last part of the expression so that you can quickly grasp how it’s filtered:

print({k:v for (k,v) in names.items() if v.startswith('A')})
# {1: 'Alice', 4: 'Ann'}

Try It Yourself in Our Interactive Cod Shell (Click “run”):

Related tutorials:

All Four Methods for Copy&Paste

Here are all four methods from the tutorial to simplify copy&pasting:

names = {1: 'Alice', 2: 'Bob', 3: 'Carl', 4: 'Ann', 5: 'Liz'} ''' Method 1: Simple For Loop ''' # FILTER BY KEY
newDict = dict() # Iterate over all (k,v) pairs in names
for key, value in names.items(): # Is condition satisfied? if key%2 == 1: newDict[key] = value print(newDict)
# {1: 'Alice', 3: 'Carl', 5: 'Liz'} # FILTER BY VALUE
newDict = dict() # Iterate over all (k,v) pairs in names
for key, value in names.items(): # Is condition satisfied? if len(value)<5: newDict[key] = value print(newDict)
# {2: 'Bob', 3: 'Carl', 4: 'Ann', 5: 'Liz'} ''' Method 2: Custom Function ''' def filter_dict(d, f): ''' Filters dictionary d by function f. ''' newDict = dict() # Iterate over all (k,v) pairs in names for key, value in d.items(): # Is condition satisfied? if f(key, value): newDict[key] = value return newDict # FILTER BY KEY
print(filter_dict(names, lambda k,v: k%2 == 1))
print(filter_dict(names, lambda k,v: k%2 == 0)) # FILTER BY VALUE
print(filter_dict(names, lambda k,v: len(v)<5))
print(filter_dict(names, lambda k,v: v.startswith('A'))) ''' Method 3: filter() ''' # FILTER BY KEY
print(dict(filter(lambda x: x[0]%2 == 1, names.items())))
print(dict(filter(lambda x: x[0]%2 == 0, names.items()))) # FITER BY VALUE
print(dict(filter(lambda x: len(x[1])<5, names.items())))
print(dict(filter(lambda x: x[1].startswith('A'), names.items()))) ''' Method 4: Dict Comprehension ''' # FITER BY KEY
print({k:v for (k,v) in names.items() if k%2 == 1})
print({k:v for (k,v) in names.items() if k%2 == 0}) # FITER BY VALUE
print({k:v for (k,v) in names.items() if len(v)<5})
print({k:v for (k,v) in names.items() if v.startswith('A')})

But how do all of those methods compare in terms of algorithmic complexity and runtime? Let’s see…

Algorithmic Analysis

Before we benchmark those methods against each other, let’s quickly discuss computational complexity.

All four methods have linear runtime complexity in the number of elements in the original dictionary to be filtered—assuming that the filtering condition itself has constant runtime complexity (it’s independent of the number of elements in the dictionary).

Method Complexity
Method 1: Loop O(n)
Method 2: Custom O(n)
Method 3: filter() O(n)
Method 4: Dictionary Comprehension O(n)

But this doesn’t mean that all methods are equally efficient. The dictionary comprehension is usually fastest for these types of filtering operations because it doesn’t use an intermediate function filter(). And it’s also easiest to understand. Therefore, you should use dictionary comprehension in your own code to filter a dictionary by key or by value!

Where to Go From Here?

Enough theory, let’s get some practice!

To become successful in coding, you need to get out there and solve real problems for real people. That’s how you can become a six-figure earner easily. And that’s how you polish the skills you really need in practice. After all, what’s the use of learning theory that nobody ever needs?

Practice projects is how you sharpen your saw in coding!

Do you want to become a code master by focusing on practical code projects that actually earn you money and solve problems for people?

Then become a Python freelance developer! It’s the best way of approaching the task of improving your Python skills—even if you are a complete beginner.

Join my free webinar “How to Build Your High-Income Skill Python” and watch how I grew my coding business online and how you can, too—from the comfort of your own home.

Join the free webinar now!

Posted on Leave a comment

Introducing Project Tye

Amiee Lo

Amiee

Project Tye is an experimental developer tool that makes developing, testing, and deploying microservices and distributed applications easier.

When building an app made up of multiple projects, you often want to run more than one at a time, such as a website that communicates with a backend API or several services all communicating with each other. Today, this can be difficult to setup and not as smooth as it could be, and it’s only the very first step in trying to get started with something like building out a distributed application. Once you have an inner-loop experience there is then a, sometimes steep, learning curve to get your distributed app onto a platform such as Kubernetes.

The project has two main goals:

  1. Making development of microservices easier by:
    • Running many services with one command
    • Using dependencies in containers
    • Discovering addresses of other services using simple conventions
  2. Automating deployment of .NET applications to Kubernetes by:
    • Automatically containerizing .NET applications
    • Generating Kubernetes manifests with minimal knowledge or configuration
    • Using a single configuration file

If you have an app that talks to a database, or an app that is made up of a couple of different processes that communicate with each other, then we think Tye will help ease some of the common pain points you’ve experienced.

We have recently demonstrated Tye in a few Build sessions that we encourage you to watch, Cloud Native Apps with .NET and AKS and Journey to one .NET

Installation

To get started with Tye, you will first need to have .NET Core 3.1 installed on your machine.

Tye can then be installed as a global tool using the following command:

dotnet tool install -g Microsoft.Tye --version "0.2.0-alpha.20258.3"

Running a single service

Tye makes it very easy to run single applications. To demonstrate this:

1. Make a new folder called microservices and navigate to it:

mkdir microservices
cd microservices

2. Then create a frontend project:

dotnet new razor -n frontend

3. Now run this project using tye run:

tye run frontend

Image tye run output The above displays how Tye is building, running, and monitoring the frontend application.

One key feature from tye run is a dashboard to view the state of your application. Navigate to http://localhost:8000 to see the dashboard running.

Image tye dashboard

The dashboard is the UI for Tye that displays a list of all of your services. The Bindings column has links to the listening URLs of the service. The Logs column allows you to view the streaming logs for the service.

Image tye logs

Services written using ASP.NET Core will have their listening ports assigned randomly if not explicitly configured. This is useful to avoid common issues like port conflicts.

Running multiple services

Instead of just a single application, suppose we have a multi-application scenario where our frontend project now needs to communicate with a backend project. If you haven’t already, stop the existing tye run command using Ctrl + C.

1. Create a backend API that the frontend will call inside of the microservices/ folder.

dotnet new webapi -n backend

2. Then create a solution file and add both projects:

dotnet new sln
dotnet sln add frontend backend

You should now have a solution called microservices.sln that references the frontend and backend projects.

3. Run tye in the folder with the solution.

tye run

The dashboard should show both the frontend and backend services. You can navigate to both of them through either the dashboard of the url outputted by tye run.

The backend service in this example was created using the webapi project template and will return an HTTP 404 for its root URL.

Getting the frontend to communicate with the backend

Now that we have two applications running, let’s make them communicate.

To get both of these applications communicating with each other, Tye utilizes service discovery. In general terms, service discovery describes the process by which one service figures out the address of another service. Tye uses environment variables for specifying connection strings and URIs of services.

The simplest way to use Tye’s service discovery is through the Microsoft.Extensions.Configuration system – available by default in ASP.NET Core or .NET Core Worker projects. In addition to this, we provide the Microsoft.Tye.Extensions.Configuration package with some Tye-specific extensions layered on top of the configuration system.

If you want to learn more about Tye’s philosophy on service discovery and see detailed usage examples, check out this reference document.

1. If you haven’t already, stop the existing tye run command using Ctrl + C. Open the solution in your editor of choice.

2. Add a file WeatherForecast.cs to the frontend project.

using System; namespace frontend { public class WeatherForecast { public DateTime Date { get; set; } public int TemperatureC { get; set; } public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); public string Summary { get; set; } } }

This will match the backend WeatherForecast.cs.

3. Add a file WeatherClient.cs to the frontend project with the following contents:

using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks; namespace frontend
{ public class WeatherClient { private readonly JsonSerializerOptions options = new JsonSerializerOptions() { PropertyNameCaseInsensitive = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, }; private readonly HttpClient client; public WeatherClient(HttpClient client) { this.client = client; } public async Task<WeatherForecast[]> GetWeatherAsync() { var responseMessage = await this.client.GetAsync("/weatherforecast"); var stream = await responseMessage.Content.ReadAsStreamAsync(); return await JsonSerializer.DeserializeAsync<WeatherForecast[]>(stream, options); } }
}

4. Add a reference to the Microsoft.Tye.Extensions.Configuration package to the frontend project

dotnet add frontend/frontend.csproj package Microsoft.Tye.Extensions.Configuration --version "0.2.0-*"

5. Now register this client in frontend by adding the following to the existing ConfigureServices method to the existing Startup.cs file:

...
public void ConfigureServices(IServiceCollection services)
{ services.AddRazorPages(); /** Add the following to wire the client to the backend **/ services.AddHttpClient<WeatherClient>(client => { client.BaseAddress = Configuration.GetServiceUri("backend"); }); /** End added code **/
}
...

This will wire up the WeatherClient to use the correct URL for the backend service.

6. Add a Forecasts property to the Index page model under Pages\Index.cshtml.cs in the frontend project.

... public WeatherForecast[] Forecasts { get; set; }
...

7. Change the OnGet method to take the WeatherClient to call the backend service and store the result in the Forecasts property:

... public async Task OnGet([FromServices]WeatherClient client) { Forecasts = await client.GetWeatherAsync(); }
...

8. Change the Index.cshtml razor view to render the Forecasts property in the razor page:

@page
@model IndexModel
@{ ViewData["Title"] = "Home page";
} <div class="text-center"> <h1 class="display-4">Welcome</h1> <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div> Weather Forecast: <table class="table"> <thead> <tr> <th>Date</th> <th>Temp. (C)</th> <th>Temp. (F)</th> <th>Summary</th> </tr> </thead> <tbody> @foreach (var forecast in @Model.Forecasts) { <tr> <td>@forecast.Date.ToShortDateString()</td> <td>@forecast.TemperatureC</td> <td>@forecast.TemperatureF</td> <td>@forecast.Summary</td> </tr> } </tbody>
</table>

9. Run the project with tye run and the frontend service should be able to successfully call the backend service!

When you visit the frontend service you should see a table of weather data. This data was produced randomly in the backend service. The fact that you’re seeing it in a web UI in the frontend means that the services are able to communicate. Unfortunately, this doesn’t work out of the box on Linux right now due to how self-signed certificates are handled, please see the workaround here

Tye’s configuration schema

Tye has a optional configuration file (tye.yaml) to enable customizing settings. This file contains all of your projects and external dependencies. If you have an existing solution, Tye will automatically populate this with all of your current projects.

To initalize this file, you will need to run the following command in the microservices directory to generate a default tye.yaml file:

tye init

The contents of the tye.yaml should look like this:

Image tye yaml

The top level scope (like the name node) is where global settings are applied.

tye.yaml lists all of the application’s services under the services node. This is the place for per-service configuration.

To learn more about Tye’s yaml specifications and schema, you can check it out here in Tye’s repository on Github.

We provide a json-schema for tye.yaml and some editors support json-schema for completion and validation of yaml files. See json-schema for instructions.

Adding external dependencies (Redis)

Not only does Tye make it easy to run and deploy your applications to Kubernetes, it’s also fairly simple to add external dependencies to your applications as well. We will now add redis to the frontend and backend application to store data.

Tye can use Docker to run images that run as part of your application. Make sure that Docker is installed on your machine.

1. Change the WeatherForecastController.Get() method in the backend project to cache the weather information in redis using an IDistributedCache.

2. Add the following using‘s to the top of the file:

using Microsoft.Extensions.Caching.Distributed;
using System.Text.Json;

3. Update Get():

[HttpGet]
public async Task<string> Get([FromServices]IDistributedCache cache)
{ var weather = await cache.GetStringAsync("weather"); if (weather == null) { var rng = new Random(); var forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] }) .ToArray(); weather = JsonSerializer.Serialize(forecasts); await cache.SetStringAsync("weather", weather, new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(5) }); } return weather;
}

This will store the weather data in Redis with an expiration time of 5 seconds.

4. Add a package reference to Microsoft.Extensions.Caching.StackExchangeRedis in the backend project:

cd backend/
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis
cd ..

5. Modify Startup.ConfigureServices in the backend project to add the redis IDistributedCache implementation.

 public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddStackExchangeRedisCache(o => { o.Configuration = Configuration.GetConnectionString("redis"); }); }

The above configures redis to the configuration string for the redis service injected by the tye host.

6. Modify tye.yaml to include redis as a dependency.

name: microservice
services:
- name: backend project: backend\backend.csproj
- name: frontend project: frontend\frontend.csproj
- name: redis image: redis bindings: - port: 6379 connectionString: "${host}:${port}"
- name: redis-cli image: redis args: "redis-cli -h redis MONITOR"

We’ve added 2 services to the tye.yaml file. The redis service itself and a redis-cli service that we will use to watch the data being sent to and retrieved from redis.

The "${host}:${port}" format in the connectionString property will substitute the values of the host and port number to produce a connection string that can be used with StackExchange.Redis.

7. Run the tye command line in the solution root

Make sure your command-line is in the microservices/ directory. One of the previous steps had you change directories to edit a specific project.

tye run

Navigate to http://localhost:8000 to see the dashboard running. Now you will see both redis and the redis-cli running listed in the dashboard.

Navigate to the frontend application and verify that the data returned is the same after refreshing the page multiple times. New content will be loaded every 5 seconds, so if you wait that long and refresh again, you should see new data. You can also look at the redis-cli logs using the dashboard and see what data is being cached in redis.

The "${host}:${port}" format in the connectionString property will substitute the values of the host and port number to produce a connection string that can be used with StackExchange.Redis.

Deploying to Kubernetes

Tye makes the process of deploying your application to Kubernetes very simple with minimal knowlege or configuration required.

Tye will use your current credentials for pushing Docker images and accessing Kubernetes clusters. If you have configured kubectl with a context already, that’s what tye deploy is going to use!

Prior to deploying your application, make sure to have the following:

  1. Docker installed based off on your operating system
  2. A container registry. Docker by default will create a container registry on DockerHub. You could also use Azure Container Registry (ACR) or another container registry of your choice.
  3. A Kubernetes Cluster. There are many different options here, including:

If you choose a container registry provided by a cloud provider (other than Dockerhub), you will likely have to take some steps to configure your kubernetes cluster to allow access. Follow the instructions provided by your cloud provider.

Deploying Redis

tye deploy will not deploy the redis configuration, so you need to deploy it first by running:

kubectl apply -f https://raw.githubusercontent.com/dotnet/tye/master/docs/tutorials/hello-tye/redis.yaml

This will create a deployment and service for redis.

Tye deploy

You can deploy your application by running the follow command:

tye deploy --interactive

Enter the Container Registry (ex: example.azurecr.io for Azure or example for dockerhub):

You will be prompted to enter your container registry. This is needed to tag images, and to push them to a location accessible by kubernetes.

Image tye deploy output

If you are using dockerhub, the registry name will be your dockerhub username. If you are using a standalone container registry (for instance from your cloud provider), the registry name will look like a hostname, eg: example.azurecr.io.

You’ll also be prompted for the connection string for redis.

Image redis connection string

Enter the following to use the instance that you just deployed:

redis:6379

tye deploy will create Kubernetes secret to store the connection string.

–interactive is needed here to create the secret. This is a one-time configuration step. In a CI/CD scenario you would not want to have to specify connection strings over and over, deployment would rely on the existing configuration in the cluster.

Tye uses Kubernetes secrets to store connection information about dependencies like redis that might live outside the cluster. Tye will automatically generate mappings between service names, binding names, and secret names.

tye deploy does many different things to deploy an application to Kubernetes. It will:

  • Create a docker image for each project in your application.
  • Push each docker image to your container registry.
  • Generate a Kubernetes Deployment and Service for each project.
  • Apply the generated Deployment and Service to your current Kubernetes context.

Image tye deploy building images

You should now see three pods running after deploying.

kubectl get pods NAME READY STATUS RESTARTS AGE
backend-ccfcd756f-xk2q9 1/1 Running 0 85m
frontend-84bbdf4f7d-6r5zp 1/1 Running 0 85m
redis-5f554bd8bd-rv26p 1/1 Running 0 98m

You can visit the frontend application, you will need to port-forward to access the frontend from outside the cluster.

kubectl port-forward svc/frontend 5000:80

Now navigate to http://localhost:5000 to view the frontend application working on Kubernetes.

Image kubernetes portforward

Currently tye does not automatically enable TLS within the cluster, and so communication takes place over HTTP instead of HTTPS. This is typical way to deploy services in kubernetes – we may look to enable TLS as an option or by default in the future.

Adding a registry to tye.yaml

If you want to use tye deploy as part of a CI/CD system, it’s expected that you’ll have a tye.yaml file initialized. You will then need to add a container registry to tye.yaml. Based on what container registry you configured, add the following line in the tye.yaml file:

registry: <registry_name>

Now it’s possible to use tye deploy without --interactive since the registry is stored as part of configuration.

This step may not make much sense if you’re using tye.yaml to store a personal Dockerhub username. A more typical use case would storing the name of a private registry for use in a CI/CD system.

For a conceptual overview of how Tye behaves when using tye deploy for deployment, check out this document.

Undeploying your application

After deploying and playing around with the application, you may want to remove all resources associated from the Kubernetes cluster. You can remove resources by running:

tye undeploy

This will remove all deployed resources. If you’d like to see what resources would be deleted, you can run:

tye undeploy --what-if

If you want to experiment more with using Tye, we have a variety of different sample applications and tutorials that you can walk through, check them out down below:

We have been diligently working on adding new capabilities and integrations to continuously improve Tye. Here are some integrations below that we have recently released. There is also information provided on how to get started for each of these:

  • Ingressto expose pods/services created to the public internet.
  • Redisto store data, cache, or as a message broker.
  • Daprfor integrating a Dapr application with Tye.
  • Zipkinusing Zipkin for distributed tracing.
  • Elastic Stackusing Elastic Stack for logging.

While we are excited about the promise Tye holds, it’s an experimental project and not a committed product. During this experimental phase we expect to engage deeply with anyone trying out Tye to hear feedback and suggestions. The point of doing experiments in the open is to help us explore the space as much as we can and use what we learn to determine what we should be building and shipping in the future.

Project Tye is currently commited as an experiment until .NET 5 ships. At which point we will be evaluating what we have and all that we’ve learnt to decide what we should do in the future.

Our goal is to ship every month, and some new capabilities that we are looking into for Tye include:

  • More deployment targets
  • Sidecar support
  • Connected development
  • Database migrations

We are excited by the potential Tye has to make developing distributed applications easier and we need your feedback to make sure it reaches that potential. We’d really love for you to try it out and tell us what you think, there is a link to a survey on the Tye dashboard that you can fill out or you can create issues and talk to us on GitHub. Either way we’d love to hear what you think.

Posted on Leave a comment

Runtime Complexity of Python List Methods [Easy Table Lookup]

What’s the runtime complexity of various list methods?

The following table summarizes the runtime complexity of all list methods.

Assume that the length of the data type is defined as n (that is—len(data_type)). You can now categorize the asymptotic complexity of the different complexity functions as follows:

Operation Example Complexity
Index l[i] O(1)
Store l[i] = 42 O(1)
Length len(l) O(1)
Append l.append(42) O(1)
Pop l.pop() O(1)
Clear l.clear() O(1)
Slicing l[a:b] O(b-a)
Extend l1.extend(l2) O(len(l1)+len(l2))
Constructor list(iter) O(len(iter))
Equality l1 == l2 O(n)
Slice Assign l[a:b] = ... O(n)
Delete del l[i] O(n)
Remove l.remove(...) O(n)
Membership x in l / x not in l O(n)
Copy l.copy() O(n)
Pop l.pop(0) O(n)
Min min(l) O(n)
Max max(l) O(n)
Reverse l.reverse() O(n)
Iterate for x in l: O(n)
Sort l.sort() O(n log(n))
Multiply l*k O(n k)

Need to learn more about these methods? Watch me giving you a quick overview of all Python list methods:

You can read more about all methods in my detailed tutorial on the Finxter blog.

Here’s your free PDF cheat sheet showing you all Python list methods on one simple page. Click the image to download the high-resolution PDF file, print it, and post it to your office wall:

Where to Go From Here?

Enough theory, let’s get some practice!

To become successful in coding, you need to get out there and solve real problems for real people. That’s how you can become a six-figure earner easily. And that’s how you polish the skills you really need in practice. After all, what’s the use of learning theory that nobody ever needs?

Practice projects is how you sharpen your saw in coding!

Do you want to become a code master by focusing on practical code projects that actually earn you money and solve problems for people?

Then become a Python freelance developer! It’s the best way of approaching the task of improving your Python skills—even if you are a complete beginner.

Join my free webinar “How to Build Your High-Income Skill Python” and watch how I grew my coding business online and how you can, too—from the comfort of your own home.

Join the free webinar now!

Posted on Leave a comment

Complexity of Python Operations

In this tutorial, you’ll learn the runtime complexity of different Python operations.

Then, you’ll learn how to calculate the complexity of your own function by combining the complexity classes of its constituents. This is called “static analysis”

The tutorial is loosely based on (source) but it extends it significantly with more practical examples, interactive snippets, and explanatory material.

Introducing Big-O

Definition: The complexity of an operation (or an algorithm for that matter) is the number of resources that are needed to run it (source). Resources can be time (runtime complexity) or space (memory complexity).

So, how can you measure the complexity of an algorithm? In most cases, the complexity of an algorithm is not static. It varies with the size of the input to the algorithm or the operation.

For example, the list method list.sort() has one input argument: the list object to be sorted. The runtime complexity is not constant, it increases with increasing size of the list. If there are more elements to be sorted, the runtime of the algorithm increases.

Complexity Function

Given input size n, you can describe the complexity of your algorithm with a function of the input nf(n) that defines the number of “resource units” (e.g., time, memory) needed to finish it (worst-case or average-case).

Say, you’ve got three implementations to sort a list: implementation_1, implementation_2, implementation_3.

The figure shows the three complexity functions. The x axis measures the input size (in our example, it would be the list size). The y axis measures the complexity with respect to this input.

  • implementation_1 has a quadratic complexity function f(n) = n².
  • implementation_2 has a quadratic complexity function f(n) = 2n².
  • implementation_3 has a logarithmic complexity function f(n) = n log(n).

You can see the code we used to generate this plot here:

import matplotlib.pyplot as plt
import math implementation_1 = [n**2 for n in range(1, 100, 10)]
implementation_2 = [2*n**2 for n in range(1, 100, 10)]
implementation_3 = [n*math.log(n) for n in range(1, 100, 10)] plt.plot(implementation_1, '--.', label='implementation 1')
plt.plot(implementation_2, '-o', label='implementation 2')
plt.plot(implementation_3, '-x', label='implementation 3') plt.legend()
plt.xlabel('Input (ex: List Size)')
plt.ylabel('Complexity (ex: Runtime)')
plt.grid()
plt.show()

Of course, it’s good to waste as little resources as possible so the logarithmic complexity function is superior to the quadratic complexity functions.

Big-O Notation

For large inputs, the runtime behavior will be dominated by the part of the complexity function that grows fastest. For example, a quadratic runtime complexity function f(n) = 1000n² + 100000n + 999 will be much better than a cubic runtime complexity function g(n) = 0.1n³.

Why? Because sooner or later the function g(n) will produce much higher values than f(n) as the input size n increases.

In fact, you can argue that the only important part of a complexity function is the part that grows fastest with increasing input size.

This is exactly what’s the Big-O notation is all about:

The Big O notation characterizes functions according to their growth rates: different functions with the same growth rate may be represented using the same O notation. (wiki)

Roughly speaking, you remove everything but the fastest-growing term from the complexity function. This allows you to quickly compare different algorithms against each other.

To show this, have a look at our two examples:

  • Complexity function f(n) = 1000n² + 100000n + 999 grows like O(n²).
  • Complexity function g(n) = 0.1n³ grows like O(n³).

By reducing the complexity function to its asymptotic growth, you can immediately see that the former is superior to the latter in terms of runtime complexity—without being distracted by all the constant factors in front of the constituents or the constituents with smaller asymptotic growth.

Examples Big-O of Complexity Functions

So, here are a few examples of complexity functions and their asymptotic growth in Big-O notation:

Complexity Function Asymptotic Growth
f(n) = 10000 O(1)
f(n) = n + 1000000 O(n)
f(n) = 33n + log(n) O(n log(n))
f(n) = 33n + 4n * log(n) O(n log(n))
f(n) = n² + n O()
f(n) = 1000n² + 100000n + 999 O()
f(n) = 0.000000001n³ + 4n² + 100000n + 999 O()
f(n) = n * n³ + 33n O()

You can see that the asymptotic growth of a function (in Big-O notation) is dominated by the fastest-growing term in the function equation.

Python Complexity of Operations

Let’s explore the complexity of Python operations—classified by the data structure on which you perform those operations. A great coder will always use the data structure that suits their needs best.

In general, the list data structure supports more operations than the set data structure as it keeps information about the ordering of the elements—at the cost of higher computational complexity.

Python List Complexity

Assume that the length of the data type is defined as n (that is—n = len(data_type)). You can now categorize the asymptotic complexity of the different complexity functions as follows:

Operation Example Complexity
Index l[i] O(1)
Store l[i] = 42 O(1)
Length len(l) O(1)
Append l.append(42) O(1)
Pop l.pop() O(1)
Clear l.clear() O(1)
Slicing l[a:b] O(b-a)
Extend l1.extend(l2) O(len(l1)+len(l2))
Constructor list(iter) O(len(iter))
Equality l1 == l2 O(n)
Slice Assign l[a:b] = ... O(n)
Delete del l[i] O(n)
Remove l.remove(...) O(n)
Membership x in l / x not in l O(n)
Copy l.copy() O(n)
Pop l.pop(0) O(n)
Min min(l) O(n)
Max max(l) O(n)
Reverse l.reverse() O(n)
Iterate for x in l: O(n)
Sort l.sort() O(n log(n))
Multiply l*k O(n k)

Tuples are similar as lists—with a few exceptions: you cannot modify a tuple because they are immutable.

Let’s consider another important data structure:

Python Set Complexity

Assume that the length of the data type is defined as n (that is—n = len(data_type)). If there are two sets in a single operation such as s1 == s2, the lengths are given by the variables n1 and n2. You can now categorize the asymptotic complexity of the different complexity functions as follows:

Operation Example Complexity
Length len(s) O(1)
Add s.add(42) O(1)
Membership 42 in s / 42 not in s O(1)
Remove s.remove(42) O(1)
Pop s.pop() O(1)
Clear s.clear() O(1)
Constructor set(iter) O(n)
Equality s1 == s2 / s1 != s2 O(min(n1, n2))
Union s1 | s2 O(n1+n2)
Intersection s1 & s2 O(min(n1, n2))
Difference s1 - s2 O(n2)
Symmetric Difference s1 ^ s2 O(n1)
Iteration for x in s: O(n)
Copy s.copy() O(n)

I highlighted the set operations that are more efficient than the corresponding list operations. The reason for those being O(1) rather than O(n) is that the list data structure also maintains the ordering of the elements—which incurs additional overhead.

Python Dictionary Complexity

Now, have a look at the time complexity of Python dictionary operations:

Operation Example Complexity
Index (Get) dict[k] O(1)
Store dict[k] = v O(1)
Length len(dict) O(1)
Delete del dict[key] O(1)
Pop dict.pop(k) O(1)
Clear dict.clear() O(1)
Keys dict.keys() O(1)
Construction dict(...) O(n)
Iteration for k in dict: O(n)

Most operations are O(1) because Python dictionaries share multiple properties of Python sets (such as fast membership operation).

Composing Complexity Classes

Now, you know the complexity of different operations. But how do you obtain the complexity of your algorithm?

The concept is simple: you break the big problem (knowing the complexity of the whole algorithm) into a series of smaller problems (knowing the complexity of individual operations).

Then, you recombine the individual operation’s complexities to obtain the solution to the big problem.

How? Let’s start with a small example: you first get a list from a dictionary of list values. Then you sort the list:

d = {1: [3, 1, 2, 4], 2: [4, 4, 1, 9]} lst = d.get(1)
lst.sort()
print(lst)
# [1, 2, 3, 4]

Try it yourself in our interactive code shell (click “run” to execute the code):

You have four operations in the code snippet. Let’s annotate each operation with a complexity class.

# Operation 1: Dictionary Creation --> O(n)
d = {1: [3, 1, 2, 4], 2: [4, 4, 1, 9]} # Operation 2: Dictionary Get --> O(1)
lst = d.get(1) # Operation 3: List Sorting --> O(n log n)
lst.sort() # Operation 4: Print List --> O(n)
print(lst)

Knowing the complexity classes of the different operations, you can recombine it as follows:

O(n) + O(1) + O(n log n) + O(n)
(1) = O(n + 1 + n log n + n)
(2) = O(n log n + 2n + 1)
(3) = O(n log n)

You see in Equation (1) what you could call the “chain rule of complexity analysis”: O(f(n)) + O(g(n)) = O(f(n) + g(n)).

You can see in Equation (3) that the Big-O notation focuses only on the largest growing term. In our case, O(n log n) grows faster than O(2n).

Here are two important examples of Big-O recombination:

  • O(f(n)) + O(f(n)) = O(f(n) + f(n)) = O(2f(n)) = O(f(n). In other words, Executing an operation a constant (fixed) number of times, doesn’t change the overall complexity of the algorithm.
  • O(f(n) + g(n)) = O(f(n)) if the complexity function f(n) grows faster than g(n). An example is O(n³ + 1000n³) = O(n³).

In programming, you can also have conditional execution:

if condition: f(n)
else: g(n)

You can recombine the complexity class of the overall code snippet as follows: O(max(f(n), g(n)). Roughly speaking, (if the condition can be true), the complexity of the conditional execution is the maximum of both blocks f(n) or g(n).

Example:

if lst: lst.sort()
else: lst = [1, 2, 3, 4]

The complexity is O(n log n) because it grows faster than O(n) — the complexity of the block in the else statement.

Another possibility is to repeatedly execute a certain function (e.g., in a for loop).

If you repeat function f(n) m times, the computational complexity is m * O(f(n)) = O(m f(n)). If m is a constant, the computational complexity simplifies to O(f(n)).

Where to Go From Here?

Enough theory, let’s get some practice!

To become successful in coding, you need to get out there and solve real problems for real people. That’s how you can become a six-figure earner easily. And that’s how you polish the skills you really need in practice. After all, what’s the use of learning theory that nobody ever needs?

Practice projects is how you sharpen your saw in coding!

Do you want to become a code master by focusing on practical code projects that actually earn you money and solve problems for people?

Then become a Python freelance developer! It’s the best way of approaching the task of improving your Python skills—even if you are a complete beginner.

Join my free webinar “How to Build Your High-Income Skill Python” and watch how I grew my coding business online and how you can, too—from the comfort of your own home.

Join the free webinar now!

Posted on Leave a comment

Python List Concatenation: Add (+) vs INPLACE Add (+=) vs extend()

A wildly popular operation you’ll find in any (non-trivial) code base is to concatenate lists—but there are multiple methods to accomplish this. Master coders will always choose the right method for the right problem.

This tutorial shows you the difference between three methods to concatenate lists:

  • Concatenate two lists with the + operator. For example, the expression [1, 2, 3] + [4, 5] results in a new list [1, 2, 3, 4, 5]. More here.
  • Concatenate two lists with the += operator. This operation is inplace which means that you don’t create a new list and the result of the expression lst += [4, 5] is to add the elements on the right to the existing list object lst. More here.
  • Concatenate two lists with the extend() method of Python lists. Like +=, this method modifies an existing list in place. So the result of lst.extend([4, 5]) adds the elements 4 and 5 to the list lst. More here.

To summarize: the difference between the + method and the += and extend() methods is that the former creates a new list and the latter modify an existing list object in-place.

You can quickly compare those three methods in the following interactive code shell:

Puzzle: Can you already figure out the outputs of this code snippet?

Fear not if you can’t! I’ll explain you each detailed example next.

Method 1: Add (+)

The standard way of adding two lists is to use the + operator like this:

# METHOD 1: ADD +
lst = ['Alice', 'Bob', 'Ann']
lst_new = lst + [42, 21]
print(lst)
print(lst_new)

While the + operator is the most readable one (especially for beginner coders), it’s not the best choice in most scenarios. The reason is that it creates a new list each time you call it. This can become very slow and I’ve seen many practical code snippets where the list data structure used with the + operator is the bottleneck of the whole algorithm.

In the above code snippet, you create two list objects in memory—even though your goal is probably just to update the existing list ['Alice', 'Bob', 'Ann'].

This can be nicely demonstrated in the code visualization tool:

Just keep clicking “Next” until the second list appears in memory.

Method 2: INPLACE Add (+=)

The += operator is not well understood by the Python community. Many of my students (join us for free) believe the add operation lst += [3, 4] is just short for lst = lst + [3, 4]. This is wrong and I’ll demonstrate it in the following example:

# METHOD 2: INPLACE ADD +=
lst = ['Alice', 'Bob', 'Ann']
lst_old = lst
lst += [42, 21]
print(lst)
print(lst_old)

Again, you can visualize the memory objects with the following interactive tool (click “Next”):

The takeaway is that the += operation performs INPLACE add. It changes an existing list object rather than creating a new one. This makes it more efficient in the majority of cases. Only if you absolutely need to create a new list, you should use the + operator. In all other cases, you should use the += operator or the extend() method.

Speaking of which…

Method 3: Extend()

Like the previous method +=, the list.extend(iterable) method adds a number of elements to the end of a list. The method operators in-place so no new list object is created.

# METHOD 3: EXTEND()
lst = ['Alice', 'Bob', 'Ann']
lst_old = lst
lst.extend([42, 21])
print(lst)
print(lst_old)

Here’s the interactive memory visualization:

Click “Next” and explore how the memory allocation “unfolds” as the execution proceeds.

Speed Comparison Benchmark

Having understood the differences of the three methods + vs += vs extend(), you may ask: what’s the fastest?

To help you understand why it’s important to choose the best method, I’ve performed a detailed speed benchmark on my Intel i7 (8th Gen) Notebook (8GB RAM) concatenating lists with increasing sizes using the three methods described previously.

Here’s the result:

The plot shows that with increasing list size, the runtime difference between the + method (Method 1), and the += and extend() methods (Methods 2 and 3) becomes increasingly evident. The former creates a new list for each concatenation operation—and this slows it down.

Result: Thus, both INPLACE methods += and extend() are more than 30% faster than the + method for list concatenation.

You can reproduce the result with the following code snippet:

import time # Compare runtime of three methods
list_sizes = [i * 300000 for i in range(40)]
runtimes_1 = [] # Method 1: + Operator
runtimes_2 = [] # Method 2: += Operator
runtimes_3 = [] # Method 3: extend() for size in list_sizes: to_add = list(range(size)) # Get time stamps time_0 = time.time() lst = [1] lst = lst + to_add time_1 = time.time() lst = [1] lst += to_add time_2 = time.time() lst = [1] lst.extend(to_add) time_3 = time.time() # Calculate runtimes runtimes_1.append((size, time_1 - time_0)) runtimes_2.append((size, time_2 - time_1)) runtimes_3.append((size, time_3 - time_2)) # Plot everything
import matplotlib.pyplot as plt
import numpy as np runtimes_1 = np.array(runtimes_1)
runtimes_2 = np.array(runtimes_2)
runtimes_3 = np.array(runtimes_3) print(runtimes_1)
print(runtimes_2)
print(runtimes_3) plt.plot(runtimes_1[:,0], runtimes_1[:,1], label='Method 1: +')
plt.plot(runtimes_2[:,0], runtimes_2[:,1], label='Method 2: +=')
plt.plot(runtimes_3[:,0], runtimes_3[:,1], label='Method 3: extend()') plt.xlabel('list size')
plt.ylabel('runtime (seconds)') plt.legend()
plt.savefig('speed.jpg')
plt.show()

If you liked this tutorial, join my free email list where I’ll send you the most comprehensive FREE Python email academy right in your INBOX.

Join the Finxter Community Now!

Where to Go From Here?

Enough theory, let’s get some practice!

To become successful in coding, you need to get out there and solve real problems for real people. That’s how you can become a six-figure earner easily. And that’s how you polish the skills you really need in practice. After all, what’s the use of learning theory that nobody ever needs?

Practice projects is how you sharpen your saw in coding!

Do you want to become a code master by focusing on practical code projects that actually earn you money and solve problems for people?

Then become a Python freelance developer! It’s the best way of approaching the task of improving your Python skills—even if you are a complete beginner.

Join my free webinar “How to Build Your High-Income Skill Python” and watch how I grew my coding business online and how you can, too—from the comfort of your own home.

Join the free webinar now!

Posted on Leave a comment

Blazor WebAssembly 3.2.0 now available

Daniel Roth

Daniel

I’m thrilled to announce that Blazor WebAssembly is now officially released. This is a fully-featured and supported release of Blazor WebAssembly that is ready for production use. Full stack web development with .NET is now here!

Get started

Getting started with Blazor WebAssembly is easy: simply go to https://blazor.net and install the latest .NET Core SDK (3.1.300 or later), which includes everything you need to build and run Blazor WebAssembly apps.

You can then create and run your first Blazor WebAssembly app by running:

dotnet new blazorwasm -o BlazorApp1
cd BlazorApp1
dotnet run

Browse to https://localhost:5001 and voilà! You’ve just built and run your first Blazor WebAssembly app!

Running Blazor WebAssembly app

To maximize your Blazor productivity, be sure to install a supported version of Visual Studio for your platform of choice:

You can find additional docs and samples on https://blazor.net.

Upgrade an existing project

If you already have an existing Blazor WebAssembly project, you can upgrade it from the 3.2.0 Release Candidate to the official 3.2.0 release by doing the following:

  • Update all Microsoft.AspNetCore.Components.WebAssembly.* and System.Net.Http.Json package references to version 3.2.0.

That’s it, you’re all set!

What is Blazor WebAssembly?

In case this is your first time learning about Blazor, let me introduce you to what Blazor WebAssembly is all about.

Blazor is an open source and cross-platform web UI framework for building single-page apps using .NET and C# instead of JavaScript. Blazor is based on a powerful and flexible component model for building rich interactive web UI. You implement Blazor UI components using a combination of .NET code and Razor syntax: an elegant melding of HTML and C#. Blazor components can seamlessly handle UI events, bind to user input, and efficiently render UI updates.

Blazor components can then be hosted in different ways to create your web app. The first supported way is called Blazor Server. In a Blazor Server app, the components run on the server using .NET Core. All UI interactions and updates are handled using a real-time WebSocket connection with the browser. Blazor Server apps are fast to load and simple to implement. Support for Blazor Server is available with .NET Core 3.1 LTS.

Blazor WebAssembly is now the second supported way to host your Blazor components: client-side in the browser using a WebAssembly-based .NET runtime. Blazor WebAssembly includes a proper .NET runtime implemented in WebAssembly, a standardized bytecode for the web. This .NET runtime is downloaded with your Blazor WebAssembly app and enables running normal .NET code directly in the browser. No plugins or code transpilation are required. Blazor WebAssembly works with all modern web browsers, both desktop and mobile. Similar to JavaScript, Blazor WebAssembly apps run securely on the user’s device from within the browser’s security sandbox. These apps can be deployed as completely standalone static sites without any .NET server component at all, or they can be paired with ASP.NET Core to enable full stack web development with .NET, where code can be effortlessly shared with the client and server.

Fully-featured

Blazor WebAssembly comes packed with features to keep you productive on your next web app project:

Blazor in action

Blazor WebAssembly has everything you need to build fully-featured production web apps. To see all these Blazor WebAssembly features in action, checkout Steve Sanderson’s on-demand BUILD session (link should be live after 12pm PT): Modern Web UI with Blazor WebAssembly.

Ready-made components

Of course, any web app is going to need beautiful and feature rich components. A variety of Blazor UI components are available from our fantastic partners that work great in any Blazor app, including Blazor WebAssembly apps:

Open-source community

Blazor also has a thriving open-source community and ecosystem. Members of the community, (folks just like you!) have built lots of great component libraries, interop libraries, test frameworks, and more, and then made them freely available for you to use. Some great examples include:

You can find these community projects and many others listed on the Awesome Blazor GitHub repo.

LTS or Current?

Blazor WebAssembly 3.2.0 is a fully supported release under the .NET Core Support Policy. Since this is the first release of Blazor WebAssembly, it is a Current release, not an LTS release; it does not the inherit LTS status of .NET Core 3.1. This means that once Blazor WebAssembly ships with .NET 5 later this year, you will need to upgrade to .NET 5 to stay in support. We expect Blazor in .NET 5 to be a highly compatible release.

What’s next?

Now that we have shipped Blazor WebAssembly, we are shifting our attention to .NET 5. Work has already started on making Blazor WebAssembly available with .NET 5, which we expect to complete for preview next month.

We also have a number of Blazor features and improvements that we are investigating for the .NET 5 & 6 wave. You can see the list of core deliverables that we are considering in the Blazor Roadmap for .NET 5 issue on GitHub. Please note that we consider this list to be highly aspirational. While we hope to deliver all of the improvements listed, there are still many unknown and plans will certainly change as we go. We also expect that there will be plenty of smaller improvements that we will deliver as well.

We are also continuing to collaborate with our friends on the Xamarin team on experimental support for building native UI using Blazor through the Mobile Blazor Bindings project. This includes some early efforts to explore building hybrid UI for native apps, which we hope to share more about soon.

Thank you

We sincerely appreciate all the enthusiastic support we have received from the Blazor community as we’ve worked to make the release a reality. The number of Blazor articles, blog posts, docs, sample apps, libraries, books, videos, presentations, workshops, courses, meetups, feature suggestions, and feedback issues that have been contributed by the community to the Blazor ecosystem even while it was still in preview has been truly outstanding. To everyone who helped make this release possible, thank you! We couldn’t have done it without you.

Try Blazor today

We hope you enjoy this release of Blazor WebAssembly. Give Blazor a try today by going to https://blazor.net. We look forward to seeing what you create with it.

As always, if you have any questions of feedback about Blazor please let us know by filing an issue on GitHub.

Posted on Leave a comment

ASP.NET Core updates in .NET 5 Preview 4

Avatar

Sourabh

.NET 5 Preview 4 is now available and is ready for evaluation! .NET 5 will be a current release.

Get started

To get started with ASP.NET Core in .NET 5.0 Preview4 install the .NET 5.0 SDK.

If you’re on Windows using Visual Studio, we recommend installing the latest preview of Visual Studio 2019 16.6.

If you’re on macOS, we recommend installing the latest preview of Visual Studio 2019 for Mac 8.6.

Upgrade an existing project

To upgrade an existing ASP.NET Core 5.0 preview3 app to ASP.NET Core 5.0 preview4:

  • Update all Microsoft.AspNetCore.* package references to 5.0.0-preview.4.*.
  • Update all Microsoft.Extensions.* package references to 5.0.0-preview.4.*.

See the full list of breaking changes in ASP.NET Core 5.0.

That’s it! You should now be all set to use .NET 5 Preview 4.

What’s new?

Performance Improvements to HTTP/2

By adding support for HPack dynamic compression of HTTP/2 response headers in Kestrel, the 5.0.0-prevew4 release improves the performance of HTTP/2. For more information on how HPACK helps save bandwidth and help reduce latency, we recommend reading this excellent write-up by the team at CloudFlare.

Reduction in container image sizes

The canonical multi-stage Docker build for ASP.NET Core involves pulling both the SDK image and ASP.NET Core runtime image. By re-platting the SDK image upon the ASP.NET runtime image, we’re sharing layers between the two images. This dramatically reduces the size of the aggregate images that you pull. For more information about the size improvements and other container enhancements, check out the .NET 5 Preview 4 blog post

See the release notes for additional details and known issues.

Give feedback

We hope you enjoy this release of ASP.NET Core in .NET 5! We are eager to hear about your experiences with this latest .NET 5 release. Let us know what you think by filing issues on GitHub.

Thanks for trying out ASP.NET Core!

Posted on Leave a comment

[Free PDF Download] Coffee Break Python – Mastery Workout

Want to boost your Python skills to the next level as an intermediate coder? Want to know how to overcome being stuck at average coding level? Do you enjoy solving puzzles?

We’re excited to release a new fresh, and tough Finxter book with 99 never-seen Python puzzles. It’s the hardest one in our Coffee Break Python series.

IF YOU CAN DO IT THERE, YOU CAN DO IT EVERYWHERE!

If you want to download a 50-page sample of the book for FREE, you’re on the right spot:

Title: Coffee Break Python – Mastery Workout

Subtitle: 99 Tricky Python Puzzles to Push You to Programming Mastery

Download link PDF (sample): https://drive.google.com/open?id=1bBH0-Eu2fsF2U31xucd75IpjJxnBxz3z

Related articles:

Posted on Leave a comment

[Top 6] What’s the Best YouTube Channel to Learn Python? Channel #1 Will Surprise You

YouTube is a great way of learning Python. But those channels top all others. In this article, you’ll find a list of the top YouTube Channels — in reverse order!


Corey Schäfer #6

Channel link: https://www.youtube.com/user/schafer5/

37,444,096 channel views

Channel Description: This channel is focused on creating tutorials and walkthroughs for software developers, programmers, and engineers. We cover topics for all different skill levels, so whether you are a beginner or have many years of experience, this channel will have something for you.

We’ve already released a wide variety of videos on topics that include: Python, Git, Development Environments, Terminal Commands, SQL, Programming Terms, JavaScript, Computer Science Fundamentals, and plenty of other tips and tricks which will help you in your career.


Clever Programmer #5

Channel link: https://www.youtube.com/channel/UCqrILQNl5Ed9Dz6CGMyvMTQ

13,893,366 channel views

Channel Description: You can find awesome programming lessons here! Also, expect programming tips and tricks that will take your coding skills to the next level.


Real Python #4

Channel Link: https://www.youtube.com/channel/UCI0vQvr9aFn27yR6Ej6n5UA

2,166,889 channel views

Channel Description: On this channel you’ll get new Python videos and screencasts every week. They’re bite-sized and to the point so you can fit them in with your day and pick up new Python skills on the side:


CS Dojo #3

Channel Link: https://www.youtube.com/channel/UCxX9wt5FWQUAAz4UrysqK9A

36,733,368 channel views

Channel Description: The videos are mostly about programming and computer science (but also some interviews).


Socratia #2

Channel Link: https://www.youtube.com/user/SocraticaStudios

23,042,289 channel views

Channel Description: Socratica makes high-quality educational videos on math and science. The videos are …. different. Check them out to see what I mean!


Sentdex #1

Channel Link: https://www.youtube.com/user/sentdex

67,432,457 channel views

Channel Description: Python Programming tutorials, going further than just the basics. Learn about machine learning, finance, data analysis, robotics, web development, game development and more.


These are the best Python channels on YouTube. Check them out, there’s an infinite number of YT videos that will make you a better coder — for free!

The Finxter Channel

You may also check out the Finxter channel which is a small Python Business related channel. If you want to improve your Python business skills, this channel is for you!

Channel Link: https://www.youtube.com/channel/UCRlWL2q80BnI4sA5ISrz9uw

Subscribe to the Python email list for continuous improvement in computer science. It’s free!

Posted on Leave a comment

Python One-Liner Webserver HTTP

Want to create your own webserver in a single line of Python code? No problem, just use this command in your shell:

$ python -m http.server 8000

The terminal will tell you:

Serving HTTP on 0.0.0.0 port 8000

To shut down your webserver, kill the Python program with CTRL+c.

This works if you’ve Python 3 installed on your system. To check your version, use the command python --version in your shell.

You can run this command in your Windows Powershell, Win Command Line, MacOS Terminal, or Linux Bash Script.

You can see in the screenshot that the server runs on your local host listening on port 8000 (the standard HTTP port to serve web requests).

Note: The IP address is NOT 0.0.0.0—this is an often-confused mistake by many readers. Instead, your webserver listens at your “local” IP address 127.0.0.1 on port 8000. Thus, only web requests issued on your computer will arrive at this port. The webserver is NOT visible to the outside world.

Python 2: To run the same simple webserver on Python 2, you need to use another command using SimpleHTTPServer instead of http:

$ python -m SimpleHTTPServer 8000
Serving HTTP on 0.0.0.0 port 8000 ...

If you want to start your webserver from within your Python script, no problem:

import http.server
import socketserver PORT = 8000 Handler = http.server.SimpleHTTPRequestHandler with socketserver.TCPServer(("", PORT), Handler) as httpd: print("serving at port", PORT) httpd.serve_forever()

You can execute this in our online Python browser (yes, you’re creating a local webserver in the browser—how cool is that)!

This code comes from the official Python documentation—feel free to read more if you’re interested in setting up the server (most of the code is relatively self-explanatory).

Where to Go From Here?

Enough theory, let’s get some practice!

To become successful in coding, you need to get out there and solve real problems for real people. That’s how you can become a six-figure earner easily. And that’s how you polish the skills you really need in practice. After all, what’s the use of learning theory that nobody ever needs?

Practice projects is how you sharpen your saw in coding!

Do you want to become a code master by focusing on practical code projects that actually earn you money and solve problems for people?

Then become a Python freelance developer! It’s the best way of approaching the task of improving your Python skills—even if you are a complete beginner.

Join my free webinar “How to Build Your High-Income Skill Python” and watch how I grew my coding business online and how you can, too—from the comfort of your own home.

Join the free webinar now!