Do-it-yourself Python framework: 2. Start from web.py

It’s impossible to use the framework with bare hands without looking at some references. Flask is relatively heavy. Since it’s teaching, just draw a simple wheel according to web.py. Why choose web.py? Simple! The core part has very little code and is easy to understand. Author of web.py....

simple example

import web

urls = ('/(.*)', 'hello')
app = web.application(urls, globals())

class hello:
    def GET(self, name):
        if not name:
            name = 'world'
        return 'Hello, ' + name + '!'
        
if __name__ == '__main__':
    app.run()
  1. Simplified processing rules, all urls are handed over to the hello class for processing.
  2. Depending on the type of request, different methods are called. Only the GET method is implemented here, and web.py requires the method to be in uppercase.

After reading this code, you must have a bunch of questions:

  1. Where is the server?
  2. What about the legendary WSGI?
  3. How is the url matched?
  4. How is the string hello related to the hello class?
  5. How is the parameter name of GET parsed?

Preparation

Put these questions aside first, and then review the relevant knowledge of Python. Here we don't talk about advanced concepts such as metaprogramming, but discuss specific scenarios one by one. This is not a theoretical classroom, but to teach you how to solve practical engineering problems.

Functions are first class citizens

How do you understand this? As an object-oriented language, everything in Python is an object, and so are functions, and all beings are equal. But for C, C++, Java, etc., it is not so simple. If you pass functions as parameters, you have to come up with function pointers, functors, bindings, and other tricks.

def log(fn, *args, **kws):
    print('run ' + fn.__name__)
    fn(*args, **kws)
    
def fn(a, b, *args, **kws):
    print(a, b)
    print(args)
    print(kws)
    
print(type(fn))

log(fn, 1, 2, 100, 200, x=1000, y=2000)

To explain, *args represents the variable parameter of the array type, and **kws represents the variable parameter of the dictionary type. Python has a very convenient function, use type to view types, dir to view attributes and methods (don't panic if there is no document). We can see that the type of fn is <class 'function'>, where fn is passed in as a parameter of the log function.

<class 'function'>
run fn
1 2
(100, 200)
{'x': 1000, 'y': 2000}

Functions can be used not only as parameters, but also as return values ​​of functions. Try the following code:

def log(fn):
    def _log(*args, **kws):
        print('run ' + fn.__name__)
        return fn(*args, **kws)
        
    return _log
    
def add(a, b):
    return a + b
    
fn = log(add)
print(fn(1, 2))

A new knowledge point " closure " is also involved here! The log function returns the _log function, and at the same time solidifies the variable fn used in the _log function into the incoming function add. The concept of closure is very confusing, and I was confused for a long time when I was a beginner. To put it simply, the log has a variable. When the internal function is returned, if the internal function uses this variable, it will be packaged and taken away. Will it be easier to understand if it is replaced by the name " package "? It is not difficult to understand the concept of this decorator, and I will not expand it in detail here, because it will not be used in the code. Those who are interested can go to the online tutorial by themselves .

Dynamically add attributes

After Python creates a class, it can also dynamically add attributes to a class, and can also easily determine whether a class has a certain attribute.

class Test:
    pass
    
t = Test()
setattr(t, 'x', 100)
print(t.x)
y = getattr(t, 'y', 200)
print(y)

The attribute x is dynamically added to the instance t. If you directly access tx before adding, an error will be reported. Use getattr to get the value of an attribute. If the attribute does not exist, we provide a default value here.

create class by name

import sys

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def info(self):
        print('{0}: {1}'.format(self.name, self.age))
        
mmod = sys.modules['__main__']
SClass =getattr(mmod, 'Student')
s1 = SClass('tom', 20)
s1.info()

You can query whether it exists in a certain class according to the name. If you are not sure about a certain module, you can use hasattr to check. After finding this class, use SClass(...) to create an instance object.

Create a type dynamically

This one is a bit high-end, but not too difficult to understand. It is easier to understand step by step. We already know before the type function that we can check what type an object is, because the return value of the type function is the type of the object. We can change the code above to see what the result is.

import sys

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def info(self):
        print('{0}: {1}'.format(self.name, self.age))
        
s1 = Student('Tom', 20)
SClass = type(s1)
s2 = SClass('Jerry', 18)
s2.info()

Let's expand a bit more, the full type function accepts the following parameters:

  • name: the name of the class
  • bases: a tuple of base classes (the so-called tuple is a read-only list)
  • dict: Dictionary, namespace variables defined within the class.

No nonsense, the following code speaks. We define two base classes of dog and wolf, then dynamically create a husky class, and add the method of "demolition".

class Dog:
    pass
    
class Wolf:
    pass

def __init__(self, name):
    self.name = name
    
def chaijia(self):
    print(self.name + ' can chaijia!')
    
Husky = type('Husky', (Dog, Wolf), {'__init__': __init__, 'chaijia': chaijia})
husky = Husky('Wangwang')
husky.chaijia()

'''正常人的写法
class Husky(Dog, Wolf):
    def __init__(self, name):
        self.name = name
        
    def chaijia(self):
        print(self.name + ' can chaijia!')
        
husky = Husky('Wangwang')
husky.chaijia()
'''

Well, the preparatory knowledge is almost finished. What specific problems are encountered later will be expanded in detail. The next one is about to start a little bit.

Guess you like

Origin blog.csdn.net/panda_lin/article/details/121638946