Write a simple Web framework with Python [2]

Five, refactoring

Although the above code works, there are a lot of problems with coding style and flexibility, which is being reconstructed step by step.

1, regular matching URL

Eliminate URL hard code and increase the flexibility of URL scheduling:

Python

51#! /usr/bin/env Python!

# -*- coding: UTF-8 -*-

“” “application.py””””

Importre########## modification point

Classmy_app:

(urls=

(“/”, “index”),

(“/hello/ (. *)”, “hello”),

##########) change point

Def__init__ (self, environ, start_response):

Self.environ=environ

Self.start=start_response

Def__iter__ (self): ########## change point

Path=self.environ[‘PATH_INFO’]

Method=self.environ[‘REQUEST_METHOD’]

Forpattern, nameinself.urls:

M=re.match (‘^’+pattern+’$’, path)

Ifm:

Pass the matched groups as arguments # to the function

Args=m.groups ()

Funcname=method.upper () +’_’+name

Ifhasattr (self, funcname):

Func=getattr (self, funcname)

Returnfunc (*args)

Returnself.notfound ()

DefGET_index (self):

Status=’200 OK’

Response_headers=[(‘Content-type’,’text/plain’)]

Self.start (status, response_headers)

Yield “Welcome! /n!””

DefGET_hello (self, name): ########## change point

Status=’200 OK’

Response_headers=[(‘Content-type’,’text/plain’)]

Self.start (status, response_headers)

Yield “Hello%s, /n”%name

Defnotfound (self):

Status=’404 Not Found’

Response_headers=[(‘Content-type’,’text/plain’)]

Self.start (status, response_headers)

Yield “Not Found/n””

2, DRY

Eliminate duplicate code in the GET_* method and allow them to return strings:

Python

61#! /usr/bin/env Python!

# -*- coding: UTF-8 -*-

“” “application.py””””

Importre

Classmy_app:

(urls=

(“/”, “index”),

(“/hello/ (. *)”, “hello”),

)

Def__init__ (self, environ, start_response): ########## change point

Self.environ=environ

Self.start=start_response

Self.status=’200 OK’

Self._headers=[]

Def__iter__ (self): ########## change point

Result=self.delegate ()

Self.start (self.status, self._headers)

# will return the value of result (string or string is converted to iterative object list)

Ifisinstance (result, basestring):

Returniter ([result])

Else:

Returniter (result)

Defdelegate (self): ########## change point

Path=self.environ[‘PATH_INFO’]

Method=self.environ[‘REQUEST_METHOD’]

Forpattern, nameinself.urls:

M=re.match (‘^’+pattern+’$’, path)

Ifm:

Pass the matched groups as arguments # to the function

Args=m.groups ()

Funcname=method.upper () +’_’+name

Ifhasattr (self, funcname):

Func=getattr (self, funcname)

Returnfunc (*args)

Returnself.notfound ()

Defheader (self, name, value): ########## change point

Self._headers.append ((name, value))

DefGET_index (self): ########## change point

Self.header (‘Content-type’,’text/plain’)

Return “Welcome! /n!””

DefGET_hello (self, name): ########## change point

Self.header (‘Content-type’,’text/plain’)

Return “Hello%s, /n”%name

Defnotfound (self): ########## change point

Self.status=’404 Not Found’

Self.header (‘Content-type’,’text/plain’)

Return “Not Found/n””

3, abstract out the framework

In order to abstract class my_app into an independent framework, the following modifications are required:

Peel out specific processing details: the URLs configuration and the GET_* method (instead of implementing the corresponding GET method in multiple classes)

Implement method header as a class method (classmethod) to facilitate external invocation as a function function

Use the instance with the __call__ method to implement the application

The modified application.py (final version):

Python

54#! /usr/bin/env Python!

# -*- coding: UTF-8 -*-

“” “application.py””””

Importre

Classmy_app:

“” “my, simple, web, framework.””””

Headers=[]

Def__init__ (self, urls= (), fvars={}):

Self._urls=urls

Self._fvars=fvars

Def__call__ (self, environ, start_response):

Self._status=’200 OK’# default state OK

Delself.headers[:]# empty last headers

Result=self._delegate (environ)

Start_response (self._status, self.headers)

# will return the value of result (string or string is converted to iterative object list)

Ifisinstance (result, basestring):

Returniter ([result])

Else:

Returniter (result)

Def_delegate (self, environ):

Path=environ[‘PATH_INFO’]

Method=environ[‘REQUEST_METHOD’]

Forpattern, nameinself._urls:

M=re.match (‘^’+pattern+’$’, path)

Ifm:

Pass the matched groups as arguments # to the function

Args=m.groups ()

(funcname=method.upper) # method name (such as GET, POST)

Klass=self._fvars.get (name) # according to the string class object name lookup

Ifhasattr (Klass, funcname):

Func=getattr (Klass, funcname)

Returnfunc (Klass (), *args)

Returnself._notfound ()

Def_notfound (self):

Self._status=’404 Not Found’

Self.header (‘Content-type’,’text/plain’)

Return “Not Found/n””

@classmethod

Defheader (CLS, name, value):

Cls.headers.append ((name, value))

Corresponds to the modified code.py (final version):

Python

33#! /usr/bin/env Python!

# -*- coding: UTF-8 -*-

“” “code.py””””

Fromapplicationimportmy_app

(urls=

(“/”, “index”),

(“/hello/ (. *)”, “hello”),

)

Wsgiapp=my_app (URLs, globals ())

Classindex:

DefGET (self):

My_app.header (‘Content-type’,’text/plain’)

Return “Welcome! /n!””

Classhello:

DefGET (self, name):

My_app.header (‘Content-type’,’text/plain’)

Return “Hello%s, /n”%name

If__name__==’__main__’:

Fromwsgiref.simple_serverimportmake_server

Httpd=make_server (‘, 8086, wsgiapp)

Sa=httpd.socket.getsockname ()

Print’http://{0}: {1}/’.format (*sa)

Respond to requests until process is # killed

Httpd.serve_forever ()

Of course, you can also configure more URL mappings in code.py and implement the corresponding classes to respond to requests. I have built a python learning exchange group, in the group, we help each other, mutual care, mutual sharing of content, this problem is more and more people who help you, 301, is the group number is 056, then 051, so you can find the aggregation of God, if you just want to help you. Not willing to share or help others, please don’t be added, you will tell others this is a share. If you have any trouble with it, please give me a favor. Thank you