python-split() 在 __init__ 中不起作用

标签 python split wsgi

我正在编写代码来使用 wsgi 提供 html 文件。当我编写一个简单的函数时,我没有收到类似的错误:

from wsgiref.simple_server import make_server
import os
   ...
   ...
def app(environ, start_response):
    path_info = environ["PATH_INFO"]
    resource = path_info.split("/")[1] #I get no error here the split works totally fine.

现在,当我尝试将代码放入类中时,出现错误 NoneType has no attribute split。
也许environ__init__没有被初始化,这就是为什么它 split 不返回任何内容。以下是我的类(class)Candy所在的文件居住地:
import os
class Candy:
    def __init__(self):
            #self.environ = environ
            #self.start = start_response
            self.status = "200 OK"
            self.headers = []

    def __call__(self , environ , start_response):
        self.environ = environ
        self.start = start_response

    #headers = []
    def content_type(path):
        if path.endswith(".css"):
            return "text/css"
        else:
            return "text/html"


    def app(self):
        path_info = self.environ["PATH_INFO"]
        resource = path_info.split("/")[1]

        #headers = []
        self.headers.append(("Content-Type", content_type(resource)))

        if not resource:
            resource = "login.html"
        resp_file = os.path.join("static", resource)

        try:
            with open(resp_file, "r") as f:
                resp_file = f.read()
        except Exception:
            self.start("404 Not Found", self.headers)
            return ["404 Not Found"]

        self.start("200 0K", self.headers)
        return [resp_file]

以下是server.py我调用 make_server 的文件:
from wsgiref.simple_server import make_server
from candy import Candy
#from app import candy_request

candy_class = Candy()

httpd = make_server('localhost', 8000, candy_class.app)
print "Serving HTTP on port 8000..."

# Respond to requests until process is killed
httpd.serve_forever()

# Alternative: serve one request, then exit
#httpd.handle_request()

有什么帮助吗?如何对这个错误进行排序,我的假设是否正确?

最佳答案

为了解释你在这里做错了什么,让我们从简单的概念开始——什么是 WSGI 应用程序。

WSGI 应用程序只是一个接收请求环境的可调用对象,以及一个启动响应的回调函数(将状态行和 header 发送回用户)。然后,这个可调用对象必须返回一个或多个构成响应主体的字符串。

以最简单的形式,你有工作它只是

def app(environ, start_response):
    start_response("200 OK", [("Content-Type", "text/plain")])
    return "hello, world"

make_server('localhost', 8000, app).serve_forever()

每当有请求时,app函数被调用,它启动响应并返回一个字符串(或者它可以返回多个字符串的迭代,例如 ["hello, ", "world"] )

现在,如果你想让它成为一个类,它的工作方式是这样的:
 class MyApp(object):
     def __init__(self):
         pass

     def __call__(self, environ, start_response):
         start_response("200 OK", [("Content-Type", "text/plain")])
         return "something"

 app = MyApp()
 make_server("localhost", 8000, app).serve_forever()

在这种情况下,可调用对象是 app ,它实际上是 __call__ Caddy的方法类实例。

当请求到来时,app.__call__被调用( __call__ 是将类实例变成可调用的魔法方法),否则它的工作方式与 app 完全相同第一个例子中的函数。除了你有一个类实例(用 self ),所以你可以在 __init__ 中做一些预配置方法。在 __init__ 中没有做任何事情这毫无用处。例如,一个更现实的例子是:
 class MyApp(object):
     def __init__(self):
         self.favorite_color = "blue"

     def __call__(self, environ, start_response):
         start_response("200 OK", [("Content-Type", "text/plain")])
         return "my favorite color is {}".format(self.favorite_color)
 ...

然后,还有一件事。有时你想要一个流响应,随着时间的推移生成。也许它很大,或者可能需要一段时间。这就是为什么 WSGI 应用程序可以返回一个可迭代的,而不仅仅是一个字符串。
def app(environ, start_response):
    start_response("200 OK", [("Content-Type", "text/plain")]))
    yield "This was a triumph\n"
    time.sleep(1)
    yield "I'm making a note here\n"
    time.sleep(1)
    yield "HUGE SUCCESS\n"

make_server("localhost", 8000, app).serve_forever()

此函数返回一个生成器,该生成器逐段返回文本。虽然您的浏览器可能并不总是这样显示,但请尝试运行 curl http://localhost:8000/ .

现在,与类相同的是:
class MyApp(object):
    def __init__(self, environ, start_response):
        self.environ = environ
        self.start = start_response

    def __iter__(self):
        self.start("200 OK", [("Content-Type", "text/plain")]))
        yield "This was a triumph\n"
        time.sleep(1)
        yield "I'm making a note here\n"
        time.sleep(1)
        yield "HUGE SUCCESS\n"

make_server("localhost", 8000, MyApp).serve_forever()

在这里,您通过MyApp (类)作为可调用的应用程序 - 它就是。当请求到来时,它被调用,就像有人写过 MyApp(environ, start_response)某处,所以 __init__启动并为此特定请求创建一个实例。然后,随着实例的迭代,__iter__开始产生响应。完成后,实例将被丢弃。

基本上就是这样。这里的类只是保存数据的便利闭包。如果您不需要它们,请不要使用类,使用普通函数 - 平面比嵌套好。

现在,关于你的代码。

您的代码用于可调用的是 Candy().app .这不起作用,因为它甚至没有接收 environstart_response它会通过。它可能会失败并显示 500 错误,比如 app() takes 1 positional arguments but 3 were given .

我假设您的问题中的代码在您获得 NoneType has no attribute split 后被修改问题,并且您已将某些内容传递给 __init__创建时 candy_instance = Candy()当您的 __init__仍然有 2 个参数(3 个与 self )。甚至不确定它到底是什么——它应该早点失败。

基本上,您将错误的对象传递给了 make_server你的类(class)混合了两种不同的想法。

我建议检查我上面的例子(并阅读 PEP-333),确定你真正需要什么,并构建你的 Candy那样的课。
  • 如果您只需要在每个请求上返回一些内容,并且您没有持久状态 - 您根本不需要类。
  • 如果你需要一个持久状态(配置,或者,一个数据库连接) - 使用一个类实例,用 __call__方法,并使之__call__返回响应。
  • 如果您需要分块响应,请使用生成器函数或带有 __iter__ 的类方法。或者一个类(class) __call__那个yields (就像一个函数)。

  • 希望这可以帮助。

    关于python-split() 在 __init__ 中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45782615/

    相关文章:

    javascript - 如何按特殊字符拆分数组元素

    Python:将查询字符串分解为关联数组不起作用

    python - 具有资源句柄的 TensorFlow 自定义 C++ 操作

    python - 如何在 tkinter 中使用图像作为背景?

    python - 如何将字节对象转换为 python 中的十进制或二进制表示形式?

    python - 将列表字典拆分为单个列表

    c++ - 将 C++ 类实例暴露给 python 嵌入式解释器

    r - 如何通过R中连续的相同字母拆分字符串

    python - Bokeh session 和文档轮询

    python - apache python 错误