-
-
Save ZoomQuiet/40f14760d5e7378ec380e3468e30d71d to your computer and use it in GitHub Desktop.
How to NEVER use lambdas - Python 3 edition
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
########################################################### | |
# How to NEVER use lambdas. An inneficient and yet educa- # | |
# tonal [sic] guide to the proper misuse of the lambda # | |
# construct in Python 3.x. [DO NOT USE ANY OF THIS EVER] # | |
# original by (and apologies to): e000 (13/6/11) # | |
# now in Python 3 courtesy of: khuxkm (17/9/20) # | |
########################################################### | |
## Part 1. Basic LAMBDA Introduction ## | |
# If you're reading this, you've probably already read e000's | |
# original, but in case you didn't read that one back when it | |
# was big, I should explain what lambdas are. As per e000: | |
# (quote) | |
# Lambdas are pretty much anonymous "one line" functions | |
# that are able to be constructed at runtime. Typical usage | |
# would be to plug it into `filter()` or `map()`, but that's | |
# boring. Let's start with the most basic of basic examples. | |
# (endquote) | |
def pow(x, power): | |
return x**power | |
# Simple enough, just a function that raises `x` to the `power` | |
# power. Now let's do it in lambda form: | |
pow = lambda x, power: x**power | |
# Easy. | |
## Part 2. Scoping within Lambdas ## | |
# Again, this part should be familiar to you if you read the | |
# original by e000. Nothing changed in Python 3, so I'll just | |
# quote the explanation here: (quote) | |
# Let's try something a bit more complicated. A random | |
# string or password generator? Sure. | |
import random, string | |
characters = string.digits + string.letters | |
def randomPasswordGenerator(length): | |
return ''.join(random.choice(characters) for i in range(length)) | |
# >>> randomPasswordGenerator(8) | |
# 'bDpHVxiO' | |
# Haah! That was cake! Now in this terrible tutorial, we're going to | |
# prohibit the use of defining ANYTHING outside of the lambda function, | |
# including any kind of variable, or import. So, how are we going to get | |
# `random` and `string`. Well the answer is obvious, we're going to make | |
# a lambda inside of a lambda inside of a lambda. We're also going to use | |
# a bit of `__import__` trickery. | |
# (endquote) | |
# The import trickery remains the same. Like I said, nothing really | |
# changed in Python 3 to break this example. As such, I even copied the | |
# source directly from donotuse.py (changing `xrange` to `range` as the | |
# former no longer exists). | |
randomPasswordGenerator = \ | |
(lambda random, string: # level 1 | |
(lambda characters: # level 2 | |
lambda length: ''.join(random.choice(characters) for i in range(length)) # level 3 | |
)(string.digits + string.letters) # level 2 args | |
)( | |
__import__('random'), # level 1 args | |
__import__('string') | |
) | |
# That's... unpythonic, disgusting, an abomination, and some might even | |
# call it ungodly. Why would anyone do that to themselves? | |
# One word: masochists. | |
## Part 3. Giving lambdas function names ## | |
# This is the first semi-new part. I'll quote e000 until there's new info. | |
# (quote) | |
# In a world where absurdity peaks, and somehow we NEED a | |
# function name, for what ever reason. Here's how to do it. | |
# THIS IS NOT FOR THE WEAK HEARTED. | |
# First, let's start with some regular code. | |
def myFunc(a, b): | |
return a + b | |
# >>> myFunc | |
# <function myFunc at 0x...> | |
myLambda = lambda a, b: a + b | |
# >>> myLambda | |
# <function <lambda> at 0x...> | |
# Uh'oh! How are we going to give this function a name? | |
# (endquote) | |
# In Python 2, we could use `new.function`. But in Python 3, `new` was | |
# replaced with `types`. Somehow, the new way to do it is even worse. | |
myFunc = (lambda types: | |
types.FunctionType((lambda a, b: a + b).__code__.replace(co_name="myFunc"),{},"myFunc") | |
)(__import__("types")) | |
# >>> myFunc | |
# <function myFunc at 0x...> | |
# In the immortal words of e000, "LOL! It works! Isn't that disgusting?" | |
## Part 4. A class? In my lambda? It's more likely than you may think. ## | |
# Let's start with a simple class. I'll write my own example this time. How | |
# about a simple namespace? | |
class Namespace: | |
def __init__(self,**kwargs): | |
self.__dict__.update(kwargs) | |
def __repr__(self): | |
keys = sorted(self.__dict__) | |
items = ("{}={!r}".format(k,self.__dict__[k]) for k in keys) | |
return "{}({})".format(type(self).__name__,", ".join(items)) | |
def __eq__(self,other): | |
return other.__dict__==self.__dict__ | |
# Yes, I know that's basically just types.SimpleNamespace, but shush. Let's | |
# lambda-ify it. Instead of `new.classobj`, we have `types.new_class`. | |
Namespace = (lambda types: | |
types.new_class("Namespace",(),exec_body=(lambda ns: ns.update( | |
dict( | |
__init__=(lambda self,**kwargs: self.__dict__.update(kwargs)), | |
__repr__=(lambda self: "{}({})".format(type(self).__name__,", ".join("{}={!r}".format(k,self.__dict__[k]) for k in sorted(self.__dict__)))), | |
__eq__=(lambda self, other: self.__dict__==other.__dict__) | |
) | |
))) | |
)(__import__("types")) | |
# >>> Namespace(x=3,s="Hello world!") | |
# Namespace(s='Hello world!', x=3) | |
# Holy mother of pearl, that is an abomination. | |
## Part 5. Flask + Lambdas = Even More of An Abomination ## | |
# This is as far as I'll go (mainly because I don't know how to Twisted). | |
# If you want to go even deeper, use the dark arts I've already taught you | |
# to convert Parts 6a and 6b into Python 3. | |
from flask import Flask | |
app = Flask(__name__) | |
@app.route('/') | |
def index(): | |
return "Hello, world!" | |
app.run() | |
# And that becomes... | |
(lambda flask: | |
(lambda app: | |
(app, | |
app.route('/')(lambda: 'Hello, world!') | |
)[0] | |
)(flask.Flask(__name__)).run() | |
)(__import__("flask")) | |
# What a disaster. | |
## Part 5b. I Lied, This Is Worse ## | |
# No comment. | |
from flask import Flask, redirect | |
shortnames = {"google":"https://google.com/","khuxkm":"https://khuxkm.tilde.team","*":"https://example.com"} | |
app = Flask(__name__) | |
@app.route('/') | |
def index(): | |
return redirect(shortnames.get("default","https://example.com"),code=307) | |
@app.route('/<path:short>') | |
def route(short): | |
return redirect(shortnames.get(short,shortnames.get("default","https://example.com")),code=307) | |
app.run() | |
# Pulling out all of the stops here... | |
(lambda flask, flaskviews, types, shortnames: | |
(lambda lmb2view: | |
(lambda app, index, route: | |
(app, | |
app.route("/")(index), | |
app.route("/<path:short>")(route) | |
)[0] | |
)(flask.Flask(__name__), | |
lmb2view(lambda s: flask.redirect(shortnames.get("default","https://example.com"),code=307),"index"), | |
lmb2view(lambda s,short: flask.redirect(shortnames.get(short,shortnames.get("default","https://example.com")),code=307),"route")).run() | |
)(lambda lmb,name: types.new_class(name,(flaskviews.views.View,),{},(lambda ns: ns.update(dict(dispatch_request=lmb)))).as_view(name)) | |
)(__import__("flask"),__import__("flask.views"),__import__("types"), | |
{ | |
"google":"https://google.com/", | |
"khuxkm":"https://khuxkm.tilde.team", | |
"*":"https://example.com" | |
}) | |
# What? Just... what? It's so goddamn big it barely fits on my 151-column monitor, it breaks all | |
# sorts of Zen, and I should probably be executed for crimes against humanity, but it's a URL | |
# shortener implemented entirely in lambdas. | |
# You ever write completely morally sound code that still leaves you feeling dirty afterwards? | |
# Me too. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment