Computers funda

Monday, 28 January 2019

Python Lambdas Explained (With Examples)

Python Lambdas Explained (With Examples)

    In this article, I will teach you exactly what a python lambda is.
    As a matter of fact if you know what functions are and how to define functions in Python then you already know what a lambda is.
    A Python lambda is just a Python function.
    But may be like a special type of function that have limited capabilities 🙂
    If you want to dive deeper and learn more about lambdas and how they are used in Python then this is what this article is about.
    Here is what I will be talking about in this article.

    What is Python lambda?

    Before trying to understand what a Python lambda is, let’s first try to understand what a Python function is at a much deeper level.
    This will require a little bit of a paradigm shift of how you think about functions.
    As you already know, everything in Python is an object.
    For example, when we run this simple line of code.
    x = 5
    What actually happens is we’re creating a Python object of type int that stores the value 5.
    x is essentially a symbol that is referring to that object.
    Now let’s check the type of x and the address it is referring to.
    We can easily do that using the type and the id built-in functions.
    >>> type(x)
    <class 'int'>
    >>> id(x)
    4308964832
    As you can see, x refers to an object of type int and this object lives in the address returned by the id
    Pretty straightforward stuff.
    Now what happens when we define a function like this one:
    >>> def f(x):
    ...   return x * x
    ...
    Let’s repeat the same exercise from above and inspect the type of f and its id.
    >>> def f(x):
    ...   return x * x
    ...
    >>> type(f)
    <class 'function'>
    >>> id(f)
    4316798080
    hmm, very interesting.
    So it turns out there is a function class in Python and the function f that we just defined is an instance of that class.
    Exactly like how x was an instance of the integer class.
    In other words, you can literally think about functions the same way you think about variables.
    The only difference is that a variable stores data whereas a function stores code.
    That also means you can pass functions as arguments to other functions, or even have a function be the return value of another function.
    let’s look at a simple example where you can pass the above function f to another function.
    def f(x):
        return x * x
    
    def modify_list(L, fn):
        for idx, v in enumerate(L):
            L[idx] = fn(v)
    
    L = [1, 3, 2]
    modify_list(L, f)
    print(L)
    
    #output: [1, 9, 4]
    Give yourself a minute and try to understand what this code does before you read on…
    As you can see, modify_list is a function that takes a list L and a function fn as arguments.
    It then iterates over the list item-by-item and applies the function fn on each.
    This is a very generic way of modifying the items of a list as it allows you to pass in the function that is responsible for the modification which can be very useful as you will see later.
    So for example when we pass the function f to modify_list, the result will be that each item in the list will be squared.
    We could pass any other custom function that can modify the list in any arbitrary way.
    That’s pretty powerful stuff right there!
    Alright now that I have laid down some foundations, let’s talk about lambdas.
    Python lambda is just another method to define a function.
    The general syntax of a Python lambda is:
    lambda arguments: expression
    Lambda functions can accept zero or more arguments but only one expression.
    The return value of the lambda function is the value that this expression is evaluated to.
    For example, if we want to define the same function f that we defined before using lambda syntax, this is how it will look like:
    >>> f = lambda x: x * x
    >>> type(f)
    <class 'function'>
    But you might be asking yourself why the need for lambdas in the first place when we can just define functions the traditional way?
    Fair question!
    Actually, lambdas are only useful when you want to define a one-off function.
    In other words, a function that will be used only once in your program. These functions are called anonymous functions.
    As you will see later, there are many situations where anonymous functions can be useful.

    Lambdas with multiple arguments

    As you saw earlier, it was easy to define a lambda function with one argument.
    >>> f = lambda x: x * x
    >>> f(5)
    25
    But if you want to define a lambda function that accepts more than one argument, you can separate the input arguments by commas.
    For example, say we want to define a lambda that takes two integer arguments and returns their product.
    >>> f = lambda x, y: x * y
    >>> f(5, 2)
    10
    Nice!
    How about if you want to have a lambda that accepts no arguments whatsoever?

    Lambdas with no arguments

    Say you want to define a lambda function that takes no arguments and returns True.
    You can achieve this with the following code.
    >>> f = lambda: True
    >>> f()
    True

    Multiline lambdas

    Yes, at some point in your life you will be wondering if you can have a lambda function with multiple lines.
    And the answer is:
    No you can’t 🙂
    Python lambda functions accept only one and only one expression.
    If your function has multiple expressions/statements, you are better off defining a function the traditional way instead of using lambdas.

    Examples of Lambda in action

    Now let’s discuss some of the most common places where python lambdas are heavily used.

    Using lambdas with map

    One common operation you will apply to Python lists is to apply an operation to each item.
    Map is a Python built-in function that takes in a function and a sequence as arguments and then calls the input function on each item of the sequence.
    For example, assume we have a list of integers and we want to square each element of the list using the map function.
    >>> L = [1, 2, 3, 4]
    >>> list(map(lambda x: x**2, L))
    [1, 4, 9, 16]
    Note that in Python3, the map function returns a Map object whereas in Python2 it returns a list.
    See, instead of defining a function and then passing it to map as an argument, you can just use lambdas to quickly define a function inside the map parentheses.
    This makes sense especially if you are not going to use this function again in your code.
    Let’s take a look at another case where lambdas can be useful.

    Using lambdas with filter

    As the name suggests, filter is another built-in function that actually filters a sequence or any iterable object.
    In other words, given any iterable object (like a list), the filter function filters out some of the elements while keeping some based on some criteria.
    This criteria is defined by the caller of filter by passing in a function as an argument.
    This function is applied to each element of the iterable.
    If the return value is True, the element is kept. Otherwise, the element is disregarded.
    for example, let’s define a very simple function that returns True for even numbers and False for odd numbers:
    def even_fn(x):
      if x % 2 == 0:
        return True
      return False
    
    print(filter(even_fn, [1, 3, 2, 5, 20, 21]))
    
    #output: [2, 20]
    That said, With the magic of lambdas you can do the same thing more succinctly.
    The above code will transform into this one-liner
    print(filter(lambda x: x % 2 == 0, [1, 3, 2, 5, 20, 21]))
    And that, my friend, is the power of lambdas.

    Using lambdas with list sorting

    Sorting a Python list is a very common operation.
    In fact I have a whole in-depth article dedicated to this topic.
    If you have a list of numbers or strings, then sorting a list is very straightforward.
    You can just use the sort or sorted built-in functions.
    However, sometimes you have a list of custom objects and may be you want to sort the list based on a specific object field.
    In this case, you can pass an optional key parameter to either sort or sorted.
    This key parameter is actually of type function.
    The function is applied to all the list items and the return value is what’s going to be sorted.
    Let’s take an example.
    Assume you have an Employee class that looks like this
    class Employee:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    Now Let’s create some Employee objects and append them to a list.
    Alex = Employee('Alex', 20)
    Amanda = Employee('Amanda', 30)
    David = Employee('David', 15)
    L = [Alex, Amanda, David]
    Now say we want to sort this list based on the age of the employees, here is what we should do:
    L.sort(key=lambda x: x.age)
    print([item.name for item in L])
    # output: ['David', 'Alex', 'Amanda']
    See how we used a lambda expression as the key parameter instead of having to define a function externally and then passing this function to sort.

    One word on Expressions vs Statements

    Like I mentioned earlier, lambdas can use only one expression as the body of the lambda function.
    Notice I didn’t say one statement.
    Statements and expressions are two different things but they can be confusing so let me try to clarify the differences.
    In programming languages, a statement is a line of code that does something but it doesn’t evaluate to a value.
    For example, an if statement, a for loop, a while loop, all of these are examples of statements.
    You can’t simply replace the statement with a value because statements don’t evaluate to a value.
    Expressions on the other hand are evaluated to a value.
    You can easily replace all the expressions in your programs with some values and your program will work correctly.
    For example:
    3 + 5 is an expression that is evaluation to 8
    10 > 5 is an expression that is evaluated to True
    True and (5 < 3) is an expression that is evaluated to False
    Lambda’s body has to be an expression because the value of this expression is the return value of the function.
    Make sure you remember this point when you are writing your next lambda function 🙂

    Learning Python?

    If you are a beginner, then I highly recommend this book.
    No longer a beginner?

    Python: Let’s Create a Simple HTTP Server (Tutorial)

    Python: Let’s Create a Simple HTTP Server (Tutorial)

      Web severs are everywhere.
      Heck you are interacting with one right now!
      No matter what type of software engineer you are, at some point in your career you will have to interact with web servers. May be you are building an API server for a backend service. Or may be you are just configuring a web server for your website.
      In this article, I will cover how to create the most basic http web server in Python.
      But because I want to make sure you understand what we are building, I am going to give an overview first about what web servers are and how they work.
      If you already know how web servers work, then you can skip directly to this section.

      What is an HTTP Server?

      An HTTP web server is nothing but a process that is running on your machine and does exactly two things:
      1- Listens for incoming http requests on a specific TCP socket address (IP address and a port number which I will talk about later)
      2- Handles this request and sends a response back to the user.
      Let me make my point less abstract.
      Imagine you pull up your Chrome browser and type www.yahoo.com in the address bar.
      Of course you are going to get the Yahoo home page rendered on your browser window.
      But what really just happened under the hood?
      Actually a lot of things have happened and I might dedicate a whole article to explain the magic behind how this happened.
      But for the sake of simplicity, I will abstract away some of the details and talk about this at a very high level.
      At a high level, when you type www.yahoo.com on your browser, your browser will create a network message called an HTTP request.
      This Request will travel all the way to a Yahoo computer that has a web server running on it. This web server will intercept your request, and handle it by responding back with the html of the Yahoo home page.
      Finally your browser renders this html on the screen and that’s what you see on your screen.
      Every interaction with the Yahoo home page after that (for example, when you click on a link) initiates a new request and response exactly like the first one.
      To reiterate, the machine that receives the http request has a software process called a web server running on it. This web server is responsible for intercepting these requestsand handling them appropriately.
      Alright, now that you know what a web server is and what its function is exactly, you might be wondering how does the request reach that yahoo machine in the first place?
      Good question!
      In fact this is one of my favorite questions that I ask potential candidates in a coding interview.
      Let me explain how, but again….at a high level.

      The TCP Socket Address

      Any http message (whether it is a request or response) needs to know how to reach its destination.
      In order to reach its destination, each http message carries an address called the destination TCP address.
      And each TCP address is composed of an IP address and a port number.
      I know all these acronyms (TCP, IP, etc..) might be overwhelming if your networking concepts are not strong.
      I will try to keep it simple but if you are interested in improving your knowledge of networking concepts, I highly recommend this book by Ross and Kurose.
      So where is that address when all you did was type www.yahoo.com on your browser?
      Well, this domain name is converted into an IP address through a large distributed database called the DNS.
      Do you want to check out what this IP address is?
      Easy! Head to your terminal and do the following:
      $ host yahoo.com
      yahoo.com has address 98.138.219.231
      yahoo.com has address 98.137.246.8
      yahoo.com has address 98.138.219.232
      yahoo.com has address 72.30.35.9
      yahoo.com has address 98.137.246.7
      yahoo.com has address 72.30.35.10
      yahoo.com has IPv6 address 2001:4998:44:41d::3
      yahoo.com has IPv6 address 2001:4998:c:1023::5
      yahoo.com has IPv6 address 2001:4998:c:1023::4
      yahoo.com has IPv6 address 2001:4998:58:1836::10
      yahoo.com has IPv6 address 2001:4998:58:1836::11
      yahoo.com has IPv6 address 2001:4998:44:41d::4
      yahoo.com mail is handled by 1 mta5.am0.yahoodns.net.
      yahoo.com mail is handled by 1 mta6.am0.yahoodns.net.
      yahoo.com mail is handled by 1 mta7.am0.yahoodns.net.
      As you can see, the DNS will translate yahoo.com to any of the addresses above.
      The IP address alone will allow the HTTP message to arrive at the right machine, but you still need the port number in order for the HTTP request to arrive exactly at the web server.
      In other words, the web server is a regular network application that is listening on a specific port.
      And the http request MUST be addressed to that port.
      So where is the port number when you type www.yahoo.com?
      By default, the port number is 80 for http and 443 for https, so even though you haven’t explicitly specified the port number, it is still there.
      And if the web server is listening on a non-default port number (neither 80 nor 443), you must explicitly specify the port number like this:

      By now you should have all the necessary information to create an http web server in Python.
      So without further ado, let’s get started.

      Create a simple HTML file

      Here is what we want to do.
      We want to create a simple http server that serves a static html web page.
      Let’s create our html page.
      <html>
          <head>
              <title>Python is awesome!</title>
          </head>
          <body>
              <h1>Afternerd</h1>
              <p>Congratulations! The HTTP Server is working!</p>
          </body>
      </html>
      Now go ahead and save this file as index.html
      With the web page that we want to serve out of the way, the next step is to create a web server that will serve this html page.

      Create an HTTP web server

      In order to create a web server in Python 3, you will need to import two modules: http.server and socketserver

      Notice that in Python 2, there was a module named SimpleHTTPServer. This module has been merged into http.server in Python 3
      Let’s take a look at the code to create an http server
      import http.server
      import socketserver
      
      PORT = 8080
      Handler = http.server.SimpleHTTPRequestHandler
      
      with socketserver.TCPServer(("", PORT), Handler) as httpd:
          print("serving at port", PORT)
          httpd.serve_forever()
      Just like that we have a functional http server.
      Now let’s dissect this code line-by-line.
      First, as I mentioned earlier, a web server is a process that listens to incoming requests on specific TCP address.
      And as you know by now a TCP address is identified by an ip address and a port number.
      Second, a web server also needs to be told how to handle incoming requests.
      These incoming requests are handled by special handlers. You can think of a web server as a dispatcher, a request comes in, the http server inspects the request and dispatches it to a designated handler.
      Of course these handlers can do anything you desire.
      But what do you think the most basic handler is?
      Well, that would be a handler that just serves a static file.
      In other words, when I go to yahoo.com, the web server at the other end sends back a static html file.
      This is in fact what we are exactly trying to do.
      And that, my friend, is what the http.server.SimpleHTTPRequestHandler is: a simple HTTP request handler that serves files from the current directory and any of its subdirectories.
      Now let’s talk about the socketserver.TCPServer class.
      An instance of TCPServer describes a server that uses the TCP protocol to send and receive messages (http is an application layer protocol on top of TCP).
      To instantiate a TCP Server, we need two things:
      1- The TCP address (IP address and a port number)
      2- The handler
      socketserver.TCPServer(("", PORT), Handler)
      As you can see, the TCP address is passed as a tuple of (ip address, port number)
      Passing an empty string as the ip address means that the server will be listening on any network interface (all available IP addresses).
      And since PORT stores the value of 8080, then the server will be listening on incoming requests on that port.
      For the handler, we are passing the simple handler that we talked about earlier.
      Handler = http.server.SimpleHTTPRequestHandler
      Well, how about serve_forever?
      serve_forever is a method on the TCPServer instance that starts the server and begins listening and responding to incoming requests.
      Cool, let’s save this file as server.py in the same directory as index.html because by default the SimpleHTTPRequestHandler will look for a file named index.html in the current directory.
      In that directory, start the web server:
      $ python server.py
      serving at port 8080
      By doing that, you now have an HTTP server that is listening on any interface at port 8080 waiting for incoming http requests.
      It’s time now for the fun stuff!
      Open your browser and type localhost:8080 in the address bar.
      Awesome! Looks like everything is working fine.
      But hey what is localhost?
      localhost is a host name that means this computer. It is used to access the network services that are running on the host via the loopback network interface.
      And since the web server is listening on any interface, it is also listening on the loopback interface.
      You want to know what IP address corresponds to localhost?
      You got it.
      $ host localhost
      localhost has address 127.0.0.1
      localhost has IPv6 address ::1
      Host localhost not found: 3(NXDOMAIN)
      In fact you can totally replace localhost with 127.0.0.1 in your browser and you would still get the same result.
      Try it out 🙂

      One Final Word

      You can actually start a web server with python without even having to write any scripts.
      Just go to your terminal and do the following (but make sure you are on python 3)
      python -m http.server 8080
      By default, this server will be listening on all interfaces and on port 8080.
      If you want to listen to a specific interface, do the following:
      python -m http.server 8080 --bind 127.0.0.1
      Also starting from Python 3.7, you can use the –directory flag to serve files from a directory that is not necessarily the current directory.
      So the question now is, why would you ever need to write a script when you can just invoke the server easily from the terminal?
      Well, remember that you are using the SimpleHTTPRequestHandler. If you want to create your custom handlers (which you will probably want to do) then you won’t be able to do that from the terminal.

      Learning Python?

      If you are a beginner, then I highly recommend this book.
      No longer a beginner?

      Python Lambdas Explained (With Examples)

      Python Lambdas Explained (With Examples) View Larger Image In this article, I will teach you exactly what a python lambda is. ...