python- split() 在内部不起作用 __init__
python- split() doesn't work inside __init__
我正在编写代码以使用 wsgi.When 为 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.
现在,当我尝试将代码放入 class 时,出现错误 NoneType has no attribute split。
也许 __init__
里面的 environ
没有被初始化,这就是为什么它没有拆分 returns 的原因。以下是我的 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]
以下是我调用 make_server 的 server.py
文件:
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 应用程序只是一个接收请求环境的可调用函数,以及一个启动响应(发送状态行和 headers 返回给用户)的回调函数。然后,此可调用对象必须 return 一个或多个字符串,构成响应 body.
在最简单的形式中,你的工作只是
def app(environ, start_response):
start_response("200 OK", [("Content-Type", "text/plain")])
return "hello, world"
make_server('localhost', 8000, app).serve_forever()
每当一个请求到来时,app
函数被调用,它开始响应并且 return 是一个字符串(或者它可以 return 一个可迭代的多个字符串,例如 ["hello, ", "world"]
)
现在,如果您希望它成为 class,它的工作方式如下:
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
,它实际上是Caddy
class实例的__call__
方法。
当请求到来时,app.__call__
被调用(__call__
是将您的 class 实例变为可调用实例的神奇方法),否则它的工作方式与 app
第一个例子中的函数。除了你有一个 class 实例(带有 self
),所以你可以在 __init__
方法中做一些 pre-configuration。在 __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 应用程序可以 return 一个可迭代对象,而不仅仅是一个字符串。
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()
这个函数return是一个生成器,return是一段一段的文本。虽然你的浏览器可能并不总是这样显示,但是试试 运行 curl http://localhost:8000/
.
现在,与 classes 相同的是:
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
(class)作为可调用的应用程序传递 - 它是。当请求到来时它被调用,就像有人在某处写了 MyApp(environ, start_response)
,所以 __init__
启动并为此特定请求创建一个实例。然后,随着实例的迭代,__iter__
开始产生响应。完成后,实例将被丢弃。
基本上就是这样。 类 这里只是保存数据的便捷闭包。如果不需要它们,请不要使用 classes,使用普通函数 - flat 优于嵌套。
现在,关于您的代码。
您的代码用于可调用的是 Candy().app
。这不起作用,因为它甚至没有接收 environ
和 start_response
它将被传递。它可能会因 500 错误而失败,比如 app() takes 1 positional arguments but 3 were given
.
我假设你的问题中的代码在你遇到 NoneType has no attribute split
问题后被修改,并且你在创建 candy_instance = Candy()
时传递了一些东西给 __init__
当你的 __init__
仍然有 2 个参数(3 个带有 self
)。甚至不确定它到底是什么 - 它应该早点失败。
基本上,您将错误的 objects 传递给了 make_server
,而您的 class 是两种不同想法的混合体。
我建议检查我上面的示例(并阅读 PEP-333),确定您实际需要什么,并像那样构建您的 Candy
class。
如果您只需要 return 每个请求的东西,并且您没有持久状态 - 您根本不需要 class。
如果您需要持久状态(配置,或者可能是数据库连接)- 使用 class 实例,使用 __call__
方法,并使 __call__
return 响应。
如果您需要分块响应,请使用生成器函数,或使用 class 和 __iter__
方法。或者 class 和 __call__
那个 yields
(就像一个函数)。
希望这对您有所帮助。
我正在编写代码以使用 wsgi.When 为 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.
现在,当我尝试将代码放入 class 时,出现错误 NoneType has no attribute split。
也许 __init__
里面的 environ
没有被初始化,这就是为什么它没有拆分 returns 的原因。以下是我的 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]
以下是我调用 make_server 的 server.py
文件:
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 应用程序只是一个接收请求环境的可调用函数,以及一个启动响应(发送状态行和 headers 返回给用户)的回调函数。然后,此可调用对象必须 return 一个或多个字符串,构成响应 body.
在最简单的形式中,你的工作只是
def app(environ, start_response):
start_response("200 OK", [("Content-Type", "text/plain")])
return "hello, world"
make_server('localhost', 8000, app).serve_forever()
每当一个请求到来时,app
函数被调用,它开始响应并且 return 是一个字符串(或者它可以 return 一个可迭代的多个字符串,例如 ["hello, ", "world"]
)
现在,如果您希望它成为 class,它的工作方式如下:
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
,它实际上是Caddy
class实例的__call__
方法。
当请求到来时,app.__call__
被调用(__call__
是将您的 class 实例变为可调用实例的神奇方法),否则它的工作方式与 app
第一个例子中的函数。除了你有一个 class 实例(带有 self
),所以你可以在 __init__
方法中做一些 pre-configuration。在 __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 应用程序可以 return 一个可迭代对象,而不仅仅是一个字符串。
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()
这个函数return是一个生成器,return是一段一段的文本。虽然你的浏览器可能并不总是这样显示,但是试试 运行 curl http://localhost:8000/
.
现在,与 classes 相同的是:
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
(class)作为可调用的应用程序传递 - 它是。当请求到来时它被调用,就像有人在某处写了 MyApp(environ, start_response)
,所以 __init__
启动并为此特定请求创建一个实例。然后,随着实例的迭代,__iter__
开始产生响应。完成后,实例将被丢弃。
基本上就是这样。 类 这里只是保存数据的便捷闭包。如果不需要它们,请不要使用 classes,使用普通函数 - flat 优于嵌套。
现在,关于您的代码。
您的代码用于可调用的是 Candy().app
。这不起作用,因为它甚至没有接收 environ
和 start_response
它将被传递。它可能会因 500 错误而失败,比如 app() takes 1 positional arguments but 3 were given
.
我假设你的问题中的代码在你遇到 NoneType has no attribute split
问题后被修改,并且你在创建 candy_instance = Candy()
时传递了一些东西给 __init__
当你的 __init__
仍然有 2 个参数(3 个带有 self
)。甚至不确定它到底是什么 - 它应该早点失败。
基本上,您将错误的 objects 传递给了 make_server
,而您的 class 是两种不同想法的混合体。
我建议检查我上面的示例(并阅读 PEP-333),确定您实际需要什么,并像那样构建您的 Candy
class。
如果您只需要 return 每个请求的东西,并且您没有持久状态 - 您根本不需要 class。
如果您需要持久状态(配置,或者可能是数据库连接)- 使用 class 实例,使用
__call__
方法,并使__call__
return 响应。如果您需要分块响应,请使用生成器函数,或使用 class 和
__iter__
方法。或者 class 和__call__
那个yields
(就像一个函数)。
希望这对您有所帮助。