python 项目生成requirements.txt等文件
pip install pipreqs
# 项目目录执行
pipreqs ./
python call 方法
Call self as a function
主要实现的是将类的对象当作函数直接调用
#
class type(object):
def __call__(self, *args, **kwargs): # real signature unknown
""" Call self as a function. """
pass
call示例
def __call__(self, environ, start_response):
self.proxied = False
script_name = environ.get('HTTP_X_SCRIPT_NAME', '')
if script_name:
self.proxied = True
environ['SCRIPT_NAME'] = script_name
path_info = environ.get('PATH_INFO', '')
if path_info and path_info.startswith(script_name):
environ['PATH_INFO'] = path_info[len(script_name):]
scheme = environ.get('HTTP_X_SCHEME', '')
if scheme:
environ['wsgi.url_scheme'] = scheme
servr = environ.get('HTTP_X_FORWARDED_HOST', '')
if servr:
environ['HTTP_HOST'] = servr
self.proxied = True
return self.app(environ, start_response)
Django、Tornado、Flask比较
使用flask好久,感觉flask还是好用些。
Django是Python 中最全能的 web 开发框架,走大而全的方向。它最出名的是其全自动化的管理后台:只需要使用起ORM,做简单的对象定义,它就能自动生成数据库结构、以及全功能的管理后台。不过Django提供的方便,也意味着Django内置的ORM跟框架内的其他模块耦合程度高,深度绑定了该框架,应用程序必须使用Django内置的ORM,否则就不能享受到框架内提供的种种基于其ORM的优秀特性。
Tornado全称Tornado Web Server,是一个用Python语言写成的Web服务器兼Web应用框架。Tornado走的是少而精的方向,注重的是性能优越,它最出名的是异步非阻塞的服务器方式。(Tornado框架和服务器一起组成一个WSGI的全栈替代品。单独在WSGI容器中使用tornado web框架或者tornaod http服务器,有一定的局限性,为了最大化的利用tornado的性能,推荐同时使用tornaod的web框架和HTTP服务器。)
Flask是一个使用 Python 编写的轻量级 Web 应用框架,也被称为 “microframework”,语法简单,部署很方便,整个框架自带了路径映射、模板引擎(Jinja2)、简单的数据库访问等web框架组件,支持WSGI协议(采用 Werkzeug)。Flask使用 BSD 授权。 Flask使用简单的核心,用 extension 增加其他功能,虽然没有默认使用的数据库、窗体验证工具,然而Flask保留了扩增的弹性,可以用Flask-extension加入ORM、窗体验证工具、文件上传、各种开放式身份验证技术这些功能。
从性能上看Tornado 比Django、Flask等主流 Web 服务器框架相比有着明显的区别:它是非阻塞式服务器,速度相当快。然而 Tornado 相比 Django 和Flask属于较为原始的框架,插件少,许多内容需要自己去处理。而Flask插件多,文档非常专业,有专门的公司团队维护,对于快速开发很有效率。由于WSGI协议的存在,可以结合 Tornado 的服务器异步特性、并发处理能力和Flask的文档和扩展能力为一体。虽然像Django,Flask框架都有自己实现的简单的WSGI服务器,但一般用于服务器调试,生产环境下建议用其他WSGI服务器,比如Nginx+uwsgi+Django方式。
参考
python-tornado简单使用
Python的web架构之Tornado+Flask
python 装饰器
装饰器能够在那个函数执行前或者执行后分别运行一些代码,使得可以再装饰器里面访问并修改原函数的参数以及返回值,以实现约束定义、调试程序、注册函数等目标。装饰器一般返回一个包装器(wrapper),而functools.wraps就是装饰包装器的装饰器。
自己创建一个装饰器
def a_new_decorator(a_func):
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
def a_function_requiring_decoration():
print("I am the function which needs some decoration to remove my foul smell")
a_function_requiring_decoration()
#outputs: "I am the function which needs some decoration to remove my foul smell"
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
#now a_function_requiring_decoration is wrapped by wrapTheFunction()
a_function_requiring_decoration()
#outputs:I am doing some boring work before executing a_func()
# I am the function which needs some decoration to remove my foul smell
# I am doing some boring work after executing a_func()
from functools import wraps
def a_new_decorator(a_func):
@wraps(a_func)
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
@a_new_decorator
def a_function_requiring_decoration():
"""Hey you! Decorate me!"""
print("I am the function which needs some decoration to "
"remove my foul smell")
a_function_requiring_decoration()
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
print(a_function_requiring_decoration.__name__)
输出结果为
I am doing some boring work before executing a_func()
I am the function which needs some decoration to remove my foul smell
I am doing some boring work after executing a_func()
a_function_requiring_decoration
python 修饰符@
修饰符@的作用是为现有函数增加额外的功能,常用于插入日志、性能测试、事务处理等等。
创建函数修饰符的规则:
(1)修饰符是一个函数
(2)修饰符取被修饰函数为参数
(3)修饰符返回一个新函数
(4)修饰符维护被维护函数的签名
修饰符@是一个函数
def log(func):
def wrapper():
print('log开始 ...')
func()
print('log结束 ...')
return wrapper
@log
def run_func():
print('run_func ..')
run_func()
#log开始 ...
#run_func ..
#log结束 ...
修饰符@维护被维护函数的签名
使用functools模块提供的修改函数属性的方法wraps
from functools import wraps
def log(func):
@wraps(func)
def wrapper():
print('log开始 ...')
func()
print('log结束 ...')
return wrapper
@log
def test1():
print('test1 ..')
def test2():
print('test2 ..')
print(test1.__name__)
print(test2.__name__)
#test1
#test2
被修饰函数带参数
from functools import wraps
def log(func):
@wraps(func)
def wrapper(*args,**kwargs):
print('log开始 ...',func.__name__)
ret = func(*args,**kwargs)
print('log结束 ...')
return ret
return wrapper
@log
def test1(s):
print('test1 ..', s)
return s
@log
def test2(s1, s2):
print('test2 ..', s1, s2)
return s1 + s2
test1('a')
test2('a','bc')
参考
python 打开文件
f = file(name[, mode[, buffering]])
入口参数: name 文件名
mode 选项,字符串
buffering 是否缓冲 (0=不缓冲,1=缓冲, >1的int数=缓冲区大小)
返回值 : 文件对象
mode 选项:
"r" 以读方式打开,只能读文件 , 如果文件不存在,会发生异常
"w" 以写方式打开,只能写文件, 如果文件不存在,创建该文件
如果文件已存在,先清空,再打开文件
"rb" 以二进制读方式打开,只能读文件 , 如果文件不存在,会发生异常
"wb" 以二进制写方式打开,只能写文件, 如果文件不存在,创建该文件
如果文件已存在,先清空,再打开文件
"rt" 以文本读方式打开,只能读文件 , 如果文件不存在,会发生异常
"wt" 以文本写方式打开,只能写文件, 如果文件不存在,创建该文件
如果文件已存在,先清空,再打开文件
"rb+" 以二进制读方式打开,可以读、写文件 , 如果文件不存在,会发生异常
"wb+" 以二进制写方式打开,可以读、写文件, 如果文件不存在,创建该文件
如果文件已存在,先清空,再打开文件
python3.8使用flask_wtf时产生的cannot import name 'url_encode'问题
werkzeug 版本过高,导致问题出现;安装werkzeug的低版本即可解决问题
pip install werkzeug==0.16.0
flask 渲染html
from flask import render_template
@app.route('/user/')
def user():
return render_template('user.html')
if __name__ == '__main__':
app.run(debug=True)
# user.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>这是用户中心</title>
<h1>这是用户中心! </h1>
</head>
<body>
</body>
</html>
python 3.7 async=True, get_object=False, no_input=False):
pip install pyspider
pyspider
➜ Containers Pyspider
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.8/bin/Pyspider", line 5, in <module>
from pyspider.run import main
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pyspider/run.py", line 231
async=True, get_object=False, no_input=False):
^
原因是python3.7中async已经变成了关键字。因此出现这个错误。
修改方式是手动替换一下
下面位置的async改为mark_async
/usr/local/lib/python3.7/site-packages/pyspider/run.py 的231行、245行(两个)、365行
/usr/local/lib/python3.7/site-packages/pyspider/webui/app.py 的95行
/usr/local/lib/python3.7/site-packages/pyspider/fetcher/tornado_fetcher.py 的81行、89行(两个)、95行、117行
~ pyspider
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.8/bin/pyspider", line 8, in <module>
sys.exit(main())
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pyspider/run.py", line 754, in main
cli()
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/click/core.py", line 829, in __call__
return self.main(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/click/core.py", line 782, in main
rv = self.invoke(ctx)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/click/core.py", line 1236, in invoke
return Command.invoke(self, ctx)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/click/decorators.py", line 21, in new_func
return f(get_current_context(), *args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pyspider/run.py", line 165, in cli
ctx.invoke(all)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/click/decorators.py", line 21, in new_func
return f(get_current_context(), *args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pyspider/run.py", line 467, in all
threads.append(run_in(ctx.invoke, phantomjs, **phantomjs_config))
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pyspider/libs/utils.py", line 68, in run_in_subprocess
thread.start()
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/multiprocessing/process.py", line 121, in start
self._popen = self._Popen(self)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/multiprocessing/context.py", line 224, in _Popen
return _default_context.get_context().Process._Popen(process_obj)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/multiprocessing/context.py", line 284, in _Popen
return Popen(process_obj)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/multiprocessing/popen_spawn_posix.py", line 32, in __init__
super().__init__(process_obj)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/multiprocessing/popen_fork.py", line 19, in __init__
self._launch(process_obj)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/multiprocessing/popen_spawn_posix.py", line 47, in _launch
reduction.dump(process_obj, fp)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/multiprocessing/reduction.py", line 60, in dump
ForkingPickler(file, protocol).dump(obj)
_pickle.PicklingError: Can't pickle <function cli at 0x7fe59a5735e0>: it's not the same object as pyspider.run.cli
解决方法:使用pipenv
参考
https://www.cnblogs.com/jiguanghover/p/11364513.html
python 多线程实现同步的四种方式
https://www.cnblogs.com/zhumengke/articles/10825242.html
Python raise
http://c.biancheng.net/view/2360.html
Python functools.partial
partial adj. 局部的;偏爱的;不公平的
Python 提供了一个 functools 的模块,该模块为高阶函数提供支持,partial 就是其中的一个函数
def add(x, y):
return x + y
add(3, y=2)
add(4, y=2)
add(5, y=2)
def plus(x, y=2):
return add(x, y)
plus(3)
plus(4)
plus(5)
from functools import partial
plus = partial(add, y=2)
partial 接收函数 add 作为参数,固定 add 的参数 y=2,并返回一个新的函数给 plus。简单而言,partial 函数的功能就是:把一个函数的某些参数给固定住,返回一个新的函数。
参考
端口转发
server{
listen 80;
server_name tomcat.shaochenfeng.com;
index index.php index.html index.htm;
location / {
proxy_pass http://127.0.0.1:8080; # 转发规则
proxy_set_header Host $proxy_host; # 修改转发请求头,让8080端口的应用可以受到真实的请求
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}