├── .gitignore ├── Django ├── 20171218090004887.png ├── unit1-Django.md ├── unit1-route.md ├── unit2-server-object.md ├── unit2-server-跨域请求.md ├── unit2-template.md ├── unit3-model-1.md ├── unit3-model-2-mysql.md ├── unit3-model-3-mysql增删改查进阶.md ├── unit3-model-4-表关系.md ├── unit4-middleware.md ├── uuid.md └── 图片上传.md ├── Flask ├── resfful api.md ├── unit0 ├── unit1-基础.md ├── unit2-router.md ├── unit3-server-obj-2.md ├── unit3-server-obj.md ├── unit4-template.md ├── unit5-mysql-SQLAlchemy.md └── unit5-mysql.md ├── mysql ├── unit1.md ├── unit2-数据查询.md ├── unit3-视图、事务、存储过程.md ├── unit4-数据库优化-0.md └── unit5-数据库优化-索引.md ├── python ├── 01-part1 │ ├── images │ │ ├── var.png │ │ └── 变量类型.jpg │ ├── python基础语法-全部.pdf │ ├── unit1-环境搭建.md │ ├── unit2-语法基础.md │ ├── unit3-queue.md │ ├── unit3-变量类型-Dictionary.md │ ├── unit3-变量类型-List.md │ ├── unit3-变量类型-Numbers.md │ ├── unit3-变量类型-Set.md │ ├── unit3-变量类型-String.md │ ├── unit3-变量类型-Tuple.md │ ├── unit3-变量类型.md │ ├── unit4-运算符.md │ ├── unit5-1-逻辑控制语句-if.md │ ├── unit5-2-逻辑控制语句-for.md │ ├── unit5-3-迭代器.md │ ├── unit6-函数.md │ ├── unit6-函数装饰器.md │ ├── unit6-函数装饰器高级.md │ ├── unit7-模块.md │ ├── unit7-模块高级.md │ ├── unit8-文件I:O.md │ ├── unit8-文件io-excel.md │ ├── unit9-OS.md │ └── unitX-内置模块.md └── 01-part2 │ ├── Untitled.ipynb │ ├── images │ ├── 修饰符.png │ ├── 元字符.png │ └── 量词.png │ ├── python高级-课件.pdf │ ├── unit1-面向对象.md │ ├── unit2-面向对象.md │ ├── unit3-异常处理.md │ ├── unit3-设计模式.md │ ├── unit4-正则表达式.md │ ├── unit5-多线程-1.md │ ├── unit5-多线程-2.md │ ├── unit5-多线程进阶.md │ ├── unit6-单元测试.md │ ├── unit6-单元测试源码.zip │ ├── unitx-1生成器-迭代器.md │ ├── unitx-2垃圾回收.md │ ├── 单元测试源码 │ ├── HTMLReport.html │ ├── HTMLTestRunner.py │ ├── calculate_func.py │ ├── test_calculate_func.py │ └── test_suite.py │ └── 对象关系图.jpg └── spider ├── 1-基础 ├── Xpath.md ├── unit0-网络基础-http.md ├── unit1-爬虫基本认知.md ├── unit2-1-案例-批量爬取淘宝数据.py ├── unit2-Urllib-base.md ├── unit2-Urllib-opener.md ├── unit3-Urllib-Requests.md ├── unit4_1-页面解析-XML.md ├── unit4_2-页面解析-CSS.md ├── unit4_3-页面解析-REGEX.md └── unit5-Selenium.md ├── 2-scrapy ├── unit1-scrapy.md ├── unit2-shell.md ├── unit3-item.md └── unit4-pipeline.md └── 3-NOSQL ├── mongoDB 用户.rtf ├── unit1-MongoDB-搭建环境.md ├── unit2-MongoDB-数据操作.md ├── unit3-mongoDB-python.md └── unit4-云服务器.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows: 2 | Thumbs.db 3 | ehthumbs.db 4 | Desktop.ini 5 | 6 | # Python: 7 | *.py[cod] 8 | *.so 9 | *.egg 10 | *.egg-info 11 | dist 12 | build 13 | 14 | # My configurations: 15 | db.ini 16 | deploy_key_rsa 17 | *.xml 18 | *.iml 19 | 20 | logs/* 21 | !.gitkeep 22 | node_modules/ 23 | bower_components/ 24 | tmp 25 | .DS_Store 26 | .idea 27 | 28 | .idea/ 29 | 30 | -------------------------------------------------------------------------------- /Django/20171218090004887.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhanforgit/python/2fc2d72bc7b08f3da8886d04150c7b918994ae28/Django/20171218090004887.png -------------------------------------------------------------------------------- /Django/unit1-Django.md: -------------------------------------------------------------------------------- 1 | # Django 2 | 1. 简介 3 | 4 | python下有许多款不同的 Web 框架。Django是重量级选手中最有代表性的一位。许多成功的网站和APP都基于Django。 5 | 6 | Django是一个开放源代码的Web应用框架,由Python写成。 7 | 8 | Django遵守BSD版权,初次发布于2005年7月, 并于2008年9月发布了第一个正式版本1.0 。 9 | 10 | [中文文档](https://docs.djangoproject.com/zh-hans/2.0/) 11 | 12 | 1. 安装 13 | 14 | 1. windows 15 | 16 | 17 | 下载 Django 压缩包,解压并和Python安装目录放在同一个根目录,进入 Django 目录,执行python setup.py install,然后开始安装,Django将要被安装到Python的Lib下site-packages。 18 | 19 | 配置环境变量: 20 | 将这几个目录添加到系统环境变量中: C:\Python33\Lib\site-packages\\..\django;C:\Python33\Scripts。 添加完成后就可以使用Django的django-admin.py命令新建工程了。 21 | 22 | 检查是否安装成功 23 | 输入以下命令进行检查: 24 | 25 | ``` 26 | >>> import django 27 | >>> django.get_version() 28 | ``` 29 | 或者 30 | 31 | ``` 32 | python3 -m django --version 33 | ``` 34 | 2. mac 35 | 36 | 下载安装包 37 | Django 下载地址:https://www.djangoproject.com/download/ 38 | 39 | 40 | ``` 41 | $ tar zxvf Django-1.x.y.tar.gz 42 | cd Django-1.x.y 43 | sudo python setup.py install 44 | ``` 45 | 46 | >如果在独立的env中,则也需要pip install django命令来安装。 47 | 48 | 3. 查看是否安装成功 49 | 50 | python -m django --version 51 | 52 | 2. 卸载 53 | 54 | 如果您以前使用过Django ,卸载就像从Python中删除目录 一样简单。要找到需要删除的目录,可以在shell提示符(而不是交互式Python提示符)下运行以下命令: 55 | 56 | 57 | python setup.py installdjangosite-packages 58 | 59 | 2. 创建项目 60 | 61 | 再进入我们的站点目录,创建 Django 项目: 62 | 63 | ``` 64 | $ django-admin startproject testdj 65 | # $ django-admin.py startproject testdj //老版本使用 66 | ``` 67 | **最新版的 Django 请使用 django-admin 命令** 68 | 启动服务: 69 | 70 | ``` 71 | cd testdj # 切换到我们创建的项目 72 | # python manage.py runserver 0.0.0.0:8000 73 | # python manage.py runserver 8080 74 | $ python manage.py runserver 75 | ``` 76 | 77 | >启动django后,不能访问,报400错误。 78 | 原因:没有开启允许访问 79 | 处理:编辑HelloWorld目录下setting.py ,把其中的 80 | ALLOWED_HOSTS=[]改成ALLOWED_HOSTS=['*'] ##* 表示任意地址。 81 | 82 | 3. 项目目录分析 83 | 84 | * HelloWorld: 项目的容器。 85 | * manage.py: 一个实用的命令行工具,可让你以各种方式与该 Django 项目进行交互。 86 | * HelloWorld/__init__.py: 一个空文件,告诉 Python 该目录是一个 Python 包。 87 | * HelloWorld/settings.py: **该 Django 项目的设置/配置。** 88 | 89 | ``` 90 | # 配置路由文件 91 | ROOT_URLCONF = 'HelloWorld.urls' 92 | 93 | TEMPLATES = [ 94 | { 95 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 96 | # 配置模板文件目录 97 | 'DIRS': [BASE_DIR + "/templates", ], 98 | 'APP_DIRS': True, 99 | 'OPTIONS': { 100 | 'context_processors': [ 101 | 'django.template.context_processors.debug', 102 | 'django.template.context_processors.request', 103 | 'django.contrib.auth.context_processors.auth', 104 | 'django.contrib.messages.context_processors.messages', 105 | ], 106 | }, 107 | }, 108 | ] 109 | 110 | ``` 111 | * HelloWorld/urls.py: 该 Django 项目的 URL 声明; 一份由 Django 驱动的网站"目录"。 112 | * HelloWorld/wsgi.py: 一个 WSGI 兼容的 Web 服务器的入口,以便运行你的项目。 113 | 5. 在项目目录中创建应用 114 | 115 | 要创建您的应用程序,请确保您位于相同的目录中manage.py 并键入此命令: 116 | 117 | ``` 118 | $ python manage.py startapp polls 119 | ``` 120 | 121 | >项目与应用程序 122 | 123 | >项目和应用程序有什么区别?应用程序是一种Web应用程序,它可以执行某些操作,例如Weblog系统,公共记录数据库或简单的轮询应用程序。项目是特定网站的配置和应用程序的集合。项目可以包含多个应用程序。一个应用程序可以在多个项目中。 124 | 125 | 为这个应用创建路由: 126 | 在该应用目录下新建urls.py文件 127 | 128 | ``` 129 | from django.urls import path 130 | 131 | from . import views 132 | 133 | urlpatterns = [ 134 | path('', views.index, name='index'), 135 | ] 136 | ``` 137 | 138 | 4. 配置模板文件和静态文件 139 | 140 | 2. 模版 141 | 142 | TEMPLATES = [ 143 | { 144 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 145 | 'DIRS': ['/templates/','position/templates/'], 146 | 147 | ___ 148 | 149 | TEMPLATE_DIRS = ( 150 | os.path.join(BASE_DIR,'templates'), 151 | ) 152 | 153 | 3. 静态文件 154 | 155 | STATICFILES_DIRS = ( 156 | os.path.join(BASE_DIR,'static'), 157 | ) 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /Django/unit1-route.md: -------------------------------------------------------------------------------- 1 | # 路由 2 | 1. 路由 3 | 4 | 1. 简单路由 5 | 6 | 1. 单一路由 7 | 8 | path('index/', views.index,name='index') 9 | 10 | **注意index/最后面的/不能省略** 11 | 12 | 13 | 14 | 1. 通过路由传参数 15 | 16 | path('getuser/', views.getuser,name='getuser') 17 | 18 | path('getuser/', views.getuser,name='getuser',{'id':12o}) 19 | views.py 20 | 21 | def getuser(request,id): 22 | return HttpResponse('HELLO WORLD--->'+str(id)) 23 | **建议复习函数** 24 | * 必备参数 25 | * 默认参数 26 | * 不定长参数 27 | * 关键字参数 28 | * 命名关键字参数 29 | 30 | 3. path(route, view, kwargs=None, name=None, Pattern=None) 31 | 32 | 1. route 33 | 34 | 模式不搜索GET和POST参数或域名。例如,在请求中https://www.example.com/myapp/,URLconf将查找 myapp/。在请求中https://www.example.com/myapp/?page=3,URLconf也将查找myapp/。 35 | 2. view 36 | 当Django找到一个匹配的模式时,它会以一个HttpRequest对象作为第一个参数以及路由中的任何“捕获”值作为关键字参数来调用指定的视图函数。 37 | 3. kwargs 38 | 39 | 任意关键字参数可以在字典中传递给目标视图。 40 | 4. name 41 | 42 | 命名您的URL可以让您从Django其他地方明确地引用它,特别是在模板中。这个强大的功能允许您在只触摸单个文件的情况下对项目的URL模式进行全局更改。 43 | 44 | 2. 基于正则的路由 45 | 46 | from django.conf.urls import url,include 47 | 48 | 路由以特定字符串开头 49 | 50 | urlpatterns = [ 51 | url(r'^getuser\w*/', views.getuser,name='getuser'), 52 | url(r'^index/(\d*)', views.index) 53 | ] 54 | 55 | 利用正则表达式传递参数 56 | 57 | #此时id的类型为str 58 | url(r'^getuser\w*/(?P\w*)', views.getuser,name='getuser') 59 | 60 | urls.py 61 | 62 | ``` 63 | from django.conf.urls import url 64 | from django.contrib import admin 65 | from . import view 66 | from . import personal 67 | 68 | urlpatterns = [ 69 | #匹配空路由相当于path(r'', view.hello), 70 | url(r'^$', view.hello), 71 | url(r'^person\w*$', personal.login) 72 | ] 73 | ``` 74 | 75 | 2. 路由重定向(同一模块中) 76 | 77 | 在路由中我们定义了name="xxx",那么在views.py函数中,我们可以通过reverse来获取路由;但是路由中如果有参数,则要传递参数 78 | 79 | 以下两个路由 80 | 81 | url(r'^getuser\w*/(?P\w*)', views.getuser,name='getuser'), 82 | url(r'^login\w*/(?P\w*)', views.login,name='login') 83 | 84 | 在views.login方法中获取getuser的路径,并实现跳转 85 | 86 | #路由名反向 87 | from django.urls import reverse 88 | 89 | #路由跳转 90 | from django.shortcuts import render,redirect 91 | 92 | uurl=reverse('getuser',args=(userid+'111',)) 93 | 94 | return redirect(uurl) 95 | 96 | 97 | 2. 导入其他应用路由文件(子模块子路由) 98 | 99 | 1. 新建子模块 100 | 101 | python manage.py startapp position 102 | 103 | 2. 修改配置文件 104 | 105 | INSTALLED_APPS = [ 106 | 'django.contrib.admin', 107 | 'django.contrib.auth', 108 | 'django.contrib.contenttypes', 109 | 'django.contrib.sessions', 110 | 'django.contrib.messages', 111 | 'django.contrib.staticfiles', 112 | 'position', 113 | 'jobapp' 114 | 115 | ] 116 | 117 | 118 | 3. 在新模块中新建urls.py 119 | 120 | from django.urls import path 121 | 122 | from . import views 123 | app_name = 'position' 124 | urlpatterns = [ 125 | 126 | path('', views.index, name='index'), 127 | path('/', views.detail, name='detail'), 128 | path('/search/', views.search, name='search'), 129 | path('add/', views.addPosition, name='addPos'), 130 | path('apply/', views.applyPosition, name='applyPos'), 131 | 132 | 133 | 4. 修改主路由,包含新模块 134 | 135 | ``` 136 | from django.conf.urls import url 137 | from django.contrib import admin 138 | from django.urls import path,include 139 | 140 | urlpatterns = [ 141 | path('polls/', include('position.urls')), 142 | url('detail/(?p\d+)',postion.detail,name='detail') 143 | path('admin/', admin.site.urls), 144 | ] 145 | 146 | ``` 147 | 在include子路由时,可以加命名空间 148 | 149 | path('polls/', include('position.urls',namespace='jobapp-position')), 150 | 151 | 152 | 153 | **模板中可以使用路由名称** 154 | 155 | {% url 'detail'%} 156 | 5. 跨模块路由跳转(注意冒号) 157 | 158 | reverse('模块名:路由名') 159 | 160 | myurl=reverse('position:getall') 161 | myurl=reverse('position:getall',kwargs={'id':110}) 162 | return redirect(myurl) 163 | 164 | 165 | 4. migrate 166 | 167 | 迁移非常强大,随着时间的推移,您可以随时更改模型,而无需删除数据库或表并创建新的数据库 - 它专门用于实时升级数据库,而不会丢失数据。我们将在本教程的后面部分更深入地介绍它们,但现在请记住进行模型更改的三步指南: 168 | 169 | * 改变你的模型(in models.py)。 170 | * 运行以为这些更改创建迁移python manage.py makemigrations 171 | * 运行以将这些更改应用于数据库。python manage.py migrate 172 | 5. 173 | 174 | 175 | -------------------------------------------------------------------------------- /Django/unit2-server-跨域请求.md: -------------------------------------------------------------------------------- 1 | # 服务器端对象-跨域请求 2 | 1. 在接口函数中配置 3 | 4 | from django.http import HttpResponse,response,JsonResponse 5 | def login(request): 6 | todo_list = [ 7 | {"id": "1", "content": "吃饭"}, 8 | {"id": "2", "content": "吃饭"}, 9 | ] 10 | response = JsonResponse(todo_list, safe=False) 11 | response["Access-Control-Allow-Origin"] = "*" 12 | response["Access-Control-Allow-Methods"] = "POST, GET, OPTIONS" 13 | response["Access-Control-Max-Age"] = "1000" 14 | response["Access-Control-Allow-Headers"] = "*" 15 | return response 16 | 17 | 1. 安装CORS 18 | 19 | pip install django-cors-headers 20 | 2. 添加app 21 | 22 | INSTALLED_APPS = ( 23 | ... 24 | 'corsheaders', 25 | ... 26 | ) 27 | 3. 添加中间件 28 | 29 | MIDDLEWARE = [ # Or MIDDLEWARE_CLASSES on Django < 1.10 30 | ... 31 | 'corsheaders.middleware.CorsMiddleware', 32 | 'django.middleware.common.CommonMiddleware', 33 | ... 34 | ] 35 | 36 | 4. 配置允许跨站访问本站 37 | 38 | 1. 配置允许跨站访问本站的地址 39 | 40 | CORS_ORIGIN_ALLOW_ALL = False 41 | CORS_ORIGIN_WHITELIST = ( 42 | 'localhost:63343', 43 | ) 44 | 45 | # 默认值是全部: 46 | CORS_ORIGIN_WHITELIST = () # 或者定义允许的匹配路径正则表达式. 47 | 48 | CORS_ORIGIN_REGEX_WHITELIST = ('^(https?://)?(\w+.)?>google.com$', ) # 默认值: 49 | 50 | CORS_ORIGIN_REGEX_WHITELIST = () 51 | 52 | 2. 设置允许访问的方法 53 | 54 | CORS_ALLOW_METHODS = ( 55 | 'GET', 56 | 'POST', 57 | 'PUT', 58 | 'PATCH', 59 | 'DELETE', 60 | 'OPTIONS' 61 | ) 62 | 63 | 3. 设置允许的header: 64 | 65 | 默认值: 66 | 67 | CORS_ALLOW_HEADERS = ( 68 | 'x-requested-with', 69 | 'content-type', 70 | 'accept', 71 | 'origin', 72 | 'authorization', 73 | 'x-csrftoken', 74 | #当客户端通过header提交数据,比如token字段是,需要加上字段名。比如 75 | 'token' 76 | ) 77 | 5. ajax获取token 78 | 79 | ###前端ajax代码 80 | 81 | $.ajax( 82 | { 83 | url:'http://localhost:8000/user/login/', 84 | type:"POST", 85 | data:user, 86 | dataType:"json", 87 | contentType:"application/json", 88 | success:function (response,textStatus,request) { 89 | 90 | console.log(response) 91 | console.log(textStatus) 92 | console.log(request.getAllResponseHeaders()) 93 | }, 94 | error:function (XMLHttpRequest,textStatus,errorThrown) { 95 | console.log('nononon') 96 | console.log(textStatus) 97 | } 98 | 99 | } 100 | ) 101 | **request.getAllResponseHeaders()负责取出数据** 102 | 103 | **但是不行啊,原因** 104 | 105 | 1:W3C的 xhr 标准中做了限制,规定客户端无法获取 response 中的 Set-Cookie、Set-Cookie2这2个字段,无论是同域还是跨域请求; 106 | 107 | 2:W3C 的 cors 标准对于跨域请求也做了限制,规定对于跨域请求,客户端允许获取的response header字段只限于“simple response header”和“Access-Control-Expose-Headers” ,在“Access-Control-Allow-Headers”中加了无效 108 | 109 | "simple response header"包括的 header 字段有:Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma; 110 | 111 | "Access-Control-Expose-Headers":首先得注意是"Access-Control-Expose-Headers"进行跨域请求时响应头部中的一个字段,对于同域请求,响应头部是没有这个字段的。这个字段中列举的 header 字段就是服务器允许暴露给客户端访问的字段。 112 | 113 | 114 | ###服务器端代码 115 | 116 | resp['token'] = '8888888888888' 117 | resp["Access-Control-Expose-Headers"] = "token" -------------------------------------------------------------------------------- /Django/unit2-template.md: -------------------------------------------------------------------------------- 1 | # 模板 2 | 3 | 1. 控制器文件 4 | 首先修改路由文件,当路由匹配时跳转到指定的控制器文件 5 | urls.py 6 | 7 | ``` 8 | from django.conf.urls import url 9 | from django.contrib import admin 10 | from . import view 11 | from . import personal 12 | 13 | urlpatterns = [ 14 | url(r'^$', view.hello), 15 | url(r'^person\w*$', personal.login), 16 | ] 17 | 18 | ``` 19 | 然后控制器文件准备数据等内容,和视图文件交互 20 | personal.py 21 | 22 | ``` 23 | from django.shortcuts import render 24 | import datetime 25 | def login(request): 26 | context={} 27 | context['userID']='lzhan....' 28 | context['isLogin']=False 29 | context['date']=datetime.datetime.now() 30 | context['myLoves']=[ 31 | {"name":"tony","age":12,"inof":"i am a student,and from USA","date":"2018-3-5"}, 32 | {"name":"sony","age":22,"inof":"i am a worker,and from USA","date":"2018-6-5"}, 33 | {"name":"rose","age":32,"inof":"i am a worker,and from USA","date":"2018-5-5"}, 34 | {"name":"bush","age":42,"inof":"i am a farm,and from USA","date":"2018-7-5"}, 35 | ] 36 | #此处render()负责跳转到视图文件 37 | return render(request,'personal.html',context) 38 | ``` 39 | 2. 视图文件 40 | 41 | ``` 42 | {% include "nav.html" %} 43 | {% if not isLogin %} 44 |

{{date|date:"F j, Y" }}

45 | {% endif %} 46 |
    47 | {% for per in myLoves %} 48 | 49 | 50 |
  • {{forloop.counter}}
  • 51 | 52 |
  • {{forloop.counter0}}
  • 53 | 54 |
  • 55 | {# 这是一个注释 #} 56 | {% for k,v in per.items %} 57 | 58 | {{k | first | upper}}--{{v|truncatewords:"10" }} 59 | {% endfor %} 60 | {% endfor %} 61 |
  • 62 |
63 | ``` 64 | 1. if标签 65 | 66 | ``` 67 | {% if condition1 and condition2 or condition3 %} 68 | ... display 1 69 | {% elif condition2 %} 70 | ... display 2 71 | {% else %} 72 | ... display 3 73 | {% endif %} 74 | ``` 75 | 2. for 76 | 77 | ``` 78 | {% for athlete in athlete_list %} 79 |

{{ athlete.name }}

80 |
    81 | {% for sport in athlete.sports_played %} 82 |
  • {{ sport }}
  • 83 | {% endfor %} 84 |
85 | {% endfor %} 86 | ``` 87 | 3. ifequal/ifnotequal 标签 88 | 89 | {% ifequal %} 标签比较两个值,当他们相等时,显示在 {% ifequal %} 和 {% endifequal %} 之中所有的值。 90 | 91 | 下面的例子比较两个模板变量 user 和 currentuser : 92 | 93 | ``` 94 | {% ifequal user currentuser %} 95 |

Welcome!

96 | {% else %} 97 |

No user Here

98 | {% endifequal %} 99 | ``` 100 | 4. 注释标签 101 | Django 注释使用 {# #}。 102 | 103 | ``` 104 | {# 这是一个注释 #} 105 | ``` 106 | 5. 过滤器 107 | 108 | ``` 109 | {{ name|lower }} 110 | {{ name|length }} 111 | {{ my_list|first|upper }} 112 | #这个将显示变量 bio 的前30个词。 113 | {{ bio|truncatewords:"30" }} 114 | {{ pub_date|date:"F j, Y" }} 115 | ``` 116 | 6. include标签 117 | 118 | {% include %} 标签允许在模板中包含其它的模板的内容。 119 | 120 | 下面这个例子都包含了 nav.html 模板: 121 | 122 | ``` 123 | {% include "nav.html" %} 124 | ``` 125 | 7. 模板继承 126 | 127 | 模板可以用继承的方式来实现复用。 128 | 129 | 接下来我们先创建之前项目的 templates 目录中添加 base.html 文件,代码如下: 130 | 131 | 132 | ``` 133 | HelloWorld/templates/base.html 文件代码: 134 | 135 | 136 | 137 | 138 | 菜鸟教程(runoob.com) 139 | 140 | 141 |

Hello World!

142 |

Django 测试。

143 | {% block mainbody %} 144 |

original

145 | {% endblock %} 146 | 147 | 148 | 149 | ``` 150 | 151 | 以上代码中,名为 mainbody 的 block 标签是可以被继承者们替换掉的部分。 152 | 153 | 所有的 {% block %} 标签告诉模板引擎,子模板可以重载这些部分。 154 | 155 | hello.html 中继承 base.html,并替换特定 block, hello.html 修改后的代码如下: 156 | 157 | HelloWorld/templates/hello.html 文件代码: 158 | 159 | ``` 160 | {% extends "base.html" %} 161 | 162 | {% block mainbody %}

继承了 base.html 文件

163 | {% endblock %} 164 | 165 | ``` 166 | 第一行代码说明 hello.html 继承了 base.html 文件。可以看到,这里相同名字的 block 标签用以替换 base.html 的相应 block。 167 | 168 | 8. 169 | 170 | -------------------------------------------------------------------------------- /Django/unit3-model-1.md: -------------------------------------------------------------------------------- 1 | # 模型 2 | 3 | 1. 介绍 4 | 5 | 模型是有关数据的单一,明确的信息来源。它包含您要存储的数据的基本字段和行为。通常,每个模型都映射到单个数据库表。 6 | 7 | 基础: 8 | 9 | * 每个模型都是一个子类的Python类 django.db.models.Model。 10 | * 模型的每个属性代表一个数据库字段。 11 | 12 | 2. ORM 13 | 14 | 关系对象映射(Object Relational Mapping,简称ORM)。 15 | 16 | 生成表结构(默认数据库为sqllite) 17 | 18 | 1. 在引用下的models.py文件中(如果没有就新键)。创建类 19 | 20 | from django.db import models 21 | 22 | # Create your models here. 23 | class userinfo(models.Model): 24 | # 自动创建一个id列,id为主键、自增长 25 | telephone = models.CharField(max_length=30) 26 | password = models.CharField(max_length=64) 27 | email = models.EmailField() 28 | # memo = models.TextField() 29 | 2. 修改配置文件(settings.py),告诉应用从哪里应用模块中创建 30 | 31 | INSTALLED_APPS = [ 32 | 'django.contrib.admin', 33 | 'django.contrib.auth', 34 | 'django.contrib.contenttypes', 35 | 'django.contrib.sessions', 36 | 'django.contrib.messages', 37 | 'django.contrib.staticfiles', 38 | 'jobapp' #注意这里加上的是模块名称 39 | ] 40 | 3. 执行创建命令-python manage.py makemigrations 41 | 42 | **注意** 43 | 44 | 该模块目录下必须有一个文件夹:migrations(如果没有就新键) 45 | 46 | 47 | 执行python manage.py makemigrations生成临时文件:“0001_initial.py” 48 | 49 | 4. python manage.py migrate 生成数据表 50 | 51 | 52 | 默认表名:“jobapp01_uerinfo” 53 | 54 | 5. 把数据库从sqllite改为mysql 55 | 56 | 修改配置文件: 57 | 58 | 之前为: 59 | 60 | DATABASES = { 61 | 'default': { 62 | 'ENGINE': 'django.db.backends.sqlite3', 63 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 64 | } 65 | } 66 | 67 | 修改为: 68 | 69 | DATABASES = { 70 | 'default': { 71 | 'ENGINE': 'django.db.backends.mysql', 72 | 'NAME':'jobapp_django', 73 | 'USER': 'root', 74 | 'PASSWORD': '12345678', 75 | 'HOST': '127.0.0.1', 76 | 'PORT': '3306', 77 | } 78 | } 79 | 80 | **注意** 81 | 82 | 由于Django内部连接MySQL时使用的是MySQLdb模块,而python3中还无此模块,所以需要使用pymysql来代替 83 | 84 | 如下设置放置的与project同名的配置的 __init__.py文件中 85 | 86 | import pymysql 87 | pymysql.install_as_MySQLdb()  88 | 89 | **所以啊,要先安装:pip install pymysql** 90 | 91 | 1. **删除数据表重新生成,解决 python No migrations to apply 无法生成表** 92 | 93 | 第一步: 94 | 95 | 删除该app名字下的migrations文件。 96 | 97 | 第二步: 98 | 99 | 进入数据库,找到django_migrations的表,删除该app名字的所有记录。 100 | delete from django_migrations; 101 | 102 | 或者删除数据库重新新建 103 | 104 | 第三部: 105 | 106 | python manage.py makemigrations 107 | 108 | python manage.py migrate 109 | 110 | 3. 访问数据数据库 111 | 112 | 1. 增加数据 113 | 114 | 在views.py文件中,增加 115 | 116 | from . import models 117 | 118 | 119 | def regist(request): 120 | # uu返回数据库中刚加入的那个对象 121 | uu=models.userinfo.objects.create( 122 | telephone="root", 123 | password="123456" 124 | ) 125 | 126 | #或者 127 | 128 | uu=models.userinfo.objects.create(**dict) 129 | 130 | 131 | #或者 132 | 133 | user=models.userinfo(telephone="admin",password="6666") 134 | user.save() 135 | 136 | return HttpResponse('regist ok') 137 | 138 | #再者 139 | 140 | dic={"telephone":"alex","password":"888"} 141 | 142 | models.userinfo(**dic).save() #当然了, models.userinfo.objects.create(**dic)也可以 143 | 144 | **force_update和force_insert** 145 | 146 | 这两个参数一般较少用到,因为save()之后django执行的是UPDATE或者INSERT这两条SQL语句的哪一条,遵循如下算法: 147 | 148 | 1.如果这个对象已经有主键而且主键的值是True的(即不是None或者空字符串等),就执行UPDATE。 149 | 150 | 2.如果没有主键或者这条save()不会update任何字段,那么它就INSERT。 151 | 152 | 只有在某些特定情况下,需要强制save()执行INSERT或UPDATE时才会使force_update=True或force_insert=True(比如我要求能UPDATE就UPDATE,不能我也不取INSERT,那么我就把这个force_update参数设置为True)。 153 | 2. 关于自增长id 154 | 155 | **id必须为models.AutoField** 156 | 157 | class userinfo(models.Model): 158 | # id = models.IntegerField(primary_key=True) 159 | id = models.AutoField(primary_key=True) 160 | 161 | # 自动创建一个id列,id为主键、自增长 162 | telephone = models.CharField(unique=True,max_length=30) 163 | password = models.CharField(max_length=64) 164 | email = models.EmailField() 165 | # memo = models.TextFi eld() 166 | 167 | **save()之后直接拿** 168 | 169 | dic={"telephone":"root","password":"999"} 170 | 171 | comment=models.userinfo(**dic) 172 | comment.save() 173 | 174 | print(comment.id) 175 | 176 | 2. 查询数据 177 | 178 | 1. 查询所有数据 179 | 180 | users=models.userinfo.objects.all() 181 | 182 | # 返回的是对象列表 183 | for user in users: 184 | print(user.id,user.telephone,user.password) 185 | 186 | #获取部分列 187 | users=models.userinfo.objects.all().values(‘id’,'telephone') 188 | #这个时候users为字典列表 189 | 190 | #获取部分列 191 | models.userinfo.objects.all().values_list(‘id’,'telephone') 192 | 193 | #这个时候users为元组列表 194 | 195 | 2. 条件查询 196 | 197 | 1. 单条件 198 | 199 | 200 | users=models.userinfo.objects.filter(telephone='root') 201 | #select * from userinfo where telephone='root' 202 | for user in users: 203 | print(user.id,user.telephone,user.password) 204 | 205 | 206 | 2. and 207 | 208 | 逗号表示and 209 | 210 | users=models.userinfo.objects.filter(telephone='root',password='123) 211 | 212 | 213 | 1. .... 214 | 215 | 3. 删除 216 | 217 | affect_rows=models.userinfo.objects.all().delete() 218 | 219 | affect_rows=models.userinfo.objects.filter(id='4').delete() 220 | 221 | 4. 更新 222 | 223 | affect_rows=models.userinfo.objects.all().update(password="666666") 224 | affect_rows=models.userinfo.objects.filter(id='4').update(password="666666") 225 | 226 | 227 | 228 | 4. demo 实现用户登录 229 | 230 | **注意** 231 | 232 | 如果数据没有查到返回的是[]空列表 233 | 234 | 如果user=models.userinfo.objects.filter(telephone='root').first()没有查到数据则结果为None 235 | 236 | 如果num=models.userinfo.objects.filter(telephone='root').count()没有查到数据则结果为0 237 | -------------------------------------------------------------------------------- /Django/unit3-model-2-mysql.md: -------------------------------------------------------------------------------- 1 | # mysql 2 | 1. model字段类型 3 | 4 | *'AutoField': 'integer AUTO_INCREMENT', 5 | 'BigAutoField': 'bigint AUTO_INCREMENT', 6 | 'BinaryField': 'longblob', 7 | *'BooleanField': 'bool', 8 | *'CharField': 'varchar(%(max_length)s)', 9 | 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 10 | *'DateField': 'date', 11 | *'DateTimeField': 'datetime', 12 | *'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 13 | 'DurationField': 'bigint', 14 | 'FileField': 'varchar(%(max_length)s)', 15 | 'FilePathField': 'varchar(%(max_length)s)', 16 | *'FloatField': 'double precision', 17 | *'IntegerField': 'integer', 18 | 'BigIntegerField': 'bigint', 19 | 'IPAddressField': 'char(15)', 20 | 'GenericIPAddressField': 'char(39)', 21 | 'NullBooleanField': 'bool', 22 | *'OneToOneField': 'integer', 23 | 'PositiveIntegerField': 'integer UNSIGNED', 24 | 'PositiveSmallIntegerField': 'smallint UNSIGNED', 25 | 'SlugField': 'varchar(%(max_length)s)', 26 | 'SmallIntegerField': 'smallint', 27 | *'TextField': 'longtext', 28 | *'TimeField': 'time', 29 | *'UUIDField': 'char(32)', 30 | 31 | 32 | DEMO: 33 | 34 | from django.db import models 35 | 36 | # Create your models here. 37 | class userinfo(models.Model): 38 | # id = models.IntegerField(primary_key=True) 39 | id = models.AutoField(primary_key=True) 40 | 41 | # 自动创建一个id列,id为主键、自增长 42 | telephone = models.CharField(unique=True,max_length=11) 43 | password = models.CharField(max_length=64) 44 | email = models.EmailField(null=True,db_column='uemail') 45 | regist_time=models.DateTimeField(auto_now_add=True,null=True) 46 | salary = models.DecimalField(max_digits=5, decimal_places=2) # 一共5位,保留两位小数 47 | 48 | ########Admin部分。放在后面谈...... 49 | # Admin为了不额外添加一张用户类型表,可以使用choices字段 50 | user_types=( 51 | (1,'普通用户'), 52 | (2,'VIP用户'), 53 | (3,'管理员') 54 | ) 55 | 56 | user_type_id=models.IntegerField(choices=user_types,default=1) 57 | # memo = models.TextField() 58 | 59 | 2. model 数据约束 60 | 61 | null 数据库中字段是否可以为空 62 | db_column 数据库中字段的列名 63 | email = models.EmailField(null=True,db_column='uemail') 64 | 65 | 66 | db_tablespace 67 | default 数据库中字段的默认值 68 | primary_key 数据库中字段是否为主键 69 | 70 | telephone = models.CharField(unique=True,max_length=30) 71 | 72 | db_index 数据库中字段是否可以建立索引 73 | unique 数据库中字段是否可以建立唯一索引 74 | unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引 75 | unique_for_month 数据库中字段【月】部分是否可以建立唯一索引 76 | unique_for_year 数据库中字段【年】部分是否可以建立唯一索引 77 | auto_now_add 该列自动填充系统当前时间 78 | == 79 | Admin模块中用到的字段 80 | 81 | verbose_name Admin中显示的字段名称 82 | blank Admin中是否允许用户输入为空 83 | editable Admin中是否可以编辑 84 | help_text Admin中该字段的提示信息 85 | choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作 86 | 如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1) 87 | 88 | error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息; 89 | 字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date 90 | 如:{'null': "不能为空.", 'invalid': '格式错误'} 91 | 92 | validators 自定义错误验证(列表类型),从而定制想要的验证规则 93 | from django.core.validators import RegexValidator 94 | from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\ 95 | MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator 96 | 如: 97 | test = models.CharField( 98 | max_length=32, 99 | error_messages={ 100 | 'c1': '优先错信息1', 101 | 'c2': '优先错信息2', 102 | 'c3': '优先错信息3', 103 | }, 104 | validators=[ 105 | RegexValidator(regex='root_\d+', message='错误了', code='c1'), 106 | RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'), 107 | EmailValidator(message='又错误了', code='c3'), ] 108 | ) 109 | 110 | 111 | DEMO: 112 | 113 | class UserInfo(models.Model): 114 | nid = models.AutoField(primary_key=True) 115 | username = models.CharField(max_length=32) 116 | class Meta: 117 | # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名 118 | db_table = "table_name" 119 | 120 | # 联合索引 121 | index_together = [ 122 | ("pub_date", "deadline"), 123 | ] 124 | 125 | # 联合唯一索引 126 | unique_together = (("driver", "restaurant"),) 127 | 128 | # admin中显示的表名称 129 | verbose_name 130 | 131 | # verbose_name加s 132 | verbose_name_plural 133 | 134 | 更多:https://docs.djangoproject.com/en/1.10/ref/models/options/ 135 | 136 | 137 | -------------------------------------------------------------------------------- /Django/unit3-model-3-mysql增删改查进阶.md: -------------------------------------------------------------------------------- 1 | # mysql-增删改查 2 | 1. 查询行数 3 | 4 | #查询结果的行数 5 | # users=models.userinfo.objects.all().count() 6 | users=models.userinfo.objects.filter(id=1).count() 7 | #查询第一个结果 8 | # user=models.userinfo.objects.all().first() 9 | # user=models.userinfo.objects.get(id=1) 10 | 11 | 12 | 13 | 14 | 2. 关系查询 15 | 16 | **注意双下划线** 17 | 18 | #获取部分列 19 | users=models.userinfo.objects.all().values(‘id’,'telephone') 20 | #这个时候users为字典列表,通过list(users)转化为字典列表,然后json.dumps(list(users))转化为字符串,传给客户端即可。 21 | 22 | #获取部分列 23 | models.userinfo.objects.all().values_list(‘id’,'telephone') 24 | #这个时候users为元组列表 25 | 26 | # 大于,小于 27 | # models.userinfo.objects.filter(id__gt=1) # 获取id大于1的值 28 | # models.userinfo.objects.filter(id__gte=1) # 获取id大于等于1的值 29 | # models.userinfo.objects.filter(id__lt=10) # 获取id小于10的值 30 | # models.userinfo.objects.filter(id__lte=10) # 获取id小于10的值 31 | # models.userinfo.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值 32 | 33 | #不等于 34 | 35 | from django.db.models import Q 36 | #查询工资不等于10000 37 | jobs = models.job.objects.filter(~Q(salary_min=10000)).values('title','com_name','salary_min') 38 | 39 | 3. in 40 | 41 | # models.userinfo.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据 42 | # models.userinfo.objects.exclude(id__in=[11, 22, 33]) # not in 43 | 44 | 4. is null 45 | 46 | users=models.userinfo.objects.filter(id__isnull=False) #True 47 | 48 | 5. contains 49 | 50 | users=models.userinfo.objects.filter(email__contains='admin') 51 | 52 | #不区分大小写 53 | 54 | users=models.userinfo.objects.filter(email__icontains='admin') 55 | 56 | #不包含 57 | 58 | users=models.userinfo.objects.exclude(email__icontains='admin') 59 | 60 | 6. range 61 | 62 | users=models.userinfo.objects.filter(id__range=[3,7]) 63 | 64 | 7. endswith startswith 65 | 8. order_by() 66 | 67 | users=models.userinfo.objects.all().order_by('id') #asc 68 | users=models.userinfo.objects.all().order_by('-id') #desc 69 | 70 | 9. group by 71 | 72 | group by 73 | 74 | # 75 | # from django.db.models import Count, Min, Max, Sum 76 | # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num')) 77 | # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id" 78 | 79 | 10. limit 80 | 81 | models.Tb1.objects.all()[10:20] 82 | 11. regex正则匹配,iregex 不区分大小写 83 | 84 | users=models.userinfo.objects.filter(email__regex=r'_admin') 85 | 86 | 12. date 87 | 88 | date 89 | 90 | # 91 | # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1)) 92 | # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1)) 93 | 94 | # year 95 | # 96 | # Entry.objects.filter(pub_date__year=2005) 97 | # Entry.objects.filter(pub_date__year__gte=2005) 98 | 99 | 13. 执行原生SQL 100 | 101 | # from django.db import connection, connections 102 | # cursor = connection.cursor() # cursor = connections['default'].cursor() 103 | # cursor.execute("""SELECT * from auth_user where id = %s""", [1]) 104 | # row = cursor.fetchone() -------------------------------------------------------------------------------- /Django/unit3-model-4-表关系.md: -------------------------------------------------------------------------------- 1 | # mysql-多表查询 2 | 3. 表关系 3 | 4 | 5 | 6 | * 一对多:models.ForeignKey(其他表) 7 | * 多对多:models.ManyToManyField(其他表) 8 | * 一对一:models.OneToOneField(其他表) 9 | 10 | 11 | 12 | 1. 一对多关系(从表为userinfo和主表usertype) 13 | 14 | 1. 设置外键 15 | 16 | user_type=models.ForeignKey(to="usertype",to_field="id",default=1,on_delete= models.CASCADE) 17 | 18 | >此时、主表为usertype,从表为userinfo.**注意在数据库中表明为“模块名_类名的小写形势”。加入模块名为userinfo,这两个表名分贝为“user_usertype”和"user_userinfo".** 19 | >在从表中会产生一个新的字段:user\_type_id.但注意user\_type代表的是主表usertpye对象。 20 | 21 | **注意加上on_delete= models.CASCADE** 22 | 23 | - models.CASCADE,删除关联数据,与之关联也删除 24 | 25 | - models.DO_NOTHING,删除关联数据,引发错误IntegrityError 26 | 27 | - models.PROTECT,删除关联数据,引发错误ProtectedError 28 | 29 | - models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空) 30 | 31 | - models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值) 32 | 33 | 34 | 2. 查询数据数据时user_type就是主表的对象 35 | 36 | ####查询数据 37 | 1. 正向查询(由从表到主表的查询) 38 | 39 | users=models.userinfo.objects.all() 40 | 41 | for user in users: 42 | print(user.user_type.id) #等价于print(user.user_type_id) 43 | print(user.user_type.name) 44 | 45 | 如果单纯想拿到user_type的值可以这么样: 46 | 47 | users=models.userinfo.objects.all().values('telephone','password','user_type') 48 | 49 | **请注意这是数据的类型为字典类型的queryset** 50 | 51 | 2. 逆向查询(由主表到从表的查询) 52 | 53 | #get得到的直接是一个对象,不过get只能查看有一条记录的 54 | #查询类型为vip的对象 55 | t = models.usertype.objects.get(name='vip') 56 | 57 | #查询类型为vip的所有用户 58 | 59 | users=t.userinfo_set.all() 60 | #users=t.userinfo_set.all().values() 61 | #users=t.userinfo_set.all().values("id","telephone") 62 | 63 | >注意userinfo_set为系统提供的集合表示方式 64 | 65 | 66 | 3. 比较厉害的双下划线 67 | 68 | users=models.userinfo.objects.all().values('telephone','user_type__name')# __name 69 | 70 | s数据类型 71 | 72 | {"telephone": "root", "password": "999", "user_type__name": "\u666e\u901a\u7528\u6237"}, {"telephone": "admin", "password": "123", "user_type__name": "VIP\u7528\u6237"} 73 | 74 | ####添加数据 75 | 76 | 1. 方式一,先主表然后从表(不推荐) 77 | 78 | 例如: 79 | try: 80 | t = { 81 | "name": "user" 82 | } 83 | 84 | 85 | obj = models.Type.objects.create(**t) 86 | print(obj.id) 87 | 88 | #获取主表id 89 | user = { 90 | "telephone": "138", 91 | "password": "111", 92 | "user_type_id":obj.id 93 | } 94 | 95 | obj_u=models.UserInfo.objects.create(**user) 96 | 2. 方式二 97 | 98 | 例如:增加一个vip用户 99 | 100 | #1. 找出类型表中vip 101 | 102 | obj_type =models.Type.objects.filter(name='vip')[0] 103 | #2. 把查出的对象直接写入,注意user_type就是一对多链接对象: 104 | # user_type=models.ForeignKey(to='Type',to_field='id',default=1,on_delete=models.CASCADE) 105 | 106 | 107 | user = { 108 | "telephone": "139", 109 | "password": "222", 110 | "user_type":obj_type 111 | } 112 | 113 | obj_u=models.UserInfo.objects.create(**user) 114 | 115 | 1. 多对多关系 116 | 117 | 需要导入包时: 118 | 119 | from jobapp.models import * 120 | 121 | 因为setting.py已经设置 122 | 123 | INSTALLED_APPS = [ 124 | 'django.contrib.admin', 125 | 'django.contrib.auth', 126 | 'django.contrib.contenttypes', 127 | 'django.contrib.sessions', 128 | 'django.contrib.messages', 129 | 'django.contrib.staticfiles', 130 | 'position', 131 | 'jobapp' 132 | 133 | ] 134 | 135 | 136 | 2. 创建多对多关系表 137 | 138 | 139 | # 模拟多对多关系:用户-投递-职位 140 | class applyposition(models.Model): 141 | id = models.AutoField(primary_key=True) 142 | # 自动创建一个id列,id为主键、自增长 143 | uobj = models.ForeignKey(to=userinfo,to_field='id',on_delete=True) 144 | pobj = models.ForeignKey(to="position",to_field='id',on_delete=True) 145 | publish_time=models.DateTimeField(auto_now_add=True,null=True) 146 | 147 | **当然,这样创作好理解但是繁琐,我们可以直接在岗位模型中加入一条语句** 148 | 149 | from jobapp.models import * 150 | 151 | #在job表中 152 | apply=models.ManyToManyField(userinfo) 153 | 154 | 3. 数据操作 155 | 156 | 1. 增加数据 157 | 158 | 这个时候要先确定一个条件,比如user01投递了position01,那么我们就确定了岗位: 159 | 160 | pos=positon.objects.get(id=1) 161 | 162 | pos.apply.add(1) #这个时候的1就是用户id 163 | pos.apply.add(1,2,3) #这个时候的1,2,3就是用户id 164 | pos.apply.add(*[1,2,3,4]) #这个时候的1就是用户id 165 | 166 | 2. 删除数据 167 | 168 | pos.apply.remove(2) 169 | pos.apply.remove(1,2,3) 170 | pos.apply.remove(*[1,2,3]) 171 | pos.apply.clear() 172 | 173 | 3. 修改数据 174 | 175 | #关系表中岗位表是1的,只会有用户名1,2,3.其他都会删除 176 | pos.apply.set(1,2,3) 177 | 178 | 3. 查询数据 179 | 180 | pos=positon.objects.get(id=1) 181 | 182 | #此时拿到的对象集合为用户对象集合 183 | pos.apply.all() 184 | 185 | #要拿到关联表中(比如用户表中的)其他字段 186 | 187 | pos.apply.all().values('job_apply_password','job_apply_telephone') 188 | 189 | == 190 | # 添加数据 191 | pp = models.position.objects.get(id=2) 192 | pp.apply.add(7) 193 | 194 | #查询数据 195 | pos=models.position.objects.get(id=1) 196 | print(pos.name) 197 | print(pos.apply.all().filter(id=1)) 198 | users=pos.apply.all() 199 | for u in users: 200 | print(u.telephone) 201 | 202 | -------------------------------------------------------------------------------- /Django/unit4-middleware.md: -------------------------------------------------------------------------------- 1 | # 中间件 2 | 3 | 1. 哪里有 4 | 5 | settings.py 6 | 7 | MIDDLEWARE = [ 8 | 'django.middleware.security.SecurityMiddleware', 9 | 'django.contrib.sessions.middleware.SessionMiddleware', 10 | 'django.middleware.common.CommonMiddleware', 11 | # 'django.middleware.csrf.CsrfViewMiddleware', 12 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 13 | 'django.contrib.messages.middleware.MessageMiddleware', 14 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 15 | ] 16 | 17 | 18 | 2. 说明 19 | 20 | django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。 21 | 22 | 全局: 23 | 24 |   中间件 django.middleware.csrf.CsrfViewMiddleware 25 | 26 | 局部: 27 | 28 | @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。 29 | 30 | @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。 31 | **注:from django.views.decorators.csrf import csrf_exempt,csrf_protect** -------------------------------------------------------------------------------- /Django/uuid.md: -------------------------------------------------------------------------------- 1 | # uuid 2 | 3 | 1. 介绍 4 | 5 | 该模块提供不可变的UUID对象(UUID类)和功能uuid1(),uuid3(),uuid4(),uuid5()如在指定用于生成版本1,3,4和5点的UUIDRFC 4122。 6 | 7 | 如果你想要的只是一个唯一的ID,你应该打电话给uuid1()或 uuid4()。请注意,uuid1()可能会破坏隐私,因为它会创建包含计算机网络地址的UUID。 uuid4()创建一个随机的UUID。 8 | 2. 方法 9 | 10 | 1. uuid.uuid1(node = None,clock_seq = None ) 11 | 12 | 从主机ID,序列号和当前时间生成UUID。如果 未给出节点,getnode()则用于获取硬件地址。如果 给出clock_seq,则将其用作序列号; 否则,选择随机的14位序列号。 13 | 14 | 2. uuid.uuid3(名称空间,名称) 15 | 16 | 基于命名空间标识符(UUID)和名称(字符串)的MD5哈希生成UUID。 17 | 18 | 3. uuid.uuid4() 19 | 20 | 生成随机UUID。 21 | 22 | 4. uuid.uuid5(名称空间,名称) 23 | 24 | 基于命名空间标识符(UUID)和名称(字符串)的SHA-1哈希生成UUID。 25 | 26 | 27 | import uuid 28 | 29 | uuid01=uuid.uuid1() 30 | print(uuid01) 31 | uuid04=uuid.uuid4() 32 | print(uuid04) 33 | uuid03=uuid.uuid3(uuid.NAMESPACE_DNS,'JOBAPP.COM') 34 | uuid05=uuid.uuid5(uuid.NAMESPACE_DNS,'JOBAPP.COM') 35 | print(uuid03) 36 | 3. 命名空间标识符 37 | 38 | * uuid.NAMESPACE_DNS 39 | 40 | 指定此命名空间时,名称字符串是完全限定的域名。 41 | 42 | * uuid.NAMESPACE_URL 43 | 44 | 指定此命名空间时,名称字符串是URL。 45 | 46 | * uuid.NAMESPACE_OID 47 | 48 | 指定此命名空间时,名称字符串是ISO OID。 49 | 50 | * uuid.NAMESPACE_X500 51 | 52 | 指定此命名空间时,名称字符串是DER或文本输出格式的X.500 DN。 -------------------------------------------------------------------------------- /Flask/resfful api.md: -------------------------------------------------------------------------------- 1 | 网上整理的对于Rest和Restful api的理解 2 | 3 | 1. 什么是Rest? 4 | 5 | REST不是"rest"这个单词,而是几个单词缩写 -- REpresentational State Transfer 直接翻译:表现层状态转移,但这个翻译正常人根本看不懂,找到的一种最好理解的说法是,URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作。 6 | 7 | REST成熟度的四个层次 8 | 9 | 第一个层次(Level0)的Web 服务只是使用 HTTP 作为传输方式,实际上只是远程方法调用(RPC)的一种具体形 式。SOAP和 XML-RPC都属于此类。 10 | 11 | 第二个层次(Level1)的Web 服务引入了资源的概念。每个资源有对应的标识符和表达。 12 | 13 | 第三个层次(Level2)的Web 服务使用不同的 HTTP 方法来进行不同的操作,并且使用HTTP 状态码来表示不同的结果。如 HTTPGET 方法来获取资源,HTTPDELETE 方法来删除资源。 14 | 15 | 第四个层次(Level3)的Web 服务使用 HATEOAS。在资源的表达中包含了链接信息。客户端可以根据链接来发现可以执行的动作。 16 | 17 | 2. Restful api接口有什么特征? 18 | 19 | 20 | REST描述的是在网络中client和server的一种交互形式;REST本身不实用,实用的是如何设计 RESTful API(REST风格的网络接口)。 21 | 22 | 1. URL的根路径 23 | 24 | http://api.chesxs.com/v1 25 | 2. 需要有api版本信息 26 | 27 | http://api.chesxs.com/v1 28 | 3. URL中只使用名词指定资源,不用动词,且推荐使用复数 29 | 30 | 服务(Server)提供的RESTful API中,URL中只使用名词来指定资源,原则上不使用动词。“资源”是REST架构或者说整个网络处理的核心。比如: 31 | 32 | http://api.chesxs.com/v1/cars // 获取某个账户下的车辆列表 33 | http://api.chesxs.com/v1/fences // 获取某个账户下的围栏列表 34 | 4. 用HTTP协议里的动词来实现资源的添加,修改,删除等操作。即通过HTTP动词来实现资源的状态扭转 35 | 36 | GET 用来获取资源, 37 | 38 | POST 用来新建资源(也可以用于更新资源)。比如:POST http://api.chesxs.com/v1/car: 添加车辆 39 | 40 | PUT 用来更新资源, 41 | 42 | DELETE 用来删除资源。比如:DELETE http://api.chesxs.com/v1/cars 删除某辆车 (在http parameter指定好友id) 43 | 44 | UPDATE http://api.chesxs.com/v1/fence 更新围栏信息 45 | 46 | 错误使用: GET http://api.chesxs.com/v1/deleteCar 删除车辆 47 | 复制代码 48 | 5. GET应该是安全的,不会改变资源状态 49 | 50 | 这个应该很好理解,get的时候就只是获取资源,而不涉及添加、更新、删除资源。 51 | 52 | 6. 使用正确的HTTP Status Code返回状态码 53 | 54 | 常用的有404,200,500,400等等。 55 | 56 | 7. 过滤信息 57 | 58 | 如果记录数量很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果。 59 | 60 | 下面是一些常见的参数。 61 | 62 | ?limit=10:指定返回记录的数量 63 | ?offset=10:指定返回记录的开始位置。 64 | ?page=2&per_page=100:指定第几页,以及每页的记录数。 65 | ?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。 66 | ?producy_type=1:指定筛选条件 67 | 8. 规范返回的数据 68 | 69 | 为了保障前后端的数据交互的顺畅,建议规范数据的返回,并采用固定的数据格式封装。 70 | 71 | 接口返回模板: 72 | 73 | 74 | { 75 | status:0, 76 | 77 | data:{}||[], 78 | 79 | msg:’’ 80 | } 81 | 82 | 83 | 84 | 85 | 86 | ###总结,看一个标准的restful api要可以做到 87 | 88 | 看Url就知道要操作的资源是什么,是操作车辆还是围栏 89 | 90 | 看Http Method就知道操作动作是什么,是添加(post)还是删除(delete) 91 | 92 | 看Http Status Code就知道操作结果如何,是成功(200)还是内部错误(500) 93 | 94 | 参考文章:https://www.cnblogs.com/bndong/p/6139598.html -------------------------------------------------------------------------------- /Flask/unit0: -------------------------------------------------------------------------------- 1 | 1. HTTP1.1协议中文版-RFC2616 2 | https://www.cnblogs.com/k1988/archive/2010/01/12/2165683.html 3 | 2. -------------------------------------------------------------------------------- /Flask/unit1-基础.md: -------------------------------------------------------------------------------- 1 | #unit1 2 | **作者:詹亮** 3 | 4 | 1. 安装Flask 5 | 6 | ``` 7 | pip install Flask 8 | ``` 9 | 这些发行版将在安装Flask时自动安装。 10 | 11 | 1. Werkzeug实现了WSGI,这是应用程序和服务器之间的标准Python接口。 12 | 2. Jinja是一种模板语言,可呈现应用程序服务的页面。 13 | 3. MarkupSafe带有Jinja。它在渲染模板时逃避不可信的输入以避免注入攻击。 14 | 4. 它的危险性可靠地标记数据以确保其完整性。这用于保护Flask的会话cookie。 15 | 5. Click是编写命令行应用程序的框架。它提供了该flask命令并允许添加自定义管理命令 16 | 17 | 18 | 这些发行版不会自动安装。如果安装它们,Flask将检测并使用它们。 19 | 20 | 1. Blinker为信号提供支持。 21 | 2. SimpleJSON是一种与Python json模块兼容的快速JSON实现。如果安装了JSON操作,则是首选。 22 | 3. python-dotenv在运行 命令时支持来自dotenv的环境变量flask。 23 | 4. 看门狗为开发服务器提供更快,更高效的重载器。 24 | 2. hello world 25 | 26 | ``` 27 | from flask import Flask 28 | app = Flask(__name__) 29 | 30 | @app.route('/') 31 | def hello_world(): 32 | return 'Hello, World!' 33 | if __name__ == '__main__': 34 | app.run() 35 | ``` 36 | 3. 启动代码 37 | 38 | 使用flask命令或者-m使用Flask的python 开关。在你这样做之前,你需要通过导出FLASK_APP环境变量告诉你的终端应用程序 : 39 | 40 | ``` 41 | $ export FLASK_APP=hello.py 42 | $ flask run 43 | * Running on http://127.0.0.1:5000/ 44 | ``` 45 | 如果您在Windows上,环境变量语法取决于命令行解释器。在命令提示符下: 46 | 47 | ``` 48 | C:\path\to\app>set FLASK_APP=hello.py 49 | ``` 50 | 4. 启动调试模式 51 | 52 | app.run(host='0.0.0.0', port=5000, debug=True) 53 | 54 | >允许外网访问,并修改端口号 -------------------------------------------------------------------------------- /Flask/unit2-router.md: -------------------------------------------------------------------------------- 1 | # unit2 路由 2 | **作者:詹亮** 3 | 4 | 1. 简单入门 5 | 6 | ``` 7 | @app.route('/') 8 | def index(): 9 | return 'Index Page' 10 | 11 | @app.route('/hello/') 12 | #路由会执行下面的第一个方法,方法名不必和路由相同 13 | def hello(): 14 | return 'Hello, World' 15 | ``` 16 | **projects端点的规范URL 具有尾部斜杠。它类似于文件系统中的文件夹。如果您访问的URL没有斜杠,则Flask会将您重定向到带有斜杠的规范URL。** 17 | 2. 路由参数 18 | 19 | 可以通过标记部分将可变部分添加到URL 。您的函数然后接收 作为关键字参数。或者,您可以使用转换器来指定参数类型。 20 | 21 | ``` 22 | @app.route('/user/') 23 | def show_user_profile(username): #这里不要忘了哦 24 | # show the user profile for that user 25 | return 'User %s' % username 26 | 27 | @app.route('/post/') 28 | def show_post(post_id): 29 | # show the post with the given id, the id is an integer 30 | return 'Post %d' % post_id 31 | 32 | @app.route('/path/') 33 | def show_subpath(subpath): 34 | # show the subpath after /path/ 35 | return 'Subpath %s' % subpath 36 | ``` 37 | 38 | 转换器类型: 39 | 40 | string (默认)接受不带斜杠的文本 41 | int 接受正整数 42 | float 接受正浮点值 43 | path 喜欢,string但也接受斜线 44 | uuid 接受UUID字符串 45 | 3. url_for 46 | 47 | url_for() 函数最简单的用法是以视图函数名作为参数, 返回对应的 URL。 48 | 49 | ``` 50 | @app.route('/allusers/') 51 | 52 | def getAllUsers(): 53 | return json.dumps(data) 54 | 55 | @app.route('/user/') 56 | def show_user_profile(username): 57 | #返回函数getAllUsers所对应的路由 58 | s=url_for('getAllUsers') 59 | #/allusers/ 60 | ``` 61 | 62 | from flask import Flask, url_for 63 | 64 | app = Flask(__name__) 65 | 66 | @app.route('/') 67 | def index(): 68 | return 'index' 69 | 70 | @app.route('/login') 71 | def login(): 72 | return 'login' 73 | 74 | @app.route('/user/') 75 | def profile(username): 76 | return '{}\'s profile'.format(username) 77 | 78 | with app.test_request_context(): 79 | print(url_for('index')) 80 | print(url_for('login')) 81 | print(url_for('login', next='/')) 82 | print(url_for('profile', username='John Doe')) 83 | 84 | / 85 | /login 86 | /login?next=/ 87 | /user/John%20Doe 88 | 4. redirect 89 | 90 | ``` 91 | from flask import Flask,url_for,redirect 92 | ... 93 | @app.route('/user/') 94 | def show_user_profile(username): 95 | #返回函数getAllUsers所对应的路由 96 | s=url_for('getAllUsers') 97 | #/allusers/ 98 | 99 | #重定向到/allusers/ 100 | return redirect(s) 101 | ``` 102 | 103 | 5. 蓝图 104 | 105 | 什么是蓝图? 106 | 107 | 一个蓝图定义了可用于单个应用的视图,模板,静态文件等等的集合。 108 | 109 | 我什么时候会用到蓝图? 110 | 蓝图的杀手锏是将你的应用组织成不同的组件,比如把admin,user相关的视图方法分为两个组件,一个是admin组件,一个是user组件.这时我们可以 111 | 112 | 创建两个蓝图实现这两个独立的组件. 113 | 6. 创建蓝图 114 | 115 | 要想创建一个蓝图对象,你需要import flask.Blueprint()类并用参数name和import_name初始化。import_name通常用__name__,一个表示当前模块的特殊的Python变量,作为import_name的取值。 116 | 117 | user.py和admin.py模块 118 | 119 | from flask import Blueprint, render_template, redirect 120 | 121 | #用参数name和import_name初始化 122 | user = Blueprint('user',__name__) 123 | 124 | @user.route('/index') 125 | def index(): 126 | return render_template('user/index.html') 127 | 128 | @user.route('/add') 129 | def add(): 130 | return 'user_add' 131 | 132 | @user.route('/show') 133 | def show(): 134 | return 'user_show' 135 | --- 136 | 137 | from flask import Blueprint,render_template, request 138 | admin = Blueprint('admin',__name__) 139 | 140 | @admin.route('/index') 141 | def index(): 142 | return render_template('admin/index.html') 143 | 144 | @admin.route('/add') 145 | def add(): 146 | return 'admin_add' 147 | 148 | @admin.route('/show') 149 | def show(): 150 | return 'admin_show' 151 | 152 | run.py 路由入口 153 | 154 | from flask import Flask, render_template 155 | from admin import admin 156 | from user import user 157 | 158 | app = Flask(__name__) 159 | 160 | #这里分别给app注册了两个蓝图admin,user 161 | #参数url_prefix='/xxx'的意思是设置request.url中的url前缀, 162 | #即当request.url是以/admin或者/user的情况下才会通过注册的蓝图的视图方法处理请求并返回 163 | app.register_blueprint(admin,url_prefix='/admin') 164 | app.register_blueprint(user, url_prefix='/user') 165 | 166 | 167 | @app.route('/') 168 | def index(): 169 | return 'index' 170 | 171 | @app.errorhandler(404) 172 | def miss(e): 173 | return render_template('404.html'), 404 174 | 175 | 176 | @app.errorhandler(500) 177 | def error(e): 178 | return render_template('500.html'), 500 179 | 180 | 181 | if __name__ == '__main__': 182 | print(app.url_map) 183 | app.run() -------------------------------------------------------------------------------- /Flask/unit4-template.md: -------------------------------------------------------------------------------- 1 | #unit4 模板 2 | **作者:詹亮** 3 | 4 | 由于我们采用的模式为动静分离模式,故此模块没有完成相应的文档 -------------------------------------------------------------------------------- /Flask/unit5-mysql-SQLAlchemy.md: -------------------------------------------------------------------------------- 1 | #unit5 mysql- SQLAlchemy 2 | **作者:詹亮** 3 | 4 | http://www.pythondoc.com/flask-sqlalchemy/quickstart.html 5 | 1. 安装 6 | 7 | pip install Flask-SQLAlchemy 8 | 9 | 2. 使用SQLAlchemy创建表 10 | 11 | 1. 新建models包__init__.py配置 12 | 13 | #导入SQLAlchemy模块 14 | from flask_sqlalchemy import SQLAlchemy 15 | 16 | #导入应用对象,代码在下面有 17 | from app import app 18 | db = SQLAlchemy() 19 | 20 | #将当app对象加入上下文 21 | app.app_context().push() 22 | print('models app is{}'.format(id(app))) 23 | 24 | 配置连接数据库 25 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True 26 | app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:12345678@127.0.0.1:3306/pythondb' 27 | #初始化连接,此时会默认生成一个数据库连接池,里面有很多连接对象session 28 | #可以使用语句db.session 29 | db.init_app(app) 30 | 31 | 32 | app.py 33 | 34 | from flask import Flask 35 | app=Flask(__name__) 36 | 37 | 2. model 38 | 39 | #.表示当前包的__init__模块 40 | from . import db 41 | class Person(db.Model): 42 | id = db.Column(db.Integer, primary_key=True) 43 | username = db.Column(db.String(80), unique=True) 44 | email = db.Column(db.String(120), unique=True) 45 | 46 | def __init__(self, username, email): 47 | self.username = username 48 | self.email = email 49 | 50 | def __repr__(self): 51 | return '' % self.username 52 | 53 | class Address(db.Model): 54 | id = db.Column(db.Integer, primary_key=True) 55 | province = db.Column(db.String(80), unique=True) 56 | city = db.Column(db.String(120), unique=True) 57 | 58 | def __init__(self, province, city): 59 | self.province = province 60 | self.city = city 61 | 62 | def __repr__(self): 63 | return '
' % self.province 64 | 65 | 66 | #如果从当前文件新建表则可以: 67 | 68 | if __name__ == '__main__': 69 | db.create_all() 70 | 3. 根据模型新建表 db.create_all() 71 | 72 | setup.py 73 | 74 | from models.Person import db 75 | if __name__ == '__main__': 76 | db.create_all() 77 | -------------------------------------------------------------------------------- /Flask/unit5-mysql.md: -------------------------------------------------------------------------------- 1 | #unit5 mysql 2 | **作者:詹亮** 3 | 4 | 5 | 1. 安装 6 | 7 | MySQLdb 只适用于python2.x,它在py3的替代品是: import pymysql 8 | 9 | pip install pymysql 10 | 11 | >而Django默认的还是使用 MySQLdb :执行会报: ImportError: No module named 'MySQLdb' 12 | 解决: 13 | 14 | 在站点的 __init__.py 文件中添加 15 | 16 | import pymysql 17 | pymysql.install_as_MySQLdb() 18 | 2. 创建数据库 19 | 20 | import pymysql # 1.导入pymysql包 21 | 22 | db = pymysql.connect(host='localhost', user='root', 23 | password='12345678',port=3306) # 2.声明一个MySQL连接对象db,在远程host传入其公网ip 24 | cursor =db.cursor() # 3.获得操作游标 25 | cursor.execute('SELECT VERSION()') # 4.通过游标进行操作,execute()执行sql语句 26 | data = cursor.fetchone() # 获得第一条数据 27 | print('Database version:', data) 28 | cursor.execute("CREATE DATABASE spiders DEFAULT CHARACTER SET utf8") # 创建数据库,默认utf-8编码 29 | db.close() # 5.关闭连接 30 | 31 | 2. 新建表 32 | 33 | try: 34 | db = None 35 | db = pymysql.connect(host='localhost', user='root', 36 | password='12345678', port=3306, db='spiders') # 2.声明一个MySQL连接对象db,在远程host传入其公网ip 37 | cursor = db.cursor() 38 | sql = 'CREATE TABLE IF NOT EXISTS students (id VARCHAR(255) NOT NULL,' \ 39 | ' name VARCHAR(255) NOT NULL, age INT NOT NULL, PRIMARY KEY (id))' 40 | cursor.execute(sql) 41 | except Exception as ex: 42 | print(ex) 43 | finally: 44 | if db: 45 | db.close() 46 | 47 | 3. 事务 48 | 49 | 1. 原子性 50 | 2. 一致性 51 | 3. 隔离性 52 | 4. 持久性 53 | 54 | try: 55 | cursor.execute(sql) 56 | cursor.commit() # 提交,数据才被真正写到了数据库中 57 | except: 58 | db.rollback() # 回滚操作,相当与没有进行操作 59 | 4. 插入数据 60 | 61 | data = { 62 | 'id': '2012001', 63 | 'name': 'Bob', 64 | 'age': 20 65 | } 66 | table = 'students' 67 | keys = ','.join(data.keys()) 68 | values = ', '.join(['%s'] * len(data)) 69 | sql = 'INSERT INTO {table}({keys}) VALUES ({values})'.format(table=table, keys=keys, values=values) 70 | try: 71 | db = None 72 | db = pymysql.connect(host='localhost', user='root', 73 | password='12345678', port=3306, db='spiders') # 2.声明一个MySQL连接对象db,在远程host传入其公网ip 74 | cursor = db.cursor() 75 | if cursor.execute(sql, tuple(data.values())): 76 | print('Successful') 77 | db.commit() 78 | except: 79 | print('Failed') 80 | db.rollback() 81 | finally: 82 | db.close() 83 | 84 | **注意 对于多个条件的情况,也可以使用下面的格式。但是不要忘记{0} 外面的单引号** 85 | 86 | sql = "insert into user(telephone,password,email,city_id) values('{0}','{1}','{2}','{3}')".format(id,password,email,city_id) 87 | 88 | 89 | 90 | 不应该 91 | 92 | sql = "insert into user(telephone,password,email,city_id) values({0},{1},{2},{3})" 93 | 插入多条语句 94 | 95 | cursor.executemany("insert into hosts(host,color_id)values(%s,%s)", [("1.1.1.11",1),("1.1.1.11",2)]) 96 | 97 | 98 | **对于自动增长列,要获取值** 99 | 100 | id=connect.insert_id() 101 | 102 | print(connect.affected_rows()) 103 | 4. 更新操作 104 | 105 | import pymysql 106 | try: 107 | connect = None 108 | connect = pymysql.connect(host='localhost', user='root', 109 | password='12345678', port=3306, db='jobapp') # 2.声明一个MySQL连接对象db,在远程host传入其公网ip 110 | cursor = connect.cursor(cursor=pymysql.cursors.DictCursor) 111 | sql = "update user set city_id='19' where telephone={0}".format('15810001000') 112 | result=cursor.execute(sql) 113 | print(result) 114 | 115 | connect.commit() 116 | 117 | except Exception as ex: 118 | connect.rollback() 119 | finally: 120 | if connect: 121 | connect.close() 122 | cursor.close() 123 | 5. 删除操作 124 | 3. 查询 125 | 126 | **设置查询结果为字典列表** 127 | 128 | cursor = connect.cursor(cursor=pymysql.cursors.DictCursor) 129 | 130 | == 131 | 132 | db = pymysql.connect(host='localhost', user='root', 133 | password='12345678',port=3306,db='school') # 2.声明一个MySQL连接对象db,在远程host传入其公网ip 134 | cursor =db.cursor() # 3.获得操作游标 135 | sql='select * from user where name="{0}"'.format('tom') 136 | cursor.execute(sql) 137 | print(cursor) 138 | print('Count:', cursor.rowcount) # rowcount属性获取查询结果的条数 139 | # 获取第一行数据 140 | one = cursor.fetchone() # fetchone()方法,这个方法可以获取结果的第一条数据,返回结果是元组形式 141 | print('One:', one) 142 | # 获取前n行数据 143 | # row_2 = cursor.fetchmany(3) 144 | # 获取所有数据 145 | results = cursor.fetchall() # fetchall()方法返回的是偏移指针指向的数据一直到结束的所有数据 146 | for uu in results: 147 | print(uu) 148 | db.close() # 5.关闭连接 149 | 150 | **注:在fetch数据时按照顺序进行,可以使用cursor.scroll(num,mode)来移动游标位置,**如: 151 | 152 | cursor.scroll(1,mode='relative') # 相对当前位置移动 +1表示向后移动一条,-1表示向上移动一条 153 | 154 | cursor.scroll(2,mode='absolute') # 相对绝对位置移动 155 | 156 | 关于默认获取的数据是元祖类型,如果想要或者字典类型的数据,即: 157 | 158 | cursor = db.cursor(cursor=pymysql.cursors.DictCursor) 159 | 160 | 161 | 5. 调用存储过程 162 | 163 | 164 | sql="call getUsersByCity('石家庄市',@res)" 165 | cursor.execute(sql) 166 | print('结果是'+str(cursor.fetchone())) 167 | 168 | 169 | res='' 170 | cursor.callproc('getUsersByCity',('石家庄市',res)) 171 | print(cursor.fetchone()) 172 | print(res) 173 | 174 | 6. 连接池 175 | 176 | pip install DBUtils 177 | 在dao/init.py文件中创建连接池 178 | 179 | import pymysql 180 | from DBUtils.PooledDB import PooledDB, SharedDBConnection 181 | 182 | POOL = PooledDB( 183 | creator=pymysql, # 使用链接数据库的模块 184 | maxconnections=6, # 连接池允许的最大连接数,0和None表示不限制连接数 185 | mincached=2, # 初始化时,链接池中至少创建的空闲的链接,0表示不创建 186 | maxcached=5, # 链接池中最多闲置的链接,0和None不限制 187 | maxshared=3, # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。 188 | blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错 189 | maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制 190 | setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."] 191 | ping=0, 192 | # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always 193 | host='127.0.0.1', 194 | port=3306, 195 | user='root', 196 | password='12345678', 197 | database='jobapp', 198 | charset='utf8' 199 | ) 200 | 201 | 在接口中 202 | 203 | from . import POOL 204 | def getUserById(id): 205 | try: 206 | client=POOL.connection() 207 | res_user=-1 208 | cursor = client.cursor(cursor=pymysql.cursors.DictCursor) -------------------------------------------------------------------------------- /mysql/unit1.md: -------------------------------------------------------------------------------- 1 | #mysql-基础 2 | 1. 介绍 3 | 4 | 20世纪90年代诞生于瑞典 5 | 6 | 2008年被SUN收购 7 | 8 | 2009年SUN被ORICAL收购 9 | 10 | [官网](http://dev.mysql.com/downloads/installer/) 11 | 2. 80版本navigat无法登陆的情况 12 | 13 | 14 | 命令行 mysql -u root -p 然后进入管理页面 15 | 16 | ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root'; 17 | 2. 安装目录及配置 18 | 19 | 1. windows: my.ini 20 | 2. mac: my.conf 21 | 22 | 配置参数 23 | 24 | # 以下选项会被MySQL客户端应用读取。 25 | # 注意只有MySQL附带的客户端应用程序保证可以读取这段内容。 26 | # 如果你想你自己的MySQL应用程序获取这些值。 27 | # 需要在MySQL客户端库初始化的时候指定这些选项。 28 | [client] 29 | port = 3306 30 | socket = /usr/local/mysql/mysql.sock 31 | # MySQL 服务端 32 | [mysqld] 33 | #默认存储引擎INNODB 34 | default-storage-engine=INNODB 35 | #GROUP_CONCAT长度 36 | group_concat_max_len =99999 37 | #端口号 38 | port = 3306 39 | #socket位置 40 | socket = /usr/local/mysql/mysql.sock 41 | #pid写入文件位置 42 | pid-file = /usr/local/mysql/mysqld.pid 43 | #数据库文件位置 44 | datadir = /home/data/mysql/data 45 | user = mysql 46 | #SQL模式具体查阅相关资料 47 | sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES 48 | #当外部锁定(external-locking)起作用时,每个进程若要访问数据表, 49 | #则必须等待之前的进程完成操作并解除锁定。由于服务器访问数据表时经常需要等待解锁, 50 | #因此在单服务器环境下external locking会让MySQL性能下降。 51 | #所以在很多Linux发行版的源中,MySQL配置文件中默认使用了skip-external-locking来避免external locking。 52 | skip-external-locking 53 | #跳过DNS反向解析 54 | skip-name-resolve 55 | #关闭TIMESTAMP类型默认值 56 | explicit_defaults_for_timestamp 57 | 3. 启动服务 58 | 59 | windows: 60 | 61 | 1. service mysqld start 62 | 2. service mysqld stop 63 | 3. service mysqld restart 64 | 4. service mysqld status 65 | 66 | 4. 三大范式 67 | 68 | 为了建立冗余较小、结构合理的数据库,设计数据库时必须遵循一定的规则。在关系型数据库中这种规则就称为范式。范式是符合某一种设计要求的总结。要想设计一个结构合理的关系型数据库,必须满足一定的范式。 69 | 70 | 1. 第一范式(确保每列保持原子性) 71 | 72 | 第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式。 73 | 74 | 第一范式的合理遵循需要根据系统的实际需求来定。比如某些数据库系统中需要用到“地址”这个属性,本来直接将“地址”属性设计成一个数据库表的字段就行。但是如果系统经常会访问“地址”属性中的“城市”部分,那么就非要将“地址”这个属性重新拆分为省份、城市、详细地址等多个部分进行存储,这样在对地址中某一部分操作的时候将非常方便。这样设计才算满足了数据库的第一范式,如下表所示。 75 | 76 | 2. 第二范式(确保表中的每列都和主键相关) 77 | 78 | 第二范式在第一范式的基础之上更进一层。第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。也就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。 79 | 80 | 比如要设计一个订单信息表,因为订单中可能会有多种商品,所以要将订单编号和商品编号作为数据库表的联合主键,如下表所示。 81 | 82 | 订单信息表 83 | 84 | ![dd](https://pic002.cnblogs.com/images/2012/270324/2012040114063976.png) 85 | 86 | 这样就产生一个问题:这个表中是以订单编号和商品编号作为联合主键。这样在该表中商品名称、单位、商品价格等信息不与该表的主键相关,而仅仅是与商品编号相关。所以在这里违反了第二范式的设计原则。 87 | 88 | 而如果把这个订单信息表进行拆分,把商品信息分离到另一个表中,把订单项目表也分离到另一个表中,就非常完美了。 89 | 90 | 案例分析: 91 | 92 | 学生| 课程| 老师| 老师职称| 教材| 教室| 上课时间| 93 | ---|---|---|---|---|---|---| 94 | 小明| 一年级语文(上)| 大宝| 副教授| 《小学语文1》| 101| 14:30| 95 | 96 | 3. 第三范式(确保每列都和主键列直接相关,而不是间接相关) 97 | 98 | 第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。 99 | 100 | 比如在设计一个订单数据表的时候,可以将客户编号作为一个外键和订单表建立相应的关系。而不可以在订单表中添加关于客户其它信息(比如姓名、所属公司等)的字段。如下面这两个表所示的设计就是一个满足第三范式的数据库表。 101 | 102 | ![](https://pic002.cnblogs.com/images/2012/270324/2012040114105477.png) 103 | 104 | 105 | drop database if exists db_name; 106 | 107 | 4. DDL 108 | 109 | 新建数据库 110 | 111 | -- 数据库名不需要加引号 112 | DROP database if EXISTS mystudents; 113 | CREATE DATABASE mystudents DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 114 | 115 | 新建表结构 116 | 117 | -- 新建student表 118 | 119 | -- drop TABLE if EXISTS student; 120 | CREATE table student( 121 | id int PRIMARY KEY auto_increment, 122 | sno VARCHAR(10) UNIQUE, 123 | sname varchar(20) not NULL, 124 | sgender VARCHAR(2) DEFAULT '女', 125 | sbirthday date, 126 | sdept varchar(20) 127 | 128 | ) 129 | 130 | 131 | -- 新建course 132 | 133 | CREATE table course( 134 | cno VARCHAR(4) PRIMARY key, 135 | cname VARCHAR(40) not null, 136 | cpno varchar(4), 137 | ccredit SMALLINT, 138 | -- 记住属性要用括号 139 | FOREIGN key(cpno) REFERENCES course(cno) 140 | ) 141 | 142 | 143 | -- 新建sc表 144 | 145 | create table sc( 146 | sno VARCHAR(10), 147 | cno varchar(4), 148 | grade SMALLINT, 149 | PRIMARY key(sno,cno), 150 | FOREIGN key(sno) REFERENCES student(sno), 151 | FOREIGN key(cno) REFERENCES course(cno) 152 | ) 153 | 154 | 155 | -- 查看表结构 156 | 157 | desc sc; 158 | show create table sc; 159 | 160 | -- 修改表约束 161 | 162 | alter table sc add FOREIGN key(sno) REFERENCES student(sno); 163 | alter table sc add FOREIGN key(cno) REFERENCES course(cno); 164 | 165 | 166 | use mystudents; 167 | 168 | -------------------------------------------------------------------------------- /mysql/unit2-数据查询.md: -------------------------------------------------------------------------------- 1 | # unit2-数据查询 2 | 3 | 1. 查询表中的若干列 4 | 5 | SELECT Sno,Sname 6 | FROM Student; 7 | #查询所有列 8 | SELECT * 9 | FROM Student; 10 | 2. select 字句 11 | 12 | 1. 算术表达式 13 | 14 | SELECT Sname,2018-Sage /*假定当年的年份为2018年*/ 15 | FROM Student; 16 | 17 | 1. 字符串常量 18 | 19 | SELECT Sname,‘我是测试列: ',2004-Sage,LOWER(Sdept) 20 | FROM Student; 21 | 22 | 1. 函数 23 | 1. 列别名 24 | 3. 消除取值重复的行 25 | 26 | select DISTINCT(sno) as '学号' from sc 27 | 28 | 🙋:查看有哪些学生参加了考试 29 | 4. where字句 30 | 31 | 32 | 1. 比较运算符: 33 | 34 | =,>,<,>=,<=,!=,<>,!>,!< 35 | 36 | 2. 范围运算符: 37 | 38 | BETWEEN AND,NOT BETWEEN AND 39 | 40 | 3. 确定集合: 41 | 42 | IN,NOT IN 43 | 44 | 4. 字符匹配: 45 | 46 | like not like 47 | 5. 空值 48 | 49 | is null , is not null 50 | 6. 逻辑 51 | 52 | not and or 53 | 54 | 🙋: 55 | 56 | 1. 查询计算机科学系全体学生的名单 57 | 58 | 2. 查询所有年龄在20岁以下的学生姓名及其年龄 59 | 60 | 3. 查询年龄在20~23岁之间的学生的 姓名、系别和年龄(between ..and..) 61 | 4. 查询信息系(IS)、数学系(MA)和计算机科学系(CS)学生的姓名和性别。 62 | 63 | 64 | 65 | 66 | 5. like 67 | 68 | 匹配串为含通配符的字符串:% _ 69 | 70 | 🙋: 71 | 72 | 查询姓"李"且全名为三个汉字的学生的姓名 73 | 74 | 6. is null is not null 75 | 76 | 🙋: 77 | 78 | 某些学生选修课程后没有参加考试,所以有选课记录,但没有考试成绩。查询缺少成绩的学生的学号和相应的课程号。 79 | 80 | 7. not and or 81 | 82 | 🙋: 83 | 查询计算机系年龄在20岁以下的学生姓名。 84 | 85 | 8. 排序 86 | 87 | 可以按一个或多个属性列排序 88 | 89 | 升序:ASC;降序:DESC;缺省值为升序 90 | 91 | 🙋: 92 | 93 | 查询全体学生情况,查询结果按所在系的系号升序排列,同一系中的学生按年龄降序排列。 94 | 查看全体同学的数学成绩,并按降序排列 95 | 96 | 9. 聚合函数 97 | 98 | count() sum() avg() max() min() 99 | 100 | 🙋: 101 | 102 | 统计有多少学生参加考试 103 | 104 | 3号课程的总成绩和平均分 105 | 106 | 002学生的总分 107 | 108 | 找出最低分 109 | 110 | select sum(grade) as '总分' from sc where sno=002; 111 | 112 | select min(grade),sno,cno from sc; 113 | 114 | 10. 分组 115 | 116 | HAVING短语与WHERE子句的区别: 117 | 118 | 1. WHERE从中选择满足条件的元组 119 | 120 | 2. HAVING短语作用于组,从中选择满足条件的组 121 | 122 | 🙋: 123 | 124 | 查看每个人的总分和平均分 125 | 126 | select sum(grade),sno from sc GROUP BY sno; 127 | 128 | 129 | select avg(grade),sno from sc GROUP BY sno; 130 | 131 | 查看平均分最高的信息 132 | 133 | select avg(grade),sno from sc GROUP BY sno ORDER BY avg(grade) desc; 134 | 135 | 136 | 查看平均分不及格信息 where 首次筛选 having 分组后筛选 137 | 138 | select avg(grade),sno from sc GROUP BY sno having avg(grade)<60; 139 | 140 | 查看平均分大于70,并从高到低排列 141 | select avg(grade),cno from sc GROUP BY cno having avg(grade)>70 ORDER BY avg(grade) asc; 142 | 143 | 找出参加三门考试的同学 144 | 145 | select count(sno),sno from sc GROUP BY sno HAVING count(*)>=3; 146 | 147 | 统计每门课程的选修人数 148 | SELECT COUNT(sno) as '考试人数', cno as '课程编号' FROM sc GROUP BY cno 149 | 统计选修人数少于2人的课程标号 150 | SELECT COUNT(sno) as '考试人数', cno as '课程编号' FROM sc GROUP BY cno HAVING COUNT(sno)<2 151 | 152 | -- ??将每门课程的平均分按从高到低排序 153 | 154 | -- ??将每门课程的最高分分按从高到低排序,并指出是哪位同学 155 | 156 | -- ??将每个学生的平均分从高到低排序 157 | 3. limit 158 | 159 | limit start,total; 160 | 161 | start:开始记录 162 | 163 | total:总共取多少行记录 164 | 165 | 🙋: 166 | 167 | 总分前3名的学生 168 | select sum(grade),sno from sc GROUP BY sno ORDER BY sum(grade) desc limit 0,3; 169 | 170 | 总分倒数第一的学生 171 | 172 | select sum(grade),sno from sc GROUP BY sno ORDER BY sum(grade) asc limit 0,1; 173 | 174 | # 内置函数 175 | 176 | 1. 数学函数 177 | 178 | 179 | 1. abs(x) 180 | 1. pi() 181 | 1. mod(x,y) 182 | 1. sqrt(x) 183 | 1. ceil(x)或者ceiling(x) 184 | 1. rand(),rand(N):返回0-1间的浮点数,使用不同的seed N可以获得不同的随机数 185 | 1. round(x, D):四舍五入保留D位小数,D默认为0, 可以为负数, 如round(19, -1)返回20 186 | 1. truncate(x, D):截断至保留D位小数,D可以为负数, 如trancate(19,-1)返回10 187 | 1. sign(x): 返回x的符号,正负零分别返回1, -1, 0 188 | 1. pow(x,y)或者power(x,y) 189 | 1. exp(x):e^x 190 | 191 | 2. 字符串函数 192 | 193 | 1. char_length(str):返回str所包含的字符数,一个多字节字符算一个字符 194 | 1. length(str): 返回字符串的字节长度,如utf8中,一个汉字3字节,数字和字母算一个字节 195 | 1. concat(s1, s1, ...): 返回连接参数产生的字符串 196 | 1. concat_ws(x, s1, s2, ...): 使用连接符x连接其他参数产生的字符串 197 | 1. INSERT(str,pos,len,newstr):返回str,其起始于pos,长度为len的子串被newstr取代。 198 | 1. 若pos不在str范围内,则返回原字符串str 199 | 2. 若str中从pos开始的子串不足len,则将从pos开始的剩余字符用newstr取代 200 | 3. 计算pos时从1开始,若pos=3,则从第3个字符开始替换 201 | 1. lower(str)或者lcase(str): 202 | 1. upper(str)或者ucase(str): 203 | 1. left(s,n):返回字符串s最左边n个字符 204 | 1. right(s,n): 返回字符串最右边n个字符 205 | 1. ltrim(s):删除s左侧空格字符 206 | 1. rtrim(s): 207 | 1. TRIM([{BOTH | LEADING | TRAILING} [remstr] FROM] str)或TRIM([remstr FROM] str):从str中删除remstr, remstr默认为空白字符 208 | 1. REPEAT(str,count):返回str重复count次得到的新字符串 209 | 1. REPLACE(str,from_str,to_str): 将str中的from_str全部替换成to_str 210 | 1. SPACE(N):返回长度为N的空白字符串 211 | 1. STRCMP(str1,str2):若str1和str2相同,返回0, 若str1小于str2, 返回-1, 否则返回1. 212 | 1. SUBSTRING(str,pos), SUBSTRING(str FROM pos), 1. SUBSTRING(str,pos,len), SUBSTRING(str FROM pos FOR len),MID(str,pos,len): 获取特定位置,特定长度的子字符串 213 | 214 | 3. 日期函数 215 | 216 | 1. CURDATE(), CURRENT_DATE, CURRENT_DATE():用于获取当前日期,格式为'YYYY-MM-DD' 217 | 2. CURTIME([fsp]), CURRENT_TIME, CURRENT_TIME([fsp]): 用于获取当前时间, 格式为'HH:MM:SS' 218 | 3. CURRENT_TIMESTAMP, CURRENT_TIMESTAMP([fsp]), LOCALTIME, LOCALTIME([fsp]), SYSDATE([fsp]), NOW([fsp]): 用于获取当前的时间日期,格式为'YYYY-MM-DD HH:MM:SS' 219 | 4. UNIX\_TIMESTAMP(), UNIX\_TIMESTAMP(date):返回一个unix时间戳('1970-01-01 00:00:00' UTC至今或者date的秒数),这实际上是从字符串到整数的一个转化过程 220 | 5. FROM_UNIXTIME(UNIX_TIMESTAMP('2010-3-3'))从时间戳返回日期 221 | 222 | 6. 提取时间 223 | 224 | MONTH(date) 225 | MONTHNAME(date) 226 | DAYNAME(date) 227 | DAY(date),DAYOFMONTH(date):1-31或者0 228 | DAYOFWEEK(date):1-7==>星期天-星期六 229 | DAYOFYEAR(date): 1-365(366) 230 | WEEK(date[,mode]):判断是一年的第几周,如果1-1所在周在新的一年多于4天,则将其定为第一周;否则将其定为上一年的最后一周。mode是用来人为定义一周从星期几开始。 231 | WEEKOFYEAR(date):类似week(date,3),从周一开始计算一周。 232 | QUARTER(date):返回1-4 233 | HOUR(time):返回时间中的小时数,可以大于24 234 | MINUTE(time): 235 | SECOND(time): 236 | 237 | 7. 返回两个日期相差的天数 238 | 239 | SELECT DATEDIFF(CURRENT_DATE(),DATE('2018-10-4')) 240 | 8. 返回相隔的时间 241 | 242 | SELECT TimeDIFF(CURRENT_DATE(),DATE('2018-10-4')) 243 | 244 | #结果 245 | 838:59:59 246 | 247 | 参考: 248 | https://www.cnblogs.com/noway-neway/p/5211401.html 249 | 250 | 3. 系统信息函数 251 | 252 | 253 | 1. VERSION():返回mysql服务器的版本,是utf8编码的字符串 254 | 1. DATABASE(),SCHEMA():显示当前使用的数据库 255 | 1. SESSION_USER(), SYSTEM_USER(), USER(), CURRENT_USER, CURRENT_USER():返回当前的用户名@主机,utf8编码字符串 256 | 1. CHARSET('hello') 字符编码 257 | 1. COLLATION(str) 字符排序规则 258 | 1. LAST\_INSERT\_ID():自动返回最后一个insert或者update查询, 为auto_increment列设置的第一个发生的值 259 | 260 | 4. 加密函数 261 | 262 | 1. password() 263 | 1. MD5(str):计算MD5 128位校验和,返回32位16进制数构成的字符串,当str为NULL时返回NULL。可以用作哈希密码 264 | 2. SHA1(str), SHA(str):计算160位校验和,返回40位16进制数构成的字符串,当str为NULL时返回NULL。 265 | 3. SHA2(str, hash_length):计算SHA-2系列的哈希方法(SHA-224, SHA-256, SHA-384, and SHA-512). 第一个参数为待校验字符串,第二个参数为结果的位数(224, 256, 384, 512) -------------------------------------------------------------------------------- /mysql/unit3-视图、事务、存储过程.md: -------------------------------------------------------------------------------- 1 | # unit3-多表链接&存储过程 2 | ## 多表查询 3 | 1. 等值与非等值连接查询 4 | 2. 自身链接 5 | 3. 外链接 6 | 7 | ## 存储过程 8 | 9 | 1. 索引 添加索引 10 | ALTER TABLE student ADD INDEX index_name(sname); 删除索引 11 | DROP INDEX index_name ON student; 添加全文索引 12 | ALTER TABLE student add FULLTEXT INDEX index_name(sname); 13 | 查看设计SQL语句 14 | show CREATE TABLE student; 2. 视图 根据查询结果生成一张新表 15 | 16 | create table student_last(select * from student order by id desc limit 5); 17 | 查看设计视图 18 | DESC student; 查询李丽的C语言成绩 SELECT student.sno,student.sname,course.cname,sc.grade FROM student INNER JOIN sc ON student.sno=sc.sno INNER JOIN course ON course.cno=sc.cno WHERE student.sname='李丽' AND course.cname='c' 建立学生成绩视图 CREATE VIEW view_stugrade AS SELECT student.sno,student.sname,course.cname,sc.grade FROM student INNER JOIN sc ON student.sno=sc.sno INNER JOIN course ON course.cno=sc.cno; ??不用视图完成把李丽的C语言成绩改成80-》》》》作业 在视图中查找李丽的C语言成绩 19 | SELECT * FROM view_stugrade WHERE sname='李丽' AND cname ='c'; 把李丽的C语言成绩改成80 20 | UPDATE view_stugrade SET grade=80 WHERE sname='李丽' AND cname ='c'; UPDATE sc set grade=90 WHERE id=6; 查看所有表和视图 21 | SHOW TABLES; 22 | 删除视图 23 | DROP VIEW view_stugrade; 3. 子查询 24 | 25 | 查询和李丽的C语言成绩相同的学生信息(利用视图) 26 | SELECT * FROM view_stugrade WHERE grade=(SELECT grade from view_stugrade WHERE sname='李丽' AND cname='c') AND sname NOT LIKE '李丽'; 27 | ??查询和李丽的C语言成绩相同的学生信息(不利用视图) 28 | SELECT student.sno,student.sname,course.cname,sc.grade FROM student INNER JOIN sc ON student.sno=sc.sno INNER JOIN course ON course.cno=sc.cno WHERE sc.grade=(SELECT sc.grade FROM student INNER JOIN sc ON student.sno=sc.sno INNER JOIN course ON course.cno=sc.cno WHERE student.sname='李丽' AND course.cname='c' ) AND student.sname <>'李丽' 查询李丽所有课程的成绩 29 | SELECT * FROM view_stugrade WHERE sname='李丽' AND cname in(SELECT cname from course) 查询李丽C 和 C++课程的成绩 30 | SELECT * FROM view_stugrade WHERE sname='李丽' AND cname in('c','c++') 31 | ??查询成绩比李丽最高分还要高的学生信息-1 SELECT * FROM view_stugrade WHERE grade>(SELECT MAX(grade) FROM view_stugrade WHERE sname='李丽') 查询成绩比李丽最低分要高的学生信息-1 32 | SELECT * FROM view_stugrade WHERE grade>(SELECT min(grade) FROM view_stugrade WHERE sname='李丽') 2. mysql 函数 33 | 创建函数 34 | USE school; CREATE FUNCTION fun_getage(str VARCHAR(12)) RETURNS CHAR(12) BEGIN RETURN(SELECT sage from student WHERE sname=str); END; 35 | 调用方法 SELECT fun_getage('李彤') 36 | 方法: 37 | 1. 必须有返回值 2. 返回值指定类型 RETURNS 3. 返回值通过 return USE school; 38 | delimiter && CREATE FUNCTION fun_getscore(nstr VARCHAR(12),cstr VARCHAR(12)) RETURNS INT BEGIN -- 申明变量 DECLARE sco INT; SET sco=0; SELECT grade INTO sco FROM view_stugrade WHERE sname=nstr AND cname=cstr; RETURN sco; END && SELECT fun_getscore('李丽','c') USE school; CREATE FUNCTION fun_ispass(nstr VARCHAR(12),cstr VARCHAR(12)) RETURNS CHAR(10) BEGIN -- 申明变量 DECLARE sco INT DEFAULT 0; DECLARE res CHAR(10) DEFAULT ''; SELECT grade INTO sco FROM view_stugrade WHERE sname=nstr AND cname=cstr; IF sco>60 and sco<100 THEN SET res='及格'; ELSEIF sco=100 then SET res='满分'; ELSE SET res='不及格'; END IF; RETURN res; END; SELECT fun_ispass('李丽','c') 4. 存储过程 39 | 40 | 创建存储过程 41 | CREATE PROCEDURE pro_test() BEGIN SELECT "ok"; END CALL pro_test() CREATE PROCEDURE pro_test1(IN n INT) BEGIN SELECT n*n; END CALL pro_test1(20) -- DECLARE a INT DEFAULT 20; -- CALL pro_test1(a);不可行 -- SET @a=20; CALL pro_test1(@a) CREATE PROCEDURE pro_test2(IN n INT,OUT m INT) BEGIN SET m=n*n; END SET @a=20; set @b=0; CALL pro_test2(@a,@b); SELECT @b; 42 | -- CREATE PROCEDURE pro_test3(INOUT n INT) BEGIN SET n=n*n; END set @a=20; CALL pro_test3(@a); SELECT @a; -- 43 | CREATE PROCEDURE pro_delstudent(in strname VARCHAR(12)) BEGIN DECLARE num VARCHAR(12) DEFAULT ''; SELECT sno INTO num FROM student WHERE sname=strname; DELETE FROM sc WHERE sno=num; DELETE FROM student WHERE sno=num; SELECT '删除成功'; END CALL pro_delstudent('李彤') -- 44 | CREATE PROCEDURE pro_loop(INOUT num DOUBLE) BEGIN DECLARE total DOUBLE DEFAULT 0; DECLARE i INT DEFAULT 0; WHILE i2000 THEN LEAVE my; END IF; SET i=i+1; END WHILE; SET num=total; END **带事务的存储过程****************** 46 | CREATE PROCEDURE pro_delstudent(in strname VARCHAR(12)) BEGIN DECLARE num VARCHAR(12) DEFAULT ''; SELECT sno INTO num FROM student WHERE sname=strname; DELETE FROM sc WHERE sno=num; DELETE FROM student WHERE sno=num; SELECT '删除成功'; END -- select * from user; start TRANSACTION; UPDATE user set money=money+1000 WHERE id=1; UPDATE user set money=money-1000 where id=2; ROLLBACK; COMMIT; 案例: 47 | 48 | delimiter && 49 | create procedure change_money(in sender varchar(255),in receiver varchar(255),in number DOUBLE,out result varchar(20)) 50 | begin 51 | declare acount DOUBLE DEFAULT 0; 52 | start TRANSACTION; 53 | update user set money=money-number where name=sender; 54 | select money into acount from user where name=sender; 55 | if acount<0 THEN 56 | set result='转账失败'; 57 | ROLLBACK; 58 | ELSE 59 | update user set money=money+number where name=receiver; 60 | set result='转账成功'; 61 | COMMIT; 62 | 63 | end if; 64 | 65 | 66 | end 67 | && 68 | 69 | set @send='tony'; 70 | set @receive='tom'; 71 | set @acount=300; 72 | 73 | set @res=''; 74 | 75 | call change_money(@send,@receive,@acount,@res); 76 | select @res; -------------------------------------------------------------------------------- /mysql/unit4-数据库优化-0.md: -------------------------------------------------------------------------------- 1 | 1. 如何选择服务器的类型? 2 | 3 | MySQL服务器配置窗口中各个参数的含义如下。 【Server Configuration Type】该选项用于设置服务器的类型。单击该选项右侧的向下按钮, 即可看到包括3个选项。 4 | 5 | 3个选项的具体含义如下: 6 | 1. Development Machine(开发机器):该选项代表典型个人用桌面工作站。假定机器上运行 着多个桌面应用程序。将MySQL服务器配置成使用最少的系统资源。 7 | 1. Server Machine (服务器):该选项代表服务器,MySQL服务器可以同其它应用程序一起 运行,例如FTP、email和web服务器。MySQL服务器配置成使用适当比例的系统资源。 8 | 1. DedicatedMySQL Server Machine (专用 MySQL 服务器):该选项代表只运行MySQL服务的服务器。假定运行没有运行其它应用程序。MySQL服务器配置成使用所有可用系统资源。作为初学者,建议选择【DevelopmentMachine】(开发者机器)选项,这样占用系统的资源 比较少。 9 | 2. MySQL中如何使用特殊字符? 10 | 11 | 诸如单引号(’),双引号("),反斜线()等符号,这些符号在MySQL中不能直接输入 使用,否则会产生意料之外的结果。在MySQL中,这些特殊字符称为转义字符,在输入时需要 以反斜线符号(’’)开头,所以在使用单引号和双引号时应分别输入(’)或者("),输入反 斜线时应该输入(),其他特殊字符还有回车符( ),换行符( ),制表符(ab),退格 符()等。在向数据库中插入这些特殊字符时,一定要进行转义处理。 12 | 3. MySQL如何执行区分大小写的字符串比较? 13 | 14 | 15 | 在Windows平台下,MySQL是不区分大小的,因此字符串比较函数也不区分大小写。如果 想执行区分大小写的比较,可以在字符串前面添加BINARY关键字。例如默认情况下,’a’=‘A’返回结果为1,如果使用BINARY关键字,BINARY’a’=‘A’结果为0,在区分大小写的情况下,’a’与’A’并不相同。 16 | 4. MySQL语句优化技巧 17 | 18 | MySQL数据库性能的优化是MySQL数据库发展的必经之路,MySQL数据库性能的优化也是MySQL数据库前进的见证,下面介绍下MySQL语句优化的一些小技巧: 19 | 1. 应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。 20 | 2. 对查询进行优化,应尽量避免全表扫描,首先应考虑在where及order by涉及的列上建立索引。 21 | 3. 应尽量避免在where子句中对字段进行null值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: 22 | 23 | select id from t where num is null 24 | 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: 25 | select id from t where num=0 26 | 4. 尽量避免在where子句中使用or来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如: 27 | 28 | select id from t where num=10 or num=20 29 | 可以这样查询: 30 | select id from t where num=10 31 | union all 32 | select id from t where num=20 33 | 5. 下面的查询也将导致全表扫描:(不能前置百分号) 34 | 35 | select id from t where name like ‘c%’ 36 | 若要提高效率,可以考虑全文检索。 37 | 6. in和not in也要慎用,否则会导致全表扫描,如: 38 | 39 | select id from t where num in(1,2,3) 40 | 对于连续的数值,能用between就不要用in了: 41 | select id from t where num between 1 and 3 42 | 7. 如果在where子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然 而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描: 43 | 44 | select id from t where num=@num 45 | 可以改为强制查询使用索引: 46 | select id from t with(index(索引名)) where num=@num 47 | 8. 应尽量避免在where子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如: 48 | 49 | select id from t where num/2=100 50 | 应改为: 51 | select id from t where num=100*2 52 | 9. 应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如: 53 | 54 | select id from t where substring(name,1,3)=’abc’–name以abc开头的id 55 | select id from t where datediff(day,createdate,’2005-11-30′)=0–’2005-11-30′生成的id 56 | 应改为: 57 | select id from t where name like ‘abc%’ 58 | select id from t where createdate>=’2005-11-30′ and createdate<’2005-12-1′ 59 | 10. 不要在where子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。 60 | 11. 在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。 61 | 12. 不要写一些没有意义的查询,如需要生成一个空表结构: 62 | 63 | select col1,col2 into #t from t where 1=0 64 | 这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样: 65 | create table #t(…) 66 | 13. 很多时候用exists代替in是一个好的选择: 67 | 68 | select num from a where num in(select num from b) 69 | 用下面的语句替换: 70 | select num from a where exists(select 1 from b where num=a.num) 71 | 14. 并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。 72 | 15. 索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert及update的效率,因为insert或update时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有 必要。 73 | 16. 应尽可能的避免更新 clustered 索引数据列,因为clustered索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新clustered索引数据列,那么需要考虑是否应将该索引建为clustered索引。 74 | 17. 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。 75 | 18. 尽可能的使用varchar/nvarchar代替char/nchar,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。 76 | 19、任何地方都不要使用select * from t,用具体的字段列表代替“*”,不要返回用不到的任何字段。 77 | 20. 尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。 78 | 21. 避免频繁创建和删除临时表,以减少系统表资源的消耗。 79 | 22. 临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。 80 | 23. 在新建临时表时,如果一次性插入数据量很大,那么可以使用select into代替create table,避免造成大量log,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。 81 | 24. 如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先truncate table,然后drop table,这样可以避免系统表的较长时间锁定。 82 | 25. 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。 83 | 26. 尽量避免大事务操作,提高系统并发能力。 84 | 85 | **总结:** 86 | 87 | 如何快速掌握MySQL? 88 | 89 | 1. 培养兴趣,夯实基础 90 | 91 | 对于MySQL的学习来说, SQL语句是其中最为基础的部分,很多操作都是通过SQL语句来实现的。所以在学习的过程中,要多编写SQL语句,对于同一个功能,使用不同的实现语句来完成,从而深刻理解其不同之处。 92 | 2. 及时学习新知识,多实践操作 93 | 94 | 数据库系统具有极强的操作性,需要多动手上机操作。在实际操作的过程中才能发现问题, 并思考解决问题的方法和思路,只有这样才能提高实战的操作能力。 -------------------------------------------------------------------------------- /mysql/unit5-数据库优化-索引.md: -------------------------------------------------------------------------------- 1 | ##1. 索引 2 | 3 | 1. 索引分类 4 | 5 | 简介 6 | MySQL目前主要有以下几种索引类型: 7 | 1. 普通索引 8 | 2. 唯一索引 9 | 3. 主键索引 10 | 4. 组合索引 11 | 5. 全文索引 12 | 13 | 2. 创建索引总览 14 | 15 | CREATE TABLE table_name[col_name data type] 16 | [unique|fulltext][index|key][index_name](col_name[length])[asc|desc] 17 | 18 | 1. unique|fulltext为可选参数,分别表示唯一索引、全文索引 19 | 2. index和key为同义词,两者作用相同,用来指定创建索引 20 | 3. col_name为需要创建索引的字段列,该列必须从数据表中该定义的多个列中选择 21 | 4. index_name指定索引的名称,为可选参数,如果不指定,默认col_name为索引值 22 | 5. length为可选参数,表示索引的长度,只有字符串类型的字段才能指定索引长度 23 | 6. asc或desc指定升序或降序的索引值存储 24 | 3. 索引类型 25 | 3. 普通索引 26 | 27 | ALTER TABLE jobs ADD INDEX(salary_max); 28 | CREATE INDEX index_salary_max ON jobs(salary_max) 29 | #删除索引 30 | ALTER TABLE jobs DROP INDEX index_salary_max 31 | 32 | 创建表的时候同时创建索引 33 | 34 | CREATE TABLE `table` ( 35 | `id` int(11) NOT NULL AUTO_INCREMENT , 36 | `title` char(255) CHARACTER NOT NULL , 37 | `content` text CHARACTER NULL , 38 | `time` int(10) NULL DEFAULT NULL , 39 | PRIMARY KEY (`id`), 40 | INDEX index_name (title(length)) 41 | ) 42 | 4. 唯一索引 43 | 44 | 与前面的普通索引类似,不同的就是:索引列的值必须唯一(比如可以在主键上建立唯一索引),但允许有空值。如果是组合索引,则列值的组合必须唯一。它有以下几种创建方式: 45 | 46 | CREATE UNIQUE INDEX unique_id ON jobs(id); 47 | ALTER TABLE jobs ADD UNIQUE(id); 48 | 49 | 4. 主键索引 50 | 51 | 是一种特殊的唯一索引,一个表只能有一个主键,不允许有空值。一般是在建表的时候同时创建主键索引: 52 | 53 | CREATE TABLE `table` ( 54 | `id` int(11) NOT NULL AUTO_INCREMENT , 55 | `title` char(255) NOT NULL , 56 | PRIMARY KEY (`id`) 57 | ); 58 | 4. 组合索引 59 | 60 | 指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用组合索引时遵循最左前缀集合 61 | 62 | ALTER TABLE `table` ADD INDEX name_city_age (name,city,age); 63 | 64 | 3. MYSQL order by排序与索引关系总结 65 | 66 | EXPLAIN sql 可以查看查询方式 67 | 1. 场景一(比较在有索引的情况下时间) 68 | 69 | CREATE INDEX index_salary_max ON jobs(salary_max); 70 | 71 | # 没有索引 72 | select * from jobs where salary_min=12000; 73 | select id,title,com_name from jobs where salary_min=12000; 74 | 75 | 76 | # 有索引 77 | select * from jobs where salary_max=12000; 78 | select id,title,com_name from jobs where salary_max=12000; 79 | 80 | 81 | 但是在下面两种情况下,查询就失去了索引的功能 82 | 83 | select * from jobs ORDER BY salary_max; 84 | select * from jobs ORDER BY salary_min; 85 | 86 | 下面的情况速度就更慢了哦 87 | 88 | select salary_max,id,com_name from jobs ORDER BY salary_max; 89 | select salary_min,id,com_name from jobs ORDER BY salary_min; 90 | 91 | 1. 如果索引了多列,要遵守最左前缀法则。所谓最左前列,指的是查询从索引的最左前列开始,并且不跳过索引中的列。 92 | 93 | CREATE INDEX index_salary_max ON jobs(com_id,publish_date); 94 | 95 | # 索引会起作用 96 | select salary_max,id,com_name from jobs where com_id='107045220'; 97 | 98 | select salary_max,id,com_name from jobs 99 | where com_id='107045220' and publish_date='2018-12-07 10:27:01'; 100 | 101 | # 索引不会起作用 102 | select salary_max,id,com_name from jobs where publish_date='2018-12-07 10:27:01'; 103 | 104 | 2. 当MySQL一旦估计检查的行数可能会”太多”,范围查找优化将不会被使用。 105 | 106 | #不会起作用 107 | EXPLAIN select salary_max,id,com_name from jobs where salary_max<20; 108 | 109 | 110 | #会起作用 111 | 112 | EXPLAIN select salary_max,id,com_name from jobs where salary_max<18000; 113 | 114 | >在应用中,可能不会碰到这么大的查询,但是应该避免这样的查 询出现: select uid from users where registered < 1295001384 115 | 116 | 3. 索引列不应该作为表达式的一部分,即也不能在索引列上使用函数 117 | 118 | # 不会起作用 119 | EXPLAIN select salary_max,id,com_name from jobs where ABS(salary_max)<20; 120 | 4. 尽量借用覆盖索引,减少select * from …语句使用 121 | 122 | # com_address 因为com_address没有索引,所以extra列为null 123 | EXPLAIN select salary_max,id,com_address from jobs where salary_max=20; 124 | 125 | # 因为id也有索引,所以所以extra列为Using index 126 | EXPLAIN select salary_max,id from jobs where salary_max=20; 127 | 128 | 129 | 130 | >第1句Extra中使用了Using index表示使用了覆盖索引。第3句也使用了覆盖索引,虽然ID不在索引uid_fuid索引列中,但是InnoDB二次索引(second index)叶子页的值就是PK值,不同于MyISAM。Extra部分的Using index表示应用了索引,不要跟type中的index混淆。第2句没有使用覆盖索引,因为fsex不在索引中。 131 | 132 | 5. ORDER BY子句,尽量使用Index方式排序,避免使用FileSort方式排序 133 | 134 | MySQL支持二种方式的排序,FileSort和Index,后者效率高,它指MySQL扫描索引本身完成排序。FileSort方式效率较低。ORDER BY满足以下情况,会使用Index方式排序: 135 | 136 | a)ORDER BY 语句使用索引最左前列。参见第1句 137 | 138 | b)使用Where子句与Order BY子句条件列组合满足索引最左前列。参见第2句. 139 | 以下情况, 140 | 141 | **会使用FileSort方式的查询** 142 | 143 | 1. 检查的行数过多,且没有使用覆盖索引。第3句,虽然跟第2句一样,order by使用了索引最左前列uid,但依然使用了filesort方式排序,因为status并不在索引中,所以没办法只扫描索引。 144 | 2. 使用了不同的索引,MySQL每回只采用一个索引.第4句,order by出现二个索引,分别是uid_fuid和聚集索引(pk) 145 | 3. 对索引列同时使用了ASC和DESC。 通过where语句将order by中索引列转为常量,则除外。第5句,和第6句在order by子句中,都出现了ASC和DESC排序,但是第5句却使用了filesort方式排序,是因为第6句where uid取出排序需要的数据,MySQL将其转为常量,它的ref列为const。 146 | 4. where语句与order by语句,使用了不同的索引。参见第7句。 147 | 5. where语句或者ORDER BY语句中索引列使用了表达式,包括函数表达式。参见第8,9句 148 | 6. where 语句与ORDER BY语句组合满足最左前缀,但where语句中使用了条件查询。查见第10句,虽然where与order by构成了索引最左有缀的条件,但是where子句中使用的是条件查询。 149 | 7. order by子句中加入了非索引列,且非索引列不在where子句中。 150 | 8. order by或者它与where组合没有满足索引最左前列。参见第11句和12句,where与order by组合,不满足索引最左前列. (uid, fsex)跳过了fuid 151 | 9. 当使用left join,使用右边的表字段排序。参见第13句,尽管user.uid是pk,依然会使用filesort排序。 152 | 153 | 7. 慎用left join语句,避免创建临时表 使用left join语句的时候,避免出现创建临时表。尽量不要用left join,分而治之。非要使用的时候,要询问自己是不是真要必须要使用。 154 | 8. 高选择性索引列。 尽量使用高选择性的过引来过滤数据。高选择性指Cardinality/#T越接近1,选择性越高,其中Cardinality指表中索引列不重复值(行)的总数。PK和唯一索引,具有最高的选择性,即1。推荐可选性达到20%以上。 155 | 9. 谨防where子句中的OR。where语句使用or,且没有使用覆盖索引,会进行全表扫描。应该尽量避免这样OR语句。尽量使用UNION代替OR 156 | 10. LIMIT与覆盖索引 limit子句,使用覆盖索引时比没有使用覆盖索引会快很多 157 | 158 | 参考:http://www.cnblogs.com/wangxusummer/p/5329813.html 159 | 4. 全文索引 160 | 161 | 1. 概述 162 | 163 | MySQL全文检索是利用查询关键字和查询列内容之间的相关度进行检索,可以利用全文索引来提高匹配的速度。 164 | 165 | 166 | 2. 语法 167 | 168 | SELECT * FROM tab_name WHERE MATCH ('列名1,列名2...列名n') AGAINST('词1 词2 词3 ... 词m'); 169 | 170 | SELECT * FROM jobs 171 | WHERE MATCH (com_name) AGAINST('上海寰享网络科技有限公司'); 172 | 173 | **col1、col2 必须是char、varchar或text类型,在查询之前需要在 col1 和 col2 上分别建立全文索引(FULLTEXT索引)。** 174 | 3. dd 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | #### 缺点 185 | 1. 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行insert、update和delete。因为更新表时,不仅要保存数据,还要保存一下索引文件。 186 | 2. 建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但如果你在一个大表上创建了多种组合索引,索引文件的会增长很快。 187 | 188 | 索引只是提高效率的一个因素,如果有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询语句。 -------------------------------------------------------------------------------- /python/01-part1/images/var.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhanforgit/python/2fc2d72bc7b08f3da8886d04150c7b918994ae28/python/01-part1/images/var.png -------------------------------------------------------------------------------- /python/01-part1/images/变量类型.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhanforgit/python/2fc2d72bc7b08f3da8886d04150c7b918994ae28/python/01-part1/images/变量类型.jpg -------------------------------------------------------------------------------- /python/01-part1/python基础语法-全部.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhanforgit/python/2fc2d72bc7b08f3da8886d04150c7b918994ae28/python/01-part1/python基础语法-全部.pdf -------------------------------------------------------------------------------- /python/01-part1/unit1-环境搭建.md: -------------------------------------------------------------------------------- 1 | # 环境搭建 2 | ### 1.python简介 3 | Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 4 | 5 | Python 的设计具有很强的可读性,相比其他语言经常使用英文关键字,其他语言的一些标点符号,它具有比其他语言更有特色语法结构。 6 | 7 | * Python 是一种解释型语言: 这意味着开发过程中没有了编译这个环节。类似于PHP和Perl语言。 8 | 9 | * Python 是交互式语言: 这意味着,您可以在一个Python提示符,直接互动执行写你的程序。 10 | 11 | * Python 是面向对象语言: 这意味着Python支持面向对象的风格或代码封装在对象的编程技术。 12 | 13 | * Python 是初学者的语言:Python 对初级程序员而言,是一种伟大的语言,它支持广泛的应用程序开发,从简单的文字处理到 WWW 浏览器再到游戏。 14 | 15 | ### 2. python安装 16 | **Python下载** 17 | Python最新源码,二进制文档,新闻资讯等可以在Python的官网查看到: 18 | 19 | Python官网:https://www.python.org/ 20 | 21 | 你可以在以下链接中下载 Python 的文档,你可以下载 HTML、PDF 和 PostScript 等格式的文档。 22 | 23 | Python文档下载地址:https://www.python.org/doc/ 24 | 25 | 1. windows安装 26 | 27 | 在 Window 平台上安装 Python 的简单步骤: 28 | 29 | 打开 WEB 浏览器访问https://www.python.org/downloads/windows/ 30 | 在下载列表中选择Window平台安装包,包格式为:python-XYZ.msi 文件 , XYZ 为你要安装的版本号。 31 | 要使用安装程序 python-XYZ.msi, Windows系统必须支持Microsoft Installer 2.0搭配使用。只要保存安装文件到本地计算机,然后运行它,看看你的机器支持MSI。Windows XP和更高版本已经有MSI,很多老机器也可以安装MSI。 32 | 下载后,双击下载包,进入Python安装向导,安装非常简单,你只需要使用默认的设置一直点击"下一步"直到安装完成即可。 33 | 34 | **设置环境变量** 35 | 在环境变量中添加Python目录: 36 | win10默认的安装目录:C:\users\用户名\AppData\Local\Programe\python\pythonx.x 37 | 38 | 在命令提示框中(cmd) : 输入 39 | 40 | ``` 41 | path=%path%;C:\Python 按下"Enter"。 42 | ``` 43 | >注意: C:\Python 是Python的安装目录。 44 | 45 | 也可以通过以下方式设置: 46 | 47 | * 右键点击"计算机",然后点击"属性" 48 | * 然后点击"高级系统设置" 49 | * 选择"系统变量"窗口下面的"Path",双击即可! 50 | * 然后在"Path"行,添加python安装路径即可(我的D:\Python32),所以在后面,添加该路径即可。 ps:记住,路径直接用分号";"隔开! 51 | * 最后设置成功以后,在cmd命令行,输入命令"python",就可以有相关显示。 52 | 53 | 2. Mac安装 54 | >最近的Macs系统都自带有Python环境,你也可以在链接 https://www.python.org/downloads/mac-osx/ 上下载最新版安装。 55 | 56 | 两个个版本的路径如下: 57 | 58 | * python2.7的路径为:/System/Library/Frameworks/Python.framework/Versions/2.7 59 | * python3.6的路径为:/Library/Frameworks/Python.framework/Versions/3.6 60 | 61 | 查看python路径的两种方法(以python3.6为例): 62 | 63 | ``` 64 | which python3.6 65 | #或者 66 | where python 67 | ``` 68 | # pip 安装 69 | https://pip.pypa.io/en/latest/user_guide/ 70 | 71 | 1. 安装pip 72 | 73 | 1. pip官网下载链接(https://pypi.python.org/pypi/pip#downloads) 74 | 2. 解压缩上面pip.x.x.tar.gz文件,打开CMD,进入解压缩后文件的根目录,该目录中有一个setup.py文件,然后再cmd中输入python setup.py install命令 75 | 76 | 2. 安装目录 77 | 78 | Windwos 79 | **pip安装目录:** 80 | C:\users\用户名\AppData\Local\Programe\python\pythonx.x\Scripts 81 | **模块安装目录:** 82 | C:\users\用户名\AppData\Local\Programe\python\pythonx.x\lib\site-packages 83 | 84 | Mac 85 | ​ **pip安装目录:** 86 | /Library/Frameworks/Python.framework/Versions/3.6/bin 87 | **模块安装目录:** 88 | /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages 89 | 90 | 3. 更新pip 91 | 4. 92 | python -m pip install -U --force reinstall pip 93 | 2. 安装组件 94 | 95 | ``` 96 | pip install XXXX 97 | ``` 98 | 我们可以通过这个网站查看自己所需的Python包及相关依赖的包,http://www.lfd.uci.edu/~gohlke/pythonlibs/ 99 | 3. 查看安装组件列表 100 | 101 | ``` 102 | pip list 103 | ``` 104 | >如果出现以下错误信息: 105 | >DEPRECATION: The default format will switch to columns in the future. You can use --format=(legacy|columns) (or define a format=(legacy|columns) in your pip.conf under the [list] section) to disable this warning. 106 | 107 | **需要修改配置文件pip.conf** 108 | 109 | ``` 110 | [list] 111 | format=columns 112 | ``` 113 | 114 | **要列出过时的软件包并显示可用的最新版本:** 115 | 116 | ``` 117 | $ pip list --outdated 118 | ``` 119 | 120 | **要显示已安装软件包的详细信息** 121 | 122 | ``` 123 | $ pip show sphinx 124 | ``` 125 | 4. 配置pip 126 | 127 | 1. 每个用户: 128 | 129 | * 在Unix上,默认配置文件是:$HOME/.config/pip/pip.conf 它尊重XDG_CONFIG_HOME环境变量。 130 | * 在macOS上,配置文件 是否存在其他目录。$HOME/Library/Application Support/pip/pip.conf$HOME/Library/Application Support/pip$HOME/.config/pip/pip.conf 131 | * 在Windows上,配置文件是%APPDATA%\pip\pip.ini。 132 | 133 | 134 | 2. 还有一个传统的每用户配置文件也受到尊重,它们位于: 135 | 136 | * 在Unix和MacOS上,配置文件是: $HOME/.pip/pip.conf 137 | * 在Windows上,配置文件是: %HOME%\pip\pip.ini 138 | 139 | 3. 您可以使用环境变量为此配置文件设置自定义路径位置PIP_CONFIG_FILE。 140 | 141 | 在virtualenv里面: 142 | 143 | 在Unix和MacOS上,文件是 $VIRTUAL_ENV/pip.conf 144 | 在Windows上,该文件是: %VIRTUAL_ENV%\pip.ini 145 | 4. 整个网站: 146 | 147 | * 在Unix上,该文件可能位于/etc/pip.conf。或者,它可能位于环境变量XDG_CONFIG_DIRS(如果存在)中 设置的任何路径的“pip”子目录中/etc/xdg/pip/pip.conf。 148 | * 在macOS上,该文件是: /Library/Application Support/pip/pip.conf 149 | * 在Windows XP上,该文件是: C:\Documents and Settings\All Users\Application Data\pip\pip.ini 150 | * 在Windows 7及更高版本中,该文件被隐藏,但可以在此处写入 C:\ProgramData\pip\pip.ini 151 | * Windows Vista不支持站点范围的配置 152 | 153 | **如果通过点找到多个配置文件,那么它们按以下顺序组合:** 154 | 155 | 1. 首先读取站点范围的文件,然后 156 | 2. 读取每个用户文件,最后 157 | 3. 读取virtualenv专用文件。 158 | 159 | >每个文件读取覆盖从以前的文件读取的任何值,所以如果在站点范围文件和每个用户文件中都指定了全局超时,那么后一个值就是将要使用的值。 160 | 161 | 162 | # virtualenv 安装 163 | ### 1. 安装 164 | 在开发Python应用程序的时候,所有第三方的包都会被pip安装到Python3的site-packages目录下。 165 | 每个应用可能需要各自拥有一套“独立”的Python运行环境。virtualenv就是用来为一个应用创建一套“隔离”的Python运行环境。 166 | 首先,我们用pip安装virtualenv: 167 | 168 | ``` 169 | $ pip3 install virtualenv 170 | ``` 171 | >备注的部分 172 | 173 | ### 2. 创建项目 174 | 第一步,创建目录 175 | 第二步,创建一个独立的Python运行环境,命名为venv: 176 | 177 | ``` 178 | Mac:myproject michael$ virtualenv --no-site-packages venv 179 | ``` 180 | 可以指定python版本: 181 | ubuntu:sudo virtualenv -p python3 --no-site-packages venv 182 | ubuntu:sudo virtualenv -p python3 --system-site-packages venv 183 | 184 | **注意:** 185 | 186 | **如果出现错误:** 187 | 188 | Traceback (most recent call last): 189 | File "/home/lzhan/.local/lib/python2.7/site-packages/ virtualenv.py", line 22, in 190 | import distutils.spawn 191 | ModuleNotFoundError: No module named 'distutils.spawn' 192 | 193 | 194 | **则需要安装** 195 | 196 | sudo apt-get install python3-distutils 197 | 198 | >命令virtualenv就可以创建一个独立的Python运行环境,我们还加上了参数--no-site-packages,这样,已经安装到系统Python环境中的所有第三方包都不会复制过来,这样,我们就得到了一个不带任何第三方包的“干净”的Python运行环境。 199 | 200 | 第三步,新建的Python环境被放到当前目录下的venv目录。有了venv这个Python环境,可以用source进入该环境: 201 | 202 | ``` 203 | Mac:myproject michael$ source venv/bin/activate 204 | ``` 205 | >注意到命令提示符变了,有个(venv)前缀,表示当前环境是一个名为venv的Python环境。 206 | >在venv环境下,用pip安装的包都被安装到venv这个环境下,系统Python环境不受任何影响。也就是说,venv环境是专门针对myproject这个应用创建的。 207 | 208 | 第四步,退出当前的venv环境,使用deactivate命令: 209 | 210 | ``` 211 | (venv)Mac:myproject michael$ deactivate 212 | ``` 213 | ### 3. PyCharm 配置 214 | 215 | file->setting->project interpreter->add local 216 | 217 | 218 | 219 | -------------------------------------------------------------------------------- /python/01-part1/unit2-语法基础.md: -------------------------------------------------------------------------------- 1 | # 基础语法 2 | 1. python全景 3 | 4 | 1. 程序由模块组成 5 | 2. 模块包含语句 6 | 3. 语句包含表达式 7 | 4. 表达式建立并处理对象 8 | 9 | 2. hello world 10 | 3. 注释 11 | 4. 单行注释 12 | 13 | ``` 14 | #注释的内容 15 | ``` 16 | 5. 多行注释 17 | 18 | python 中多行注释使用三个单引号(''')或三个双引号(""") 19 | 20 | ``` 21 | ''' 22 | 注释内容第一行 23 | 注释内容第二行 24 | ''' 25 | ``` 26 | 1. 中文编码 27 | 28 | 只要在文件开头加入 # -*- coding: UTF-8 -*- 或者 #coding=utf-8 就行了 29 | 30 | ``` 31 | # -*- coding: UTF-8 -*- 32 | ``` 33 | >Python3.X 源码文件默认使用utf-8编码,所以可以正常解析中文,无需指定 UTF-8 编码。 34 | 35 | >如果你使用编辑器,同时需要设置 py 文件存储的格式为 UTF-8.设置路径:file / setting / editor / file encodings 36 | 2. 交互式编程 37 | 38 | 在命令行中输入python即可 39 | 4. 行和缩进 40 | 41 | 学习 Python 与其他语言最大的区别就是,Python 的代码块不使用大括号 {} 来控制类,函数以及其他逻辑判断。python 最具特色的就是用缩进来写模块。 42 | 43 | 缩进的空白数量是可变的,但是所有代码块语句必须包含相同的缩进空白数量,这个必须严格执行。 44 | >建议你在每个缩进层次使用 单个制表符 或 两个空格 或 四个空格 , 切记不能混用 45 | 5. 多行语句 46 | 47 | Python语句中一般以新行作为语句的结束符。 48 | 49 | 但是我们可以使用斜杠( \)将一行的语句分为多行显示,如下所示: 50 | 51 | ``` 52 | total = item_one + \ 53 | item_two + \ 54 | item_three 55 | 56 | ``` 57 | 语句中包含 [], {} 或 () 括号就不需要使用多行连接符。如下实例: 58 | 59 | ``` 60 | days = ['Monday', 'Tuesday', 'Wednesday', 61 | 'Thursday', 'Friday'] 62 | ``` 63 | 7. 输入和输出 64 | 65 | 输入 66 | 67 | ``` 68 | #python2.x 69 | raw_input("按下 enter 键退出,其他任意键显示...\n") 70 | 71 | #python3.x 72 | input("按下 enter 键退出,其他任意键显示...\n") 73 | ``` 74 | **注意在python2.x中** 75 | * input返回的是数值类型,如int,float 76 | * input会计算在字符串中的数字表达式,而raw_input不会 77 | * raw_inpout返回的是字符串类型,string类型’ 78 | 79 | 80 | 输出 81 | 82 | print() 默认输出是换行的,如果要实现不换行需要在变量末尾加上逗号 , 83 | 84 | ``` 85 | age = 18 86 | name = "xiaoming" 87 | print("我的姓名是%s,年龄是%d"%(name,age)) 88 | print("我的姓名是',name,'年龄是',age) 89 | 90 | ``` 91 | 常用的格式符号 92 | 93 | 格式符号|转换| 94 | ---|---| 95 | %s| 通过str() 字符串转换来格式化| 96 | %d| 有符号十进制整数| 97 | %f| 浮点实数| 98 | 99 | 9. demo 100 | 101 | 输出一张个人名片 102 | 103 | ``` 104 | ''' 105 | # 用户名输入姓名 106 | name=input('请输入你的姓名') 107 | # 用户名输入电话 108 | tel=input('请输入你的电话号码') 109 | # 用户输入公司名称 110 | com=input('请输入你的公司名称') 111 | 112 | # 打印名片 113 | print('=======================') 114 | print('姓 名:%s'%name) 115 | print('电 话:%s'%tel) 116 | print('公司名称:%s'%com) 117 | print('=======================') 118 | ''' 119 | ``` 120 | 121 | 8. 执行脚本传入参数 122 | 123 | ``` 124 | import sys 125 | sys.path 126 | print sys.argv 127 | ``` 128 | >sys.argv[0] 代表文件本身路径,所带参数从 sys.argv[1] 开始。 129 | 130 | 脚本语言的第一行,目的就是指出,你想要你的这个文件中的代码用什么可执行程序去运行它,就这么简单。 131 | 132 | * \#!/usr/bin/python : 是告诉操作系统执行这个脚本的时候,调用 /usr/bin 下的 python 解释器; 133 | 134 | * \#!/usr/bin/env python(推荐): 这种用法是为了防止操作系统用户没有将 python 装在默认的 /usr/bin 路径里。当系统看到这一行的时候,首先会到 env 设置里查找 python 的安装路径,再调用对应路径下的解释器程序完成操作。 135 | 136 | * \#!/usr/bin/python 相当于写死了python路径; 137 | 138 | * \#!/usr/bin/env python 会去环境设置寻找 python 目录,推荐这种写法 139 | 140 | 141 | -------------------------------------------------------------------------------- /python/01-part1/unit3-queue.md: -------------------------------------------------------------------------------- 1 | # queue 2 | 3 | 4 | 1. 特性 5 | 6 | Queue是python中的标准库,可以直接 7 | 8 | import queue 9 | 10 | 队列是线程间最常用的交换数据的形式 11 | 12 | 2. 方法 13 | 14 | 1. 初始化 15 | 16 | import queue 17 | q=queue.Queue(10) 构建长度为10的队列 18 | 19 | q = queue.Queue(maxsize=3) 20 | 21 | 2. 包中的常用方法: 22 | 23 | Queue.qsize() 返回队列的大小 24 | 25 | Queue.empty() 如果队列为空,返回True,反之False 26 | 27 | Queue.full() 如果队列满了,返回True,反之False 28 | 29 | Queue.full 与 maxsize 大小对应 30 | 31 | Queue.get([block[, timeout]])获取队列,timeout等待时间 32 | 33 | 3. 将一个值放入队列中 34 | 35 | myqueue.put(10) 36 | put(item[, block[, timeout]]) 37 | 38 | 将item放入队列中。 39 | 40 | 如果可选的参数block为True且timeout为空对象(默认的情况,阻塞调用,无超时)。 41 | 42 | 如果timeout是个正整数,阻塞调用进程最多timeout秒,如果一直无空空间可用,抛出Full异常(带超时的阻塞调用)。 43 | 44 | 如果block为False,如果有空闲空间可用将数据放入队列,否则立即抛出Full异常 45 | 其非阻塞版本为put_nowait等同于put(item, False) 46 | 47 | 48 | 49 | 4. 将一个值从队列中取出 50 | 51 | myqueue.get() 52 | 53 | 54 | demo 55 | 56 | import queue 57 | 58 | q = queue.Queue(maxsize=3) 59 | 60 | for i in range(3): 61 | q.put(i) 62 | 63 | while not q.empty(): 64 | print(q.get()) 65 | 66 | 67 | 5. task_done() 68 | 69 | 意味着之前入队的一个任务已经完成。由队列的消费者线程调用。每一个get()调用得到一个任务,接下来的task_done()调用告诉队列该任务已经处理完毕。 70 | 71 | 如果当前一个join()正在阻塞,它将在队列中的所有任务都处理完时恢复执行(即每一个由put()调用入队的任务都有一个对应的task_done()调用)。 -------------------------------------------------------------------------------- /python/01-part1/unit3-变量类型-Dictionary.md: -------------------------------------------------------------------------------- 1 | # 变量类型-Dictionary 2 | 1. 类型 3 | 字典的每个键值 key=>value 对用冒号 : 分割,每个键值对之间用逗号 , 分割,整个字典包括在花括号 {} 中. 4 | 5 | 键一般是唯一的,如果重复最后的一个键值对会替换前面的,值不需要唯一。 6 | 7 | 2. 特性 8 | 9 | 和list和tuple一样,dictionary也可以: 10 | 11 | ``` 12 | char={item:ord(item) for item in 'python'} 13 | 14 | print(char) 15 | ``` 16 | 17 | 3. 字典访问 18 | 19 | ``` 20 | user={ 21 | 'name':{'firstName':'zhan','lastName':'liang'}, 22 | 'age':20, 23 | 'address':'usa', 24 | 'hobby':['film','sport'] 25 | } 26 | 27 | print('user length:',len(user)) 28 | 29 | print('user first property is :',user['name']) 30 | 31 | for key,value in user.items(): 32 | print ('property %s value %s' % (key,value)) 33 | 34 | for kk in user.keys(): 35 | print ('property %s' % (kk)) 36 | 37 | for vv in user.values(): 38 | print ('values %s' % (vv)) 39 | 40 | ``` 41 | 42 | 如果想根据key的先后顺序遍历字典,则可以: 43 | 44 | ``` 45 | for kk in sorted(user.keys()): 46 | print ('property %s' % (kk)) 47 | ``` 48 | 4. 针对不存在的键,如果访问会出现错误。 49 | 50 | ``` 51 | nation=user['nation'] #error 52 | 53 | nation=user['nation'] if 'nation' in user else 'china' 54 | ``` 55 | 5. dict,bytes,string之间的相互转化 56 | 57 | ``` 58 | s='{"id":"001","name":"python"}' 59 | # s='http://www/163.com' 60 | #string to bytes 61 | s_bytes_utf8=s.encode('utf-8') 62 | print(s_bytes_utf8) 63 | 64 | # bytes to string 65 | s_string_utf8=s_bytes_utf8.decode('utf-8') 66 | print(s_string_utf8) 67 | 68 | # string to dict 69 | s_dict=eval(s_string_utf8) 70 | 71 | print(s_dict['id']) 72 | 73 | # dict to string 74 | 75 | s_string=str(s_dict) 76 | 77 | print(s_string) 78 | 79 | 80 | 81 | ``` 82 | 83 | 84 | 6. 字典方法 85 | 86 | D.clear() #移除D中的所有项 87 | D.copy() #返回D的副本 88 | D.fromkeys(seq[,val]) #返回从seq中获得的键和被设置为val的值的字典。可做类方法调用 89 | D.get(key[,default]) #如果D[key]存在,将其返回;否则返回给定的默认值None 90 | D.has_key(key) #检查D是否有给定键key 91 | D.items() #返回表示D项的(键,值)对列表 92 | D.iteritems() #从D.items()返回的(键,值)对中返回一个可迭代的对象 93 | D.iterkeys() #从D的键中返回一个可迭代对象 94 | D.itervalues() #从D的值中返回一个可迭代对象 95 | D.keys() #返回D键的列表 96 | D.pop(key[,d]) #移除并且返回对应给定键key或给定的默认值D的值 97 | D.popitem() #从D中移除任意一项,并将其作为(键,值)对返回 98 | D.setdefault(key[,default]) #如果D[key]存在则将其返回;否则返回默认值None 99 | D.update(other) #将other中的每一项加入到D中。 100 | D.values() #返回D中值的列表 101 | 102 | https://www.cnblogs.com/mxh1099/p/8512552.html -------------------------------------------------------------------------------- /python/01-part1/unit3-变量类型-List.md: -------------------------------------------------------------------------------- 1 | # 变量类型-List 2 | 1. list 3 | 4 | 5 | 列表的数据项不需要具有相同的类型 6 | List(列表) 是 Python 中使用最频繁的数据类型。 7 | 列表可以完成大多数集合类的数据结构实现。它支持字符,数字,字符串甚至可以包含列表(即嵌套。 8 | 5. 列表取值 9 | 10 | 11 | 列表用 [ ] 标识,是 python 最通用的复合数据类型。 12 | 列表中值的切割也可以用到变量 [头下标:尾下标] ,就可以截取相应的列表,从左到右索引默认 0 开始,从右到左索引默认 -1 开始,下标可以为空表示取到头或尾。 13 | 14 | 加号 + 是列表连接运算符,星号 * 是重复操作。 15 | 16 | ``` 17 | list=[1,3,5,7,9,11] 18 | print list # 输出完整列表 19 | print list[:] 20 | print list[0] # 输出列表的第一个元素 21 | prnit list[-1] # 输出列表的最后一个元素 22 | print list[1:3] # 输出第二个至第三个元素 23 | print list[2:] # 输出从第三个开始至列表末尾的所有元素 24 | print list[:5] 25 | print tinylist * 2 # 输出列表两次 26 | print list + tinylist # 打印组合的列表 27 | 28 | for item in range(len(arr)): 29 | print(arr(item)) 30 | 31 | for item in arr: 32 | print(item) 33 | ``` 34 | 2. list 操作 35 | 36 | ``` 37 | fruits = ['orange', 'apple', 'pear', 'banana'] 38 | 39 | # 统计 40 | # print (fruits.count('apple')) 41 | # 判断是否存在 42 | # print (fruits.index('apple')) #如果没有找到会异常 43 | # print ('apple' in fruits) 44 | 45 | 46 | # 从第三个位置开始寻找 47 | # print (fruits.index('apple',3)) 48 | # fruits.reverse() 49 | # fruits.sort() 50 | 51 | # 增加元素 52 | # fruits.append('kiwi') 53 | # 增加集合 54 | # fruits.extend(['kiwi','water']) 55 | # 合并两个列表 56 | # new_fruits=fruits+['kiwi','water'] 57 | # 插入元素 58 | # fruits.insert(0,'pick'); 59 | 60 | # 删除元素 61 | # fruits.remove('apple') 62 | # fruits.remove(fruits[2]) 63 | # del fruits[1] 64 | # 删除单个元素 65 | # fruits[1:2]=[] 66 | # 删除多个元素 67 | # fruits[2:4]=[] 68 | # 删除聊表末尾的元素 69 | # fruits.pop() 70 | # fruits.pop(index) 71 | 72 | # 替换元素 73 | # fruits[0:3]=['橙子','苹果','梨'] 74 | 75 | # 拷贝 76 | ff=fruits[:] 77 | fff=fruits.copy() 78 | # 清空元素 79 | # fruits.clear() 80 | # del fruits[:] #不同于del fruits 81 | # fruits[ : ]=[] 82 | 83 | # 判断是否存在 84 | # print('apple' in fruits) 85 | 86 | # 最大最小值 87 | # print(max(fruits)) 88 | # print(min(fruits)) 89 | ``` 90 | 91 | 3. 栈和队列 92 | 93 | ``` 94 | #!/Users/lzhan/Lzhan/python/project/unit2 95 | # -*- coding: UTF-8 -*- 96 | from collections import deque 97 | fruits = ['orange', 'apple', 'pear', 'banana'] 98 | # from collections import deque 99 | # 100 | queue = deque(fruits) 101 | 102 | # 先进先出 103 | queue.append('haha') 104 | queue.popleft() 105 | 106 | # 先进后出 107 | queue.append('') 108 | queue.pop() 109 | 110 | print(list(queue)) 111 | ``` 112 | 113 | 4. 列表初始化 114 | 115 | ``` 116 | squares=[] 117 | squares=[x**2 for x in range(10)] 118 | vec = [-4, -2, 0, 2, 4] 119 | vec2=[x*2 for x in vec] 120 | vec3=[x for x in vec if x >= 0] 121 | vec4=[abs(x) for x in vec] 122 | 123 | print ([(x, x**2) for x in range(6)]) 124 | ``` 125 | 126 | ``` 127 | squares=[] 128 | squares=list(map(lambda x: x**3, range(10))) 129 | lists=[(x, y) for x in [1,2,3] for y in [3,1,4] if x != y] 130 | # [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)] 131 | ``` 132 | **补充:map()** 133 | 134 | map() 会根据提供的函数对指定序列做映射。 135 | 136 | 第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。 137 | 138 | 139 | ``` 140 | map(function, iterable, ...) 141 | ``` 142 | 143 | 返回值 144 | Python 2.x 返回列表。 145 | 146 | Python 3.x 返回迭代器。 147 | 148 | ``` 149 | arr=[1,2,3,4] 150 | 151 | mm=map(lambda x:x ** 2,arr) 152 | print(next(mm)) 153 | 154 | for res in mm: 155 | print(res) 156 | 157 | ``` 158 | 去掉列表元素单词左右空格 159 | 160 | 161 | ``` 162 | # freshfruit = [' banana', ' loganberry ', 'passion fruit '] 163 | # 164 | # # 去掉单词左右空格 165 | # freshfruit=[weapon.strip() for weapon in freshfruit] 166 | ``` 167 | 168 | 读取二维数组 169 | 170 | ``` 171 | vec = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 172 | 173 | list1=[num for elem in vec for num in elem] 174 | list2=[[elem[i] for elem in vec] for i in range(3)] 175 | print(list2) 176 | ``` 177 | 1. -------------------------------------------------------------------------------- /python/01-part1/unit3-变量类型-Numbers.md: -------------------------------------------------------------------------------- 1 | # 变量类型-Numbers 2 | 1. del 3 | 4 | ``` 5 | num=1 6 | mum=2 7 | del num,mum 8 | print(mum) 9 | ``` 10 | 2. Python math 模块、cmath 模块 11 | 12 | 13 | Python 中数学运算常用的函数基本都在 math 模块、cmath 模块中。 14 | 15 | Python math 模块提供了许多对浮点数的数学运算函数。 16 | 17 | Python cmath 模块包含了一些用于复数运算的函数。 18 | 19 | cmath 模块的函数跟 math 模块函数基本一致,区别是 cmath 模块运算的是复数,math 模块运算的是数学运算。 20 | 21 | 要使用 math 或 cmath 函数必须先导入: 22 | 23 | ``` 24 | import math 25 | #查看 math 查看包中的内容: 26 | dir(math) 27 | ``` 28 | 数学函数 29 | 30 | ``` 31 | import math,cmath 32 | import random 33 | print(dir(math)) 34 | print(dir(cmath)) 35 | a=-12.57 36 | b=1.9 37 | 38 | print(math.fabs(a)) 39 | print(math.floor(a)) 40 | # 截断小数位 41 | print(math.trunc(a)) 42 | print(math.ceil(a)) 43 | print(math.radians(a)) 44 | 45 | rana=random.choice(range(10)) 46 | print(rana) 47 | 48 | ranb=random.randrange(0,500,5) 49 | print(ranb) 50 | 51 | ranc=random.random() 52 | 53 | print(ranc) 54 | 55 | arr=[1,2,3,4,5,6,7] 56 | #将序列的所有元素随机排序 57 | random.shuffle(arr) 58 | 59 | print(arr) 60 | 61 | 62 | ``` 63 | ``` 64 | >>> range(1,5) # 代表从1到5(不包含5) 65 | [1, 2, 3, 4] 66 | >>> range(1,5,2) # 代表从1到5,间隔2(不包含5) 67 | [1, 3] 68 | >>> range(5) # 代表从0到5(不包含5) 69 | [0, 1, 2, 3, 4] 70 | ``` 71 | >cmp(x, y) 函数在 python3.x 中不可用,可用以下函数替代: 72 | 73 | ``` 74 | s='a' 75 | n=98 76 | print(ord(s)) # convert char to int 77 | print(chr(n)) # convert int to char 78 | ``` 79 | 80 | >1、abs()是一个内置函数,而fabs()在math模块中定义的。 81 | >2、fabs()函数只适用于float和integer类型,而 abs() 也适用于复数。 82 | 83 | 84 | 3. decimal 85 | 86 | ``` 87 | import decimal 88 | #prec 保留三位小数 89 | decimal.getcontext().prec=3 90 | m=2.0 91 | n=3.0 92 | 93 | d=decimal.Decimal(m)/decimal.Decimal(n) 94 | 95 | print(d) 96 | 97 | #如果是浮点数,保留3位小数 98 | 99 | pi=3.1415926 100 | 101 | print(round(pi,3)) 102 | ``` 103 | 4. 分数计算 104 | 105 | ``` 106 | from fractions import Fraction 107 | f=Fraction(3,5) #3/5 108 | f=f+1 #3/5+1=8/5 109 | 110 | f=f+Fraction(1,2) 111 | print(f) 112 | ``` 113 | 114 | 5. bool 115 | 116 | ``` 117 | x,y=3>2,3>5 118 | 119 | print(x,y) # True False 120 | 121 | print(bool('')) #False 122 | 123 | ``` 124 | 6. None 125 | 126 | ``` 127 | obj=None 128 | print(obj) 129 | ``` 130 | 131 | 7. type() 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /python/01-part1/unit3-变量类型-Set.md: -------------------------------------------------------------------------------- 1 | # 变量类型-Set 2 | 3 | 4 | 1. 特性 5 | 6 | set是一个无序且不重复的元素集合。 7 | 8 | 集合对象是一组无序排列的可哈希的值,集合成员可以做字典中的键。集合支持用in和not in操作符检查成员,由len()内建函数得到集合的基数(大小), 用 for 循环迭代集合的成员。但是因为集合本身是无序的,不可以为集合创建索引或执行切片(slice)操作,也没有键(keys)可用来获取集合中元素的值。 9 | 10 | set和dict一样,只是没有value,相当于dict的key集合,由于dict的key是不重复的,且key是不可变对象因此set也有如下特性: 11 | 12 | * 不重复 13 | 14 | * 元素为不可变对象 15 | 16 | 2. 创建 17 | 18 | ``` 19 | s = set() 20 | s = {11,22,33,44} #注意在创建空集合的时候只能使用s=set(),因为s={}创建的是空字典 21 | 22 | s1={} 23 | s2={1} 24 | s3=set() 25 | print(type(s1)) #dict 26 | print(type(s2)) #set 27 | print(type(s3)) #set 28 | ``` 29 | 30 | ``` 31 | a=set('body') 32 | b=set(['y', 'b', 'o','o']) 33 | c=set({"k1":'v1','k2':'v2'}) 34 | d={'k1','k2','k2'} 35 | e={('k1', 'k2','k2')} 36 | ``` 37 | 3. 基本操作 38 | 39 | 1. 添加 40 | 41 | se.add(1) 42 | 43 | 1. discard()-移除不存的元素不会报错 44 | 45 | 46 | ``` 47 | se = {11, 22, 33} 48 | se.discard(11) 49 | se.discard(44) # 移除不存的元素不会报错 50 | print(se) 51 | ``` 52 | 53 | 2. remove(44)-移除不存的元素会报错 54 | 55 | ``` 56 | se = {11, 22, 33} 57 | se.remove(11) 58 | se.remove(44) # 移除不存的元素会报错 59 | print(se) 60 | ``` 61 | 3. pop()-移除末尾元素 62 | 63 | ``` 64 | se = {11, 22, 33} # 移除末尾元素并把移除的元素赋给新值 65 | temp = se.pop() 66 | print(temp) # 33 67 | ``` 68 | 4. intersection() -取交集,赋给新值 69 | 70 | ``` 71 | se = {11, 22, 33} 72 | be = {22, 55} 73 | 74 | temp1 = se.intersection(be) #取交集,赋给新值 75 | print(temp1) # 22 76 | print(se) # {11, 22, 33} 77 | 78 | temp2 = se.intersection_update(be) #取交集并更新自己 79 | print(temp2) # None 80 | print(se) # 22 81 | ``` 82 | 4. 判断 83 | 84 | ``` 85 | se = {11, 22, 33} 86 | be = {22} 87 | 88 | print(se.isdisjoint(be)) #False,判断是否不存在交集(有交集False,无交集True) 89 | print(se.issubset(be)) #False,判断se是否是be的子集合 90 | print(se.issuperset(be)) #True,判断se是否是be的父集合 91 | ``` 92 | 5. 合并(se和be的并集 减去 se和be的交集) 93 | 94 | ``` 95 | se = {11, 22, 33} 96 | be = {22,55} 97 | 98 | temp1 = se.symmetric_difference(be) # 合并不同项,并赋新值 99 | print(temp1) #{33, 11, 55} 100 | print(se) #{33, 11, 22} 101 | 102 | temp2 = se.symmetric_difference_update(be) # 合并不同项,并更新自己 103 | print(temp2) #None 104 | print(se) #{33, 11, 55} 105 | ``` 106 | 6. 取并集 107 | 108 | ``` 109 | se = {11, 22, 33} 110 | be = {22,44,55} 111 | 112 | temp=se.union(be) #取并集,并赋新值 113 | print(se) #{33, 11, 22} 114 | print(temp) #{33, 22, 55, 11, 44} 115 | ``` 116 | 合并且更新 117 | 118 | ``` 119 | se = {11, 22, 33} 120 | be = {22,44,55} 121 | 122 | se.update(be) # 把se和be合并,得出的值覆盖se 123 | print(se) 124 | se.update([66, 77]) # 可增加迭代项 125 | print(se) 126 | ``` 127 | 128 | 8. 类型转化 129 | 130 | ``` 131 | se = set(range(4)) 132 | li = list(se) 133 | tu = tuple(se) 134 | st = str(se) 135 | ``` -------------------------------------------------------------------------------- /python/01-part1/unit3-变量类型-Tuple.md: -------------------------------------------------------------------------------- 1 | # 变量类型-Tuple 2 | 3 | 4 | 1. 特性 5 | 6 | 和字符串一样,tuple一旦创建就不能改变。 7 | 8 | ``` 9 | t1=(10) 10 | print(type(t1)) # 11 | t2=(10,) 12 | print(type(t2)) # 13 | ``` 14 | 15 | 16 | ``` 17 | tt=('python',['2.6','3.7'],'it') 18 | 19 | print(tt[1]) 20 | 21 | tt[0]='java' #error 22 | 23 | tt[1][0]='2.5' #不会出错,因为引用没有改变 24 | ``` 25 | 26 | 任意无符号的对象,以逗号隔开,默认为元组 27 | 28 | ``` 29 | x,y=1,2 30 | tup3 = "a", "b", "c", "d" 31 | ``` 32 | 33 | ``` 34 | x=(1) 35 | y=(2,) 36 | z=('a') 37 | q=3,4,5 38 | 39 | print(type(x)) #int 40 | print(type(y)) #tuple 41 | print(type(z)) #str 42 | print(type(q)) # 43 | ``` 44 | 2. 访问 45 | 46 | ``` 47 | t2=(10,20,30,40) 48 | print(t2[0:2]) 49 | ``` 50 | 3. 修改 51 | 52 | 修改元组是非法的 53 | 元组中的元素值是不允许删除的,但我们可以使用del语句来删除整个元组 54 | 3. 删除 55 | 56 | ``` 57 | del t2 58 | ``` 59 | 60 | 4. 元组运算符 61 | 62 | 与字符串一样,元组之间可以使用 + 号和 * 号进行运算。这就意味着他们可以组合和复制,运算后会生成一个新的元组。 63 | 64 | Python| 表达式| 结果 描述| 65 | ---|---|---| 66 | len((1, 2, 3))| 3| 计算元素个数| 67 | (1, 2, 3) + (4, 5, 6)| (1, 2, 3, 4, 5, 6)| 连接| 68 | ('Hi!',) * 4| ('Hi!', 'Hi!', 'Hi!', 'Hi!')| 复制| 69 | 3 in (1, 2, 3)| True| 元素是否存在| 70 | for x in (1, 2, 3): print (x,)| 1 2 3| 迭代| 71 | 72 | 5. index() count() 73 | 74 | 6. 和list比较 75 | 76 | ①、Tuple 与 list 的相同之处 77 | 78 | 定义 tuple 与定义 list 的方式相同, 除了整个元素集是用小括号包围的而不是方括号。 79 | Tuple 的元素与 list 一样按定义的次序进行排序。 Tuples 的索引与 list 一样从 0 开始, 所以一个非空 tuple 的第一个元素总是 t[0]。 80 | 负数索引与 list 一样从 tuple 的尾部开始计数。 81 | 与 list 一样分片 (slice) 也可以使用。注意当分割一个 list 时, 会得到一个新的 list ;当分割一个 tuple 时, 会得到一个新的 tuple。 82 | 83 | ②、Tuple 不存在的方法 84 | 85 | 您不能向 tuple 增加元素。Tuple 没有 append 或 extend 方法。 86 | 您不能从 tuple 删除元素。Tuple 没有 remove 或 pop 方法。 87 | 然而, 您可以使用 in 来查看一个元素是否存在于 tuple 中。 88 | 89 | ③、用 Tuple 的好处 90 | 91 | Tuple 比 list 操作速度快。如果您定义了一个值的常量集,并且唯一要用它做的是不断地遍历它,请使用 tuple 代替 list。 92 | 如果对不需要修改的数据进行 “写保护”,可以使代码更安全。使用 tuple 而不是 list 如同拥有一个隐含的 assert 语句,说明这一数据是常量。如果必须要改变这些值,则需要执行 tuple 到 list 的转换。 93 | 94 | ④、Tuple 与 list 的转换 95 | 96 | Tuple 可以转换成 list,反之亦然。内置的 tuple 函数接收一个 list,并返回一个有着相同元素的 tuple。而 list 函数接收一个 tuple 返回一个 list。从效果上看,tuple 冻结一个 list,而 list 解冻一个 tuple。 -------------------------------------------------------------------------------- /python/01-part1/unit3-变量类型.md: -------------------------------------------------------------------------------- 1 | # 变量类型 2 | 3 | 变量存储在内存中的值。这就意味着在创建变量时会在内存中开辟一个空间。 4 | 5 | 基于变量的数据类型,解释器会分配指定内存,并决定什么数据可以被存储在内存中。 6 | 7 | 因此,变量可以指定不同的数据类型,这些变量可以存储整数,小数或字符。 8 | ![](/Users/lzhan/AI/Python 1.x/python教程/images/变量类型.jpg 9 | ) 10 | 11 | 1. 变量 12 | 13 | python变量是动态的(它自动地跟踪你的类型而不是要求声明代码),但也是强类型语言(只能对一个对象进行适合该类型的有效的操作)。 14 | 在Python中类型属于对象,而不是属于变量,变量只是指向对象的引用或者叫地址。比如 15 | 16 | ``` 17 | a=3 18 | #变量a指向对象3的地址 19 | ``` 20 | 21 | python中每个对象都有一个引用计数器,一旦这个计数器被设置为零,这个对象的内存空间就会被回收。 22 | 23 | **思考 循环检测器???* 24 | 3. Python标识符 25 | 26 | * 在 Python 里,标识符由字母、数字、下划线组成。 27 | 28 | * 在 Python 中,所有标识符可以包括英文、数字以及下划线(_),但不能以数字开头。 29 | 30 | * Python 中的标识符是区分大小写的。 31 | 32 | * 以下划线开头的标识符是有特殊意义的。 33 | 34 | * 以双下划线开头的 __foo 代表类的私有成员;以双下划线开头和结尾的 __foo__ 代表 Python 里特殊方法专用的标识,如 __init__() 代表类的构造函数。 35 | * 见名知义 36 | * 小驼峰 37 | * 大驼峰 38 | * 下划线链接 39 | * 不能和关键字重名 40 | 41 | 关键字,是python已经使用的了,所以不允许开发者自己定义和关键字相同的名字的标示符 42 | 查看关键字: 43 | ``` 44 | import keyword 45 | keyword.kwlist 46 | ``` 47 | 48 | * Python 可以同一行显示多条语句,方法是用分号 ; 分开 49 | 50 | ``` 51 | #如果要判断的字符串过多可以这样写 52 | lst = [str1, str2] 53 | # _ 只有单个下划线的变量名会保存最后表达式的结果 54 | in_lst = [_ for _ in lst if word in _] 55 | ``` 56 | 57 | 1. 变量赋值 58 | 59 | ``` 60 | a = b = c = 1 61 | a, b, c = 1, 2, "john" 62 | ``` 63 | 64 | 2. 标准数据类型 65 | 66 | 67 | 在内存中存储的数据可以有多种类型。 68 | 69 | 例如,一个人的年龄可以用数字来存储,他的名字可以用字符来存储。 70 | 71 | Python 定义了一些标准类型,用于存储各种类型的数据。 72 | 73 | Python有五个标准的数据类型: 74 | 75 | * Numbers(数字) 76 | * String(字符串) 77 | * List(列表) 78 | * Tuple(元组) 79 | * Dictionary(字典) 80 | * Set(集合) 81 | 82 | ![](images/var.png) 83 | 84 | 1. 在python中,只要定义了一个变量,而且它有数据,那么它的类型就已经确定了,不需要咱们开发者主动的去说明它的类型,系统会自动辨别 85 | 2. 可以使用type(变量的名字),来查看变量的类型 86 | 3. Python数字 87 | 88 | Python支持四种不同的数字类型: 89 | 90 | 1. int(有符号整型) 91 | 2. long(长整型[也可以代表八进制和十六进制]) 92 | 3. float(浮点型) 93 | 4. complex(复数) 94 | 95 | ``` 96 | a=12 97 | lon=123L 98 | flo=12.3E100 99 | com1=3.14j 100 | com2=4.53e-7j 101 | ``` 102 | >长整型也可以使用小写 l,但是还是建议您使用大写 L,避免与数字 1 混淆。Python使用 L 来显示长整型。 103 | Python 还支持复数,复数由实数部分和虚数部分构成,可以用 a + bj,或者 complex(a,b) 表示, 复数的实部 a 和虚部 b 都是浮点型。 104 | 105 | 106 | 107 | ``` 108 | 4. 类型转化 109 | 110 | ``` 111 | a=12 112 | m=3.1415 113 | s='12.5' 114 | 115 | print(int(m)) #float ==> int 116 | print(float(a)) #int==>float 117 | #保留两位小数 118 | print(float('%.2f' % m)) 119 | print(round(m,2)) 120 | 121 | print(str(a)) #int==>str 122 | print(float(s)+2) 123 | print(s+2) #error 124 | print(s+str(2)) 125 | 126 | str='3+2.5' 127 | print(eval(str)) 128 | ``` 129 | 8. Python数据类型转换 130 | 131 | |函数 | 描述| 132 | |---|---| 133 | |int(x [,base])|将x转换为一个整数| 134 | |long(x [,base] )|将x转换为一个长整数| 135 | |float(x)|将x转换到一个浮点数| 136 | |complex(real [,imag])|创建一个复数| 137 | |str(x)|将对象 x 转换为字符串| 138 | |repr(x)|将对象 x 转换为表达式字符串| 139 | |eval(str)|用来计算在字符串中的有效Python表达式,并返回一个对象| 140 | |tuple(s)|将序列 s 转换为一个元组| 141 | |list(s)|将序列 s 转换为一个列表| 142 | |set(s)|转换为可变集合| 143 | |dict(d)|创建一个字典。d 必须是一个序列 (key,value)元组。| 144 | |frozenset(s)|转换为不可变集合| 145 | |chr(x)|将一个整数转换为一个字符| 146 | |unichr(x)|将一个整数转换为Unicode字符| 147 | |ord(x)|将一个字符转换为它的整数值| 148 | 149 | >python 的所有数据类型都是类,可以通过 type() 查看该变量的数据类型: 150 | 151 | type()不会认为子类是一种父类类型。 152 | isinstance()会认为子类是一种父类类型。 153 | 6. Python元组 154 | 155 | 元组是另一个数据类型,类似于List(列表)。 156 | 157 | 元组用"()"标识。内部元素用逗号隔开。但是元组不能二次赋值,相当于只读列表。 158 | 159 | ``` 160 | tu=(11,22,33,44) 161 | tu[0]=88 #TypeError: 'str' object does not support item assignment 162 | ``` 163 | 164 | 7. Python 字典 165 | 166 | 字典(dictionary)是除列表以外python之中最灵活的内置数据结构类型。列表是有序的对象集合,字典是无序的对象集合。 167 | 168 | 两者之间的区别在于:字典当中的元素是通过键来存取的,而不是通过偏移存取。 169 | 170 | 字典用"{ }"标识。字典由索引(key)和它对应的值value组成。 171 | 172 | ``` 173 | users=[ 174 | {"name":"tom","age":12}, 175 | {"name":"tony","age":12}, 176 | {"name":"anli","age":12}, 177 | {"name":"dapen","age":12} 178 | ] 179 | for item in users: 180 | for v in item.values(): 181 | print(v) 182 | 183 | for k in item.keys(): 184 | print(k) 185 | 186 | for item in users: 187 | for k in item.keys(): 188 | print(k,":",item[k]) 189 | 190 | users[0][3]='haha' 191 | 192 | ``` 193 | ``` 194 | switcher={ 195 | 0:'zero', 196 | 1:'one', 197 | 2:'two', 198 | 3:lambda:"three" 199 | } 200 | 201 | print(switcher.get(3)()) 202 | ``` 203 | 204 | #补充 205 | 1. 可变对象拷贝 206 | 207 | ``` 208 | list1=[1,2,3] 209 | list2=list1 #这是重复引用,不是拷贝 210 | 211 | list3=list1[:] #拷贝 212 | list4=list1.copy() 213 | 214 | #检查对象是否相等 215 | 216 | list1==list3 #true 比较的是内容 217 | list1 is list3 #false 比较的是地址是否是同一个地址 218 | ``` 219 | 220 | 但是 221 | 222 | ``` 223 | X=12 224 | Y=12 225 | X IS Y # True 226 | ``` 227 | 228 | >这是因为python缓存并复用了小整数和小字符串,即使执行x=14,对象12也不会被回收,他将可能被保存在一个系统表中,等待你的代码下次使用12这个对象。 229 | 230 | 可以通过以下代码来验证对象被引用的次数 231 | 232 | ``` 233 | import sys 234 | x=12 235 | y=12 236 | z=12 237 | 238 | print(sys.getrefcount(12)) 239 | 240 | ``` 241 | 242 | -------------------------------------------------------------------------------- /python/01-part1/unit4-运算符.md: -------------------------------------------------------------------------------- 1 | # 运算符&表达式 2 | 1. 赋值运算符 3 | 4 | ``` 5 | str='spam' 6 | m,n=10,20 7 | [s1,s2]=['hello','python'] 8 | a,b,c,d='spam' 9 | x,*y='spam' #等价于x,y='spam'[0],'spam'[1:] 10 | #x,*y,z='spam' 11 | e=f=20 12 | g+=20 13 | ``` 14 | demo 15 | 16 | ``` 17 | l=[1,2,3,4,5] 18 | while l: 19 | front,*l=l 20 | print(front) 21 | ``` 22 | >注意: *l每次得到的都是一个列表,如果没有数据就是空列表。 23 | 1. 算术运算符 24 | 25 | 运算符| 描述| 实例| 26 | ---|---|---| 27 | +| 加| 两个对象相加 a + b 输出结果 30| 28 | -| 减| 得到负数或是一个数减去另一个数 a - b 输出结果 -10| 29 | *| 乘| 两个数相乘或是返回一个被重复若干次的字符串 a * b 输出结果 200| 30 | /| 除| x除以y b / a 输出结果 2| 31 | //| 取整除| 返回商的整数部分 9//2 输出结果 4 , 9.0//2.0 输出结果 4.0| 32 | %| 取余| 返回除法的余数 b % a 输出结果 0| 33 | **| 幂| 返回x的y次幂 a**b 为10的20次方, 输出结果 100000000000000000000| 34 | 35 | ``` 36 | ** 幂 - 返回x的y次幂 a**b 为10的20次方, 输出结果 100000000000000000000 37 | 38 | // 取整除 - 返回商的整数部分 39 | import math 40 | 41 | f=-3.89 42 | 43 | print(f//1) 44 | 45 | print(math.floor(f)) 46 | print(math.trunc(f)) 47 | # 9//2 输出结果 4 , 48 | 9.0//2.0 输出结果 4.0 49 | ``` 50 | 51 | 3. 复合赋值运算符 52 | 53 | ``` 54 | c += a 等效于 c = c + a 55 | ``` 56 | 2. 比较运算符 57 | 58 | 59 | 运算符| 描述| 示例| 60 | ---|---|---| 61 | ==| 检查两个操作数的值是否相等,如果是则条件变为真。| 如a=3,b=3则(a == b) 为 true.| 62 | !=| 检查两个操作数的值是否相等,如果值不相等,则条件变为真。| 如a=1,b=3则(a != b) 为 true.| 63 | <>| 检查两个操作数的值是否相等,如果值不相等,则条件变为真。| 如a=1,b=3则(a <> b) 为 true。这个类似于 != 运算符| 64 | >| 检查左操作数的值是否大于右操作数的值,如果是,则条件成立。| 如a=7,b=3则(a > b) 为 true.| 65 | <| 检查左操作数的值是否小于右操作数的值,如果是,则条件成立。| 如a=7,b=3则(a < b) 为 false.| 66 | >=| 检查左操作数的值是否大于或等于右操作数的值,如果是,则条件成立。| 如a=3,b=3则(a >= b) 为 true.| 67 | <=| 检查左操作数的值是否小于或等于右操作数的值,如果是,则条件成立。| 如a=3,b=3则(a <= b) 为 true.| 68 | 69 | == 等于 - 比较对象是否相等 70 | <>或者!= 两者相同 71 | **在python3中<>被移除** 72 | 73 | 74 | 75 | 3. Python逻辑运算符 76 | 77 | * and 78 | * not 79 | * or 80 | 81 | **比较预算符 xis 与 == 区别: 102 | is 用于判断两个变量引用对象是否为同一个, == 用于判断引用变量的值是否相等。 103 | 104 | ``` 105 | a=20 106 | b=20 107 | c=30 108 | print(a is b) #True 109 | print(id(a)==id(b)) #True 110 | print(b is c) #False 111 | ``` 112 | 113 | > 114 | python中会为每个出现的对象分配内存,哪怕他们的值完全相等(注意是相等不是相同)。如执行a=2.0,b=2.0这两个语句时会先后为2.0这个Float类型对象分配内存,然后将a与b分别指向这两个对象。所以a与b指向的不是同一对象: 115 | 116 | >但是为了提高内存利用效率对于一些简单的对象,如一些数值较小的int对象,python采取重用对象内存的办法,如指向a=2,b=2时,由于2作为简单的int类型且数值小,python不会两次为其分配内存,而是只分配一次,然后将a与b同时指向已分配的对象: 117 | 118 | **Python 中没有 ++ 或 -- 自运算符** 119 | 120 | 121 | 6. 作业 122 | 123 | 必做题: 124 | 125 | 1. 说出变量名字,可以由哪些字符组成 126 | 127 | 2. 写出变量命名时的规则 128 | 129 | 3. 说出什么是驼峰法(大驼峰、小驼峰) 130 | 131 | 4. 编写程序,完成以下要求: 132 | 133 | 提示用户进行输入数据 134 | 获取用户的数据数据(需要获取2个) 135 | 对获取的两个数字进行求和运行,并输出相应的结果 136 | 5. 编写程序,完成以下要求: 137 | 138 | 提示用户进行输入数据 139 | 获取用户的数据数据(需要获取2个) 140 | 对获取的两个数字进行减法运行,并输出相应的结果 141 | 6. 编写程序,完成以下信息的显示: 142 | 143 | ``` 144 | ================================== 145 | = 欢迎进入到身份认证系统V1.0 146 | = 1. 登录 147 | = 2. 退出 148 | = 3. 认证 149 | = 4. 修改密码 150 | ================================== 151 | ``` 152 | 153 | 7. 编写程序,从键盘获取一个人的信息,然后按照下面格式显示 154 | 155 | ``` 156 | ================================== 157 | 姓名: lzhan 158 | QQ:xxxxxxx 159 | 手机号:131xxxxxx 160 | 公司地址:苏州xxxx 161 | ================================== 162 | ``` 163 | 8. 编写程序,从键盘获取用户名和密码,然后判断,如果正确就输出以下信息 164 | 165 | 亲爱的xxx,欢迎登陆 爱学习管理系统 -------------------------------------------------------------------------------- /python/01-part1/unit5-1-逻辑控制语句-if.md: -------------------------------------------------------------------------------- 1 | # 逻辑控制语句 2 | 1. 语法规则 3 | 4 | ``` 5 | a=12 6 | if a>10: 7 | a=a+10;b=a+1 8 | c=a+\ 9 | 10+20+\ 10 | 10 11 | d=(a+10 12 | +20 13 | +30) 14 | print('a=',a) 15 | print('b=',b) 16 | print('c=',c) 17 | print('d=',d) 18 | ``` 19 | 20 | 1. 行结束没有分号 21 | 2. 没有语句块大括号,使用语句缩进 22 | 3. 条件部分没有括号 23 | 4. 分号用于多条简单的语句放在同一行,作为分隔符 24 | 5. 跨行可以使用‘\’,或者(),当然[],{}等也适合。 25 | 26 | demo 27 | 28 | ``` 29 | while True: 30 | reply =input('Enter text:') 31 | if reply == 'stop': 32 | break 33 | elif not reply.isdigit(): 34 | print('Bad'*8) 35 | else: 36 | print(int(reply)**2) 37 | print('bye') 38 | 39 | ``` 40 | 1. 条件语句 41 | 42 | ``` 43 | if 判断条件: 44 | 执行语句…… 45 | else: 46 | 执行语句…… 47 | ``` 48 | 2. 练习 49 | 50 | 用户输入年龄,如果大于18岁,显示“成年”;否则显示“未成年” 51 | 3. 多条件 52 | 53 | ``` 54 | if 判断条件1: 55 | 执行语句1…… 56 | elif 判断条件2: 57 | 执行语句2…… 58 | elif 判断条件3: 59 | 执行语句3…… 60 | else: 61 | 执行语句4…… 62 | ``` 63 | >由于 python 并不支持 switch 语句,所以多个条件判断,只能用 elif 来实现,如果判断需要多个条件需同时判断时,可以使用 or (或),表示两个条件有一个成立时判断条件成功;使用 and (与)时,表示只有两个条件同时成立的情况下,判断条件才成功。 64 | 65 | **备注** 66 | python 复合布尔表达式计算采用短路规则,即如果通过前面的部分已经计算出整个表达式的值,则后面的部分不再计算。如下面的代码将正常执行不会报除零错误,但是如果改为or则会出错 67 | 68 | ``` 69 | a=0 70 | b=1 71 | if ( a > 0 ) and ( b / a > 2 ): 72 | print "yes" 73 | else : 74 | print "no" 75 | ``` 76 | 77 | 3. 练习 78 | 79 | 商品价格100元,用户账户余额150元,请用户输入购买商品数量,如果数量大于1,显示用户余额不足,否则购买成功,并显示购买后的余额。 80 | 81 | 4. if嵌套 82 | 83 | ``` 84 | if 条件1: 85 | 86 | 满足条件1 做的事情1 87 | 满足条件1 做的事情2 88 | ...(省略)... 89 | 90 | if 条件2: 91 | 满足条件2 做的事情1 92 | 满足条件2 做的事情2 93 | ...(省略)... 94 | ``` 95 | 5. 练习 96 | 97 | 商品价格100元,数量为5,用户账户余额150元,请用户输入购买商品数量,如果数量大于5,则显示库存不足;如果数量大于1,显示用户余额不足,否则购买成功,并显示购买后的余额。 98 | 3. 三元运算符 99 | 100 | ``` 101 | x=1 102 | 103 | # if x>0: 104 | # a=True 105 | # else: 106 | # a=False 107 | 108 | f=True if x>0 else False 109 | 110 | print(a) 111 | ``` 112 | 113 | 4. 补充(**可以跳过**) 114 | 115 | Python 没有 switch/case 语句,如果遇到很多中情况的时候,写很多的 if/else 不是很好维护,这时可以考虑用字典映射的方法替代: 116 | 117 | ``` 118 | #!/usr/bin/env python 119 | # -*- coding: utf-8 -*- 120 | 121 | import os 122 | def zero(): 123 | return "zero" 124 | 125 | def one(): 126 | return "one" 127 | 128 | def two(): 129 | return "two" 130 | 131 | def num2Str(arg): 132 | switcher={ 133 | 0:zero, 134 | 1:one, 135 | 2:two, 136 | 3:lambda:"three" 137 | } 138 | func=switcher.get(arg,lambda:"nothing") 139 | return func() 140 | 141 | if __name__ == '__main__': 142 | print num2Str(0) 143 | ``` 144 | 6. 课后练习 145 | 146 | 石头剪刀布游戏:剪刀(0) 石头(1) 布(2) 147 | 148 | ``` 149 | import random 150 | 151 | player = input('请输入:剪刀(0) 石头(1) 布(2):') 152 | 153 | player = int(player) 154 | 155 | computer = random.randint(0,2) 156 | 157 | # 用来进行测试 158 | #print('player=%d,computer=%d',(player,computer)) 159 | 160 | if ((player == 0) and (computer == 2)) or ((player ==1) and (computer == 0)) or ((player == 2) and (computer == 1)): 161 | print('获胜,哈哈,你太厉害了') 162 | elif player == computer: 163 | print('平局,要不再来一局') 164 | else: 165 | print('输了,不要走,洗洗手接着来,决战到天亮') 166 | ``` -------------------------------------------------------------------------------- /python/01-part1/unit5-2-逻辑控制语句-for.md: -------------------------------------------------------------------------------- 1 | # 逻辑控制语句-for 2 | 2. 循环语句 3 | 0. 循环 4 | 5 | ``` 6 | i = 0 7 | while i<10000: 8 | print("媳妇儿,我错了") 9 | i+=1 10 | ``` 11 | 1. while 12 | 13 | ``` 14 | count = 0 15 | while count < 5: 16 | print(count, " is less than 5") 17 | count = count + 1 18 | else: 19 | print(count, " is not less than 5") 20 | ``` 21 | 3. 练习 22 | 23 | 计算1~100之间偶数的累积和(包含1和100) 24 | 25 | 4. 嵌套循环 26 | 27 | 28 | ``` 29 | i = 1 30 | while i<=5: 31 | 32 | j = 1 33 | while j<=5: 34 | print("* ",end='') 35 | j+=1 36 | 37 | print("\n") 38 | i+=1 39 | ``` 40 | 41 | 5. 练习 42 | 43 | ``` 44 | * 45 | * * 46 | * * * 47 | * * * * 48 | * * * * * 49 | ``` 50 | 51 | 九九乘法表 52 | 53 | 2. for 54 | 55 | ``` 56 | #!/usr/bin/python 57 | # -*- coding: UTF-8 -*- 58 | 59 | for letter in 'Python': # 第一个实例 60 | print '当前字母 :', letter 61 | 62 | fruits = ['banana', 'apple', 'mango'] 63 | for fruit in fruits: # 第二个实例 64 | print '当前水果 :', fruit 65 | 66 | print "Good bye!" 67 | ``` 68 | 69 | ``` 70 | fruits = ['banana', 'apple', 'mango'] 71 | for index in range(len(fruits)): 72 | print '当前水果 :', fruits[index] 73 | else: 74 | print('over') 75 | ``` 76 | 77 | 3. break 78 | 4. continue 79 | 80 | * break/continue只能用在循环中,除此以外不能单独使用 81 | 82 | * break/continue在嵌套循环中,只对最近的一层循环起作用 83 | 5. range() zip() 84 | 85 | ``` 86 | arr=[1,2,3,4,5,6,7,8] 87 | 88 | print(arr[1::2]) 89 | print(arr[::2]) 90 | 91 | for i in range(0,len(arr),2): 92 | print(i) 93 | ``` 94 | ``` 95 | arr1=['a','b','c'] 96 | arr2=[97,98,99] 97 | 98 | 99 | li=list(zip(arr1,arr2)) 100 | print(li) 101 | #转化为字典 102 | dic=dict(zip(arr1,arr2)) 103 | print(dic) 104 | for(x,y) in zip(arr1,arr2): 105 | print(x,':',y) 106 | ``` 107 | 108 | ``` 109 | x,y,z=(1,2,3),(4,5,6),(7,8,9) 110 | 111 | li=list(zip(x,y,z)) 112 | print(li) 113 | 114 | #[(1, 4, 7), (2, 5, 8), (3, 6, 9)] 115 | ``` 116 | 117 | 6. enumerate() 118 | 119 | enumerate()返回一个生成器对象 120 | 121 | ``` 122 | arr1=['a','b','c'] 123 | 124 | e=enumerate(arr1) 125 | 126 | print(next(e)) 127 | 128 | for (index,item) in enumerate(arr1): 129 | print(index,'--->',item) 130 | ``` 131 | 5. pass 132 | 133 | Python pass是空语句,是为了保持程序结构的完整性。 134 | 135 | pass 不做任何事情,一般用做占位语句。 136 | 137 | Python 语言 pass 语句语法格式如下: 138 | 139 | ``` 140 | pass 141 | ``` 142 | 5. 课后练习 143 | 144 | 选做题: 145 | 146 | 1. 根据以下信息提示,请帮小明计算,他每月乘坐地铁支出的总费用 147 | 148 | 提示信息: 149 | 150 | 北京公交地铁新票价确定 151 | 152 | 据北京市发改委网站消息称,北京市将从2015年12月28起实施公共交通新票价:地铁6公里(含)内3元,公交车10公里(含)内2元,使用市政交通一卡通刷卡乘公交车普通卡5折,学生卡2.5折。 153 | 154 |   具体实施方案如下: 155 | 156 |   一、城市公共电汽车价格调整为:10公里(含)内2元,10公里以上部分,每增加1元可乘坐5公里。使用市政交通一卡通刷卡乘坐城市公共电汽车,市域内路段给予普通卡5折,学生卡2.5折优惠;市域外路段维持现行折扣优惠不变。享受公交政策的郊区客运价格,由各区、县政府按照城市公共电汽车价格制定。 157 | 158 |   二、轨道交通价格调整为:6公里(含)内3元;6公里至12公里(含)4元;12公里至22公里(含)5元;22公里至32公里(含)6元;32公里以上部分,每增加1元可乘坐20公里。使用市政交通一卡通刷卡乘坐轨道交通,每自然月内每张卡支出累计满100元以后的乘次,价格给予8折优惠;满150元以后的乘次,价格给予5折优惠;支出累计达到400元以后的乘次,不再享受打折优惠。 159 | 160 | 要求: 161 | 162 | 假设每个月,小明都需要上20天班,每次上班需要来回1次,即每天需要乘坐2次同样路线的地铁;每月月初小明第一次刷公交卡时,扣款5元;编写程序,帮小明完成每月乘坐地铁需要的总费用 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /python/01-part1/unit5-3-迭代器.md: -------------------------------------------------------------------------------- 1 | # 迭代器 2 | 1. 概述 3 | 4 | 迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。 5 | 6 | 2. 可迭代对象 7 | 8 | 迭代器提供了一个统一的访问集合的接口。只要是实现了__iter__()或 __getitem__()方法的对象,就可以使用迭代器进行访问。 9 | 10 | 序列:字符串、列表、元组 11 | 12 | 非序列:字典、文件 13 | 14 | 自定义类:用户自定义的类实现了__iter__()或__getitem__()方法的对象 15 | 16 | 迭代字典 17 |    18 |    d = {'a': 1, 'b': 2, 'c': 3} 19 | 20 | for k in d: 21 | print(k) 22 | 23 | for k in d.keys(): 24 | print(k) 25 | 26 | for v in d.values(): 27 | print(v) 28 | 29 | for (k,v) in d.items(): 30 | print(k,v) 31 | 32 | 3. 迭代基础 33 | 34 | ``` 35 | f1=open('data.txt') 36 | 37 | # for line in f1.readlines(): #把所有行读入内存,遇到大文件效率差 38 | # print(line) 39 | 40 | # for line in f1: 41 | # print(line) 42 | 43 | # 文件对象就是自己的迭代器 44 | 45 | print(f1.__next__()) 46 | print(f1.__next__()) 47 | 48 | # 为了手动支持迭代,python3.0提供了一个next()方法,他会自动调用对象的_next_() 49 | 50 | print(next(f1)) 51 | ``` 52 | 53 | 4. iter() 和 next() 54 | 55 | 56 | 字符串/数组本身没有迭代对象 57 | 58 | ``` 59 | s='hello' 60 | 61 | iter01=iter(s) 62 | print(next(iter01)) 63 | print(next(iter01)) 64 | 65 | 66 | arr=[1,2,3,4] 67 | E=iter(arr) 68 | # print(E.__next__()) 69 | # print(next(E)) 70 | 71 | while True: 72 | try: 73 | X=E.__next__() 74 | except StopIteration: 75 | break 76 | print(X) 77 | ``` 78 | >字典对象有一个迭代器,每次返回字典的key 79 | 80 | ``` 81 | params={'name':'tom','age':12} 82 | for key in params: 83 | ... 84 | #所以不要下面的写法 85 | for key in params.keys(): 86 | ... 87 | 88 | ``` 89 | 5. range() 90 | 91 | range()支持多个迭代器,而其他内置函数不支持 92 | ``` 93 | arr=list(range(20)) 94 | print(arr) 95 | 96 | R=iter(range(100)) 97 | 98 | print(next(R)) 99 | print(next(R)) 100 | print(next(R)) 101 | 102 | 103 | ``` 104 | 5. enumerate函数 105 | 106 | Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身: 107 | 108 | mylist=['A', 'B', 'C'] 109 | for i, value in enumerate(mylist): 110 | print(i,value) 111 | 112 | 6. map() zip() filter() 113 | 和range()不同,以上三个函数都是自己的迭代器 114 | 115 | ``` 116 | M=map(abs,[2,-3,-1,3]) 117 | print(next(M)) 118 | ``` 119 | 120 | 121 | -------------------------------------------------------------------------------- /python/01-part1/unit6-函数装饰器.md: -------------------------------------------------------------------------------- 1 | # 函数装饰器 2 | 0. 为什么要用装饰器? 3 | 4 | 装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用.概括的讲,**装饰器的作用就是为已经存在的对象添加额外的功能。** 5 | 6 | 7 | 1. 先定义两个个函数 8 | 9 | def addUser(): 10 | print('添加用户成功!') 11 | 12 | def registUser(): 13 | print('添加用户成功!') 14 | 如果用户想要知道是哪个函数添加了用户,怎么办?(略...) 15 | 16 | 改进方法 17 | 18 | def debug(): 19 | import inspect 20 | caller_name = inspect.stack()[1][3] 21 | print("[DEBUG]: enter {}()".format(caller_name)) 22 | 23 | def addUser(): 24 | debug() 25 | print('添加用户成功!') 26 | 27 | def registUser(): 28 | debug() 29 | print('添加用户成功!') 30 | 31 | 但是如果再想要取消这个功能,则需要改变两个函数:addUser,registUser 32 | 33 | **装饰器的作用很明显** 34 | 35 | def debug(func): 36 | def wrapper(): 37 | print("[DEBUG]: enter {}()".format(func.__name__)) 38 | return func() 39 | return wrapper 40 | 41 | @debug 42 | def addUser(): 43 | print('添加用户成功!') 44 | return 'ok' 45 | 46 | @debug 47 | def registUser(): 48 | print('添加用户成功!') 49 | 2. 装饰器传参 50 | 51 | 参数先传给装饰器,装饰器传给函数 52 | 53 | def debug(func): 54 | def wrapper(name): 55 | print("[DEBUG]: enter {}()".format(func.__name__)) 56 | func(name) 57 | return wrapper 58 | 59 | @debug 60 | def addUser(name): 61 | print('添加用户{0}成功!'.format(name)) 62 | 63 | @debug 64 | def registUser(name): 65 | print('添加用户{0}成功!'.format(name)) 66 | 67 | addUser('tom') 68 | registUser('jack') 69 | 70 | 如果函数是有返回值的,则加上return 语句即可 71 | 72 | def debug(func): 73 | def wrapper(name): 74 | print("[DEBUG]: enter {}()".format(func.__name__)) 75 | return func(name) #此处加上return 76 | return wrapper 77 | 78 | 3. 传递可变参数 79 | 80 | def debug(func): 81 | def wrapper(*args,**other): 82 | print("[DEBUG]: enter {}()".format(func.__name__)) 83 | print(other) 84 | # 可以在此处对 args和other数据进行处理 85 | return func(args) 86 | return wrapper 87 | 88 | @debug 89 | def addUser(user): 90 | print('添加用户{0}成功!'.format(user)) 91 | return user 92 | 93 | @debug 94 | def registUser(user): 95 | print('添加用户{0}成功!'.format(user)) 96 | return user 97 | 98 | n1=addUser('tom',12,other={'gender': 'M', 'job': 'Engineer'}) 99 | n2=registUser('jack') 100 | -------------------------------------------------------------------------------- /python/01-part1/unit6-函数装饰器高级.md: -------------------------------------------------------------------------------- 1 | # 函数装饰器高级 2 | 3 | 4 | 0. 最新版本 5 | 6 | 最新版本的python导入了functools模块 7 | 8 | from functools import wraps 9 | def debug(func): 10 | @wraps(func) 11 | def wrapper(name): 12 | print("[DEBUG]: enter {}()".format(func.__name__)) 13 | return func(name) #此处加上return 14 | return wrapper 15 | @debug 16 | 17 | def show(s): 18 | print(s) 19 | 20 | show('ppyth') 21 | 1. 带参数的装饰器 22 | 23 | ``` 24 | from functools import wraps 25 | def debug(*text): 26 | def decorated(func): 27 | @wraps(func) 28 | def wrapper(name): 29 | print("[DEBUG]: enter {}()".format(func.__name__)) 30 | return func(name) # 此处加上return 31 | 32 | return wrapper 33 | return decorated 34 | 35 | @debug() #此处的()不可以删略 36 | def show(s): 37 | print(s) 38 | 39 | show('ppyth') 40 | ``` 41 | 42 | 3. \_\_call__() 43 | 44 | 所有的函数都是可调用对象。 45 | 一个类实例也可以变成一个可调用对象,只需要实现一个特殊方法__call__() 46 | 47 | class Person(object): 48 | def __init__(self,name): 49 | self.name=name 50 | 51 | def __call__(self, *args, **kwargs): 52 | print('my name is ',self.name) 53 | print('my hobby is ',args) 54 | 55 | p1=Person('tom') 56 | 57 | p1('reading') 58 | >所以,在Python中,函数也是对象,对象和函数的区别并不显著。 59 | 2. 类装饰器(待续.....) 60 | 61 | from functools import wraps 62 | from datetime import datetime 63 | 64 | #类的装饰器写法,日志 65 | class log(object): 66 | def __init__(self, logfile='out.log'): 67 | self.logfile = logfile 68 | 69 | def __call__(self, func): 70 | @wraps(func) 71 | def wrapped_func(*args, **kwargs): 72 | self.writeLog(*args, **kwargs) # 先调用 写入日志 73 | return func(*args, **kwargs) # 正式调用主要处理函数 74 | return wrapped_func 75 | 76 | #写入日志 77 | def writeLog(self, *args, **kwargs): 78 | time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") 79 | log_str = time+' 操作人:{0[0]} 进行了【{0[1]}】操作'.format(args) 80 | with open(self.logfile, 'a',encoding='utf8') as file: 81 | file.write(log_str + '\n') 82 | 83 | @log() 84 | def myfunc(name,age): 85 | print('姓名:{0},年龄:{1}'.format(name,age)) 86 | 87 | if __name__ == '__main__': 88 | myfunc('小白', '查询') 89 | myfunc('root', '添加人员') 90 | myfunc('小小', '修改数据') 91 | 92 | 93 | [参考](https://www.cnblogs.com/cicaday/p/python-decorator.html) 94 | 95 | [参考](https://www.jianshu.com/p/9e9726055bbe) -------------------------------------------------------------------------------- /python/01-part1/unit7-模块.md: -------------------------------------------------------------------------------- 1 | # 模块 2 | 3 | 1. 介绍 4 | 5 | Python 模块(Module),是一个 Python 文件,以 .py 结尾,包含了 Python 对象定义和Python语句。 6 | 7 | 模块让你能够有逻辑地组织你的 Python 代码段。 8 | 9 | 把相关的代码分配到一个模块里能让你的代码更好用,更易懂。 10 | 11 | 模块能定义函数,类和变量,模块里也能包含可执行的代码。 12 | 13 | 2. import(导入模块) 14 | 15 | 16 | module_a.py 17 | 18 | ``` 19 | #!/Users/lzhan/Lzhan/python/project/unit1 20 | # -*- coding: UTF-8 -*- 21 | def add(a,b): 22 | return a+b 23 | version='1.0' 24 | print('add is end') 25 | # print __name__=="__main__" # 结果为false 26 | ``` 27 | 28 | main.py 29 | 30 | ``` 31 | # -*- coding:UTF-8 -*- 32 | # 第一种应用方式--导入模块 33 | 34 | # import module_a 35 | 36 | # print module_a.add(10,20) 37 | # dir(module_a) # get list of attributes for sys module 38 | # 第二种调用方式--从模块导入内部属性或方法 39 | from module_a import add,version 40 | print (add(10,20)) 41 | print (version) 42 | 43 | print( __name__=='__main__') 44 | ``` 45 | 46 | 补充: 47 | 48 | ``` 49 | #!/Users/lzhan/Lzhan/python/project/unit1 50 | # -*- coding: UTF-8 -*- 51 | import sys 52 | print 'test import and arguments' 53 | for i in sys.argv: 54 | print(i) 55 | 56 | print (__name__=="__main__") 57 | 58 | print( 'end') 59 | 60 | print (__name__) 61 | 62 | print( sys.path) 63 | 64 | print (dir()) 65 | 66 | ``` 67 | 68 | **当导入包文件夹的情况下,多级目录使用.作为分隔符,使用模块的时候,也要全部引入** 69 | 70 | ``` 71 | 72 | import dir01.dir02.moudule 73 | 74 | #调用模块中的内容 75 | dir01.dir02.moudule.func() 76 | 77 | 或者 78 | import dir01.dir02.moudule as m 79 | 80 | m.func() 81 | 82 | 83 | ``` 84 | 3. from 模块 import *(模块内部的元素) 85 | 86 | ``` 87 | from module_a import add,version 88 | ``` 89 | 4. **搜索路径** 90 | 91 | 当你导入一个模块,Python 解析器对模块位置的搜索顺序是: 92 | 93 | 1. 当前目录 94 | 2. 如果不在当前目录,Python 则搜索在 shell 变量 PYTHONPATH 下的每个目录。 95 | 3. 如果都找不到,Python会察看默认路径。UNIX下,默认路径一般为/usr/local/lib/python/。 96 | 97 | 98 | 模块搜索路径存储在 system 模块的 sys.path 变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录。 99 | 100 | 查看系统目录 101 | 102 | import sys 103 | print(sys.path) 104 | 105 | 如果动态添加搜索路径可以这么做 106 | 107 | sys.path.append('/Users/lzhan/AI/Python 1.x') 108 | 109 | 110 | 4. globals() 和 locals() 函数 111 | 112 | 113 | 根据调用地方的不同,globals() 和 locals() 函数可被用来返回全局和局部命名空间里的名字。 114 | 115 | 如果在函数内部调用 locals(),返回的是所有能在该函数里访问的命名。 116 | 117 | 如果在函数内部调用 globals(),返回的是所有在该函数里能访问的全局名字。 118 | 119 | 两个函数的返回类型都是字典。所以名字们能用 keys() 函数摘取。 120 | 121 | 122 | 5. reload() 函数 123 | 124 | 125 | 当一个模块被导入到一个脚本,模块顶层部分的代码只会被执行一次。 126 | 127 | 因此,如果你想重新执行模块里顶层部分的代码,可以用 reload() 函数。该函数会重新导入之前导入过的模块。语法如下: 128 | 129 | ``` 130 | reload(module_name) 131 | 在这里,module_name要直接放模块的名字,而不是一个字符串形式。比如想重载 hello 模块,如下: 132 | 133 | reload(hello) 134 | ``` 135 | 136 | 6. Python中的包 137 | 138 | 139 | 包是一个分层次的文件目录结构,它定义了一个由模块及子包,和子包下的子包等组成的 Python 的应用环境。 140 | 141 | 简单来说,包就是文件夹,但该文件夹下必须存在 __init__.py 文件, 该文件的内容可以为空。__init__.py 用于标识当前文件夹是一个包。 142 | 143 | 1. -------------------------------------------------------------------------------- /python/01-part1/unit7-模块高级.md: -------------------------------------------------------------------------------- 1 | # 模块 2 | 3 | 1. import如何工作 4 | 5 | **导入只发生一次** 6 | 2. 找到模块文件 7 | 3. 编译成位码(需要时) 8 | 4. 执行模块的代码来创建其所定义的对象 9 | 10 | >Python把导入的模块存贮到sys.moudles表中,并在导入操作的时候检查该表,如果模块不存在,将会启动上面三个步骤。 11 | 2. 搜索 12 | 13 | 大多数情况下,可以依赖模块导入的路径来搜索路径,不需要额外配置路径。但是,也可以自己预定义路径,那么搜索的顺序: 14 | 1. 程序的主目录 15 | 2. PYHONPATH目录(如果已经进行了设置) 16 | 17 | ``` 18 | import sys 19 | print(list(sys.path)) 20 | #手动添加目录 21 | sys.path.append('c:\\python\\modules') 22 | sys.path.append('c:/python/modules') 23 | 24 | ``` 25 | 3. 标准链接库目录 26 | 27 | 4. 任何.pth文件的内容(如果存在的话) 28 | 29 | 在python安装路径的site-packages目录下修建了PckPath.pth文件 30 | 31 | ``` 32 | /Users/lzhan/AI/python/project_modules/modules 33 | ``` 34 | 3. 编译 35 | 36 | >当文件导入时,就会进行编译。因此、通常不会看到程序顶层文件的.pyc字节码文件。除非这个文件也被其他文件导入:只有被导入的文件才会留下字节码文件。顶层文件的字节码是在内部使用后就丢弃了。 37 | 4. 执行 38 | 39 | 和def一样,import和form是可执行语句,而不是在编译期间的声明。直到python执行到这些语句时,才会进行解析。 40 | 4. distutils 41 | 42 | Distutils可以用来在Python环境中构建和安装额外的模块。新的模块可以是纯Python的,也可以是用C/C++写的扩展模块,或者可以是Python包,包中包含了由C和Python编写的模块。 43 | 5. from 44 | 45 | from会把模块中的变量复制到另一个作用域,所以顶层文件中就可以直接使用该变量了。 46 | 47 | ``` 48 | import modulea 49 | from modulea import * #等价 50 | ``` 51 | >from语句智能用在模块文件的顶部,不能放在函数中。 52 | 53 | 所以下面代码是等价的 54 | 55 | ``` 56 | from module import name1,name2 57 | #等价于 58 | import module 59 | name1=module.name1 60 | name2=module.name2 61 | del module 62 | ``` 63 | 64 | from语句有破坏命名空间的潜质!! 65 | 6. 查看模块命名空间 66 | 67 | ``` 68 | import public_var as p 69 | print(p.__dict__) 70 | print(dir(p)) 71 | ``` 72 | 7. reload() 73 | 74 | 1. reload是Python的内置函数,而不是语句 75 | 2. reload只能重载已经存在的模块对象,而不是变量 76 | 3. relaod必须手动导入 77 | 78 | ``` 79 | import public_var as p 80 | from importlib import reload 81 | 82 | print(p.urls['first']) 83 | 84 | p.urls['first']='baidu.com' 85 | 86 | print(p.urls['first']) 87 | 88 | reload(p) 89 | print(p.urls['first']) 90 | ``` 91 | 92 | 93 | 8. 包导入 94 | 95 | ``` 96 | import modules.public_var 97 | from modules.public_var import * 98 | ``` 99 | **注意** 100 | 作为包的目录内必须存在__init__.py文件。 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /python/01-part1/unit8-文件I:O.md: -------------------------------------------------------------------------------- 1 | # 文件I/O 2 | 2. 打开和关闭文件-open() 3 | 4 | ``` 5 | file object = open(file_name [, access_mode][, buffering]) 6 | ``` 7 | 各个参数的细节如下: 8 | 9 | * file_name:file_name变量是一个包含了你要访问的文件名称的字符串值。 10 | * access_mode:access_mode决定了打开文件的模式:只读,写入,追加等。所有可取值见如下的完全列表。这个参数是非强制的,默认文件访问模式为只读(r)。 11 | * buffering:如果buffering的值被设为0,就不会有寄存。如果buffering的值取1,访问文件时会寄存行。如果将buffering的值设为大于1的整数,表明了这就是的寄存区的缓冲大小。如果取负值,寄存区的缓冲大小则为系统默认。 12 | * buffering=1024,写够1024个字节后执行一次IO操作 13 | 14 | 3. File对象的属性 15 | 16 | ``` 17 | #!/usr/bin/python 18 | # -*- coding: UTF-8 -*- 19 | 20 | # 打开一个文件 21 | fo = open("foo.txt", "w") 22 | print "文件名: ", fo.name 23 | 24 | #返回true如果文件已被关闭,否则返回false。 25 | print "是否已关闭 : ", fo.closed 26 | #返回被打开文件的访问模式。 27 | print "访问模式 : ", fo.mode 28 | #如果用print输出后,必须跟一个空格符,则返回false。否则返回true。 29 | print "末尾是否强制加空格 : ", fo.softspace 30 | 31 | fo.close() 32 | ``` 33 | 4. 打开模式 34 | 35 | 标识|模式|说明| 36 | ---|---|---| 37 | r|只读|文件不存在报错| 38 | w|只写|文件不存在,新建文件| 39 | a|追加|文件不存在,新建文件| 40 | r+|可读写|文件不存在报错,先读取文件,然后才能写入文件,反之,写不进内容| 41 | w+|可读写|写读取文件,然后就无法读文件了。。。。| 42 | a+|可读写|同上,原因是文件指针的位置决定了| 43 | 4. 目录 44 | 45 | 1. ./ 当前目录 46 | 2. ../上一级目录 47 | 3. /下一级目录 48 | 4. write() 49 | 50 | write()方法可将任何字符串写入一个打开的文件。需要重点注意的是,Python字符串可以是二进制数据,而不是仅仅是文字。 51 | 52 | write()方法不会在字符串的结尾添加换行符('\n'): 53 | 54 | *当存入非字符串对象是,数据必须转化为字节码,或者序列化* 55 | 56 | ``` 57 | fo=open('content2.txt','a+') 58 | fo.write( "Python 是一个非常好的语言。\n是的,的确非常好!!\n" ) 59 | fo.write( "Python 是一个非常好的语言。\n是的,的确非常好!!???????????\n" ) 60 | 61 | fo.close() 62 | ``` 63 | 64 | 如果要写入一些不是字符串的东西, 那么将需要先进行转换: 65 | 66 | ``` 67 | f = open("/tmp/foo1.txt", "w") 68 | 69 | value = ('www.runoob.com', 14) 70 | s = str(value) 71 | f.write(s) 72 | 73 | f.flush() 74 | 75 | # 关闭打开的文件 76 | f.close() 77 | ``` 78 | 5. read() 79 | 80 | ``` 81 | fo=open('content2.txt','r+') 82 | str=fo.read() 83 | print(str) 84 | 85 | fo.close() 86 | ``` 87 | 6. readline() readlines() 88 | 89 | ``` 90 | fo=open('content2.txt','r+') 91 | str1=fo.readline() 92 | #指针移动到第二行,读出所有行放到一个数组中 93 | str2=fo.readlines() 94 | print(str1) 95 | print(str2) 96 | 97 | fo.close() 98 | ``` 99 | 100 | ``` 101 | for line in fo: 102 | print(line, end='') 103 | ``` 104 | 7. tell() 105 | 返回文件对象当前所处的位置, 它是从文件开头开始算起的字节数。 106 | ``` 107 | fo.tell() 108 | ``` 109 | 8. seek() 110 | 111 | 如果要改变文件当前的位置, 可以使用 f.seek(offset, from_what) 函数。 112 | 113 | from_what 的值, 如果是 0 表示开头, 如果是 1 表示当前位置, 2 表示文件的结尾,例如: 114 | 115 | * seek(x,0) : 从起始位置即文件首行首字符开始移动 x 个字符 116 | * seek(x,1) : 表示从当前位置往后移动x个字符 117 | * seek(-x,2):表示从文件的结尾往前移动x个字符 118 | 119 | 8. json序列化对象 120 | 121 | 122 | 9. pickle 模块 123 | python的pickle模块实现了基本的数据序列和反序列化。 124 | 125 | 通过pickle模块的序列化操作我们能够将程序中运行的对象信息保存到文件中去,永久存储。 126 | 127 | 通过pickle模块的反序列化操作,我们能够从文件中创建上一次程序保存的对象。 128 | 129 | 基本接口: 130 | 131 | 132 | ``` 133 | pickle.dump(obj, file, [,protocol]) 134 | ``` 135 | 136 | write_file.py 137 | 138 | ``` 139 | #!/usr/bin/python3 140 | import pickle 141 | 142 | # 使用pickle模块将数据对象保存到文件 143 | data1 = {'a': [1, 2.0, 3, 4+6j], 144 | 'b': ('string', u'Unicode string'), 145 | 'c': None} 146 | 147 | selfref_list = [1, 2, 3] 148 | selfref_list.append(selfref_list) 149 | 150 | output = open('data.pkl', 'wb') 151 | 152 | # Pickle dictionary using protocol 0. 153 | pickle.dump(data1, output) 154 | 155 | # Pickle the list using the highest protocol available. 156 | pickle.dump(selfref_list, output, -1) 157 | 158 | output.close() 159 | ``` 160 | 161 | read_file.py 162 | 163 | ``` 164 | #!/usr/bin/python3 165 | import pprint, pickle 166 | 167 | #使用pickle模块从文件中重构python对象 168 | pkl_file = open('data.pkl', 'rb') 169 | 170 | data1 = pickle.load(pkl_file) 171 | print(data1['a']) 172 | pprint.pprint(data1) 173 | 174 | data2 = pickle.load(pkl_file) 175 | pprint.pprint(data2) 176 | 177 | pkl_file.close() 178 | ``` 179 | 1. pickle.dump(obj, file, protocol=None,) 180 | 2. pickle.load(file,*,fix_imports=True, encoding="ASCII", errors="strict") 181 | 182 | >必填参数file必须以二进制可读模式打开,即“rb”,其他都为可选参数 183 | 3. pickle.dumps(obj):以字节对象形式返回封装的对象,不需要写入文件中 184 | 185 | 4. pickle.loads(bytes_object): 从字节对象中读取被封装的对象,并返回 186 | 1. flush() 187 | 188 | flush() 方法是用来刷新缓冲区的,即将缓冲区中的数据立刻写入文件,同时清空缓冲区,不需要是被动的等待输出缓冲区写入。 189 | 190 | 一般情况下,文件关闭后会自动刷新缓冲区,但有时你需要在关闭前刷新它,这时就可以使用 flush() 方法。 191 | 192 | 193 | 2. 内存读写 194 | 195 | 1. StringIO在内存中读写str 196 | 197 | from io import StringIO 198 | 199 | f = StringIO() 200 | # f.write('hello') 201 | # f.write('python') 202 | f.write('!') 203 | 204 | print(f.getvalue()) 205 | 206 | 207 | 写入多行语句 208 | 209 | f = StringIO('Hello!\nHi!\nGoodbye!') 210 | 211 | for line in f: 212 | print(line) 213 | 214 | 2. 二进制数据,就需要使用BytesIO 215 | 216 | from io import BytesIO 217 | f = BytesIO() 218 | f.write('中文'.encode('utf-8')) 219 | print(f.getvalue()) 220 | 221 | f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87') 222 | 223 | f.read() -------------------------------------------------------------------------------- /python/01-part1/unit8-文件io-excel.md: -------------------------------------------------------------------------------- 1 | # 文件I/O-excel 2 | 3 | ## 读写数据 4 | 5 | 1. 安装 openpyxl 6 | 7 | ``` 8 | pip install openpyxl 9 | ``` 10 | 2. 打开文件 11 | 12 | ``` 13 | from openpyxl import load_workbook 14 | 15 | from openpyxl.writer.excel import ExcelWriter 16 | 17 | try: 18 | workbook_ = load_workbook(u"data.xlsx") 19 | # 获得表单名字 20 | sheetnames = workbook_.get_sheet_names() 21 | 22 | sheet = workbook_.get_sheet_by_name(sheetnames[0]) 23 | except Exception as ex: 24 | print(ex) 25 | 26 | ``` 27 | 3. 获取单元格 28 | 29 | ``` 30 | # 获取某个单元格的值,观察excel发现也是先字母再数字的顺序,即先列再行 31 | b4 = sheet['A4'] #A行4列 32 | 33 | # 除了用下标的方式获得,还可以用cell函数, 换成数字,这个表示B4 34 | b4_too = sheet.cell(row=4, column=2) 35 | print(b4_too.value) 36 | 37 | 38 | for i in range(2): 39 | for j in range(5): 40 | print(sheet.cell(row=i+1, column=j+1).value,end=' ') 41 | print() 42 | ``` 43 | 4. 获得最大行和最大列 44 | 45 | ``` 46 | # 获得最大列和最大行 47 | print(sheet.max_row) 48 | print(sheet.max_column) 49 | 50 | 51 | ``` 52 | 5. 获取行和列 53 | 54 | ``` 55 | sheet.rows为生成器, 里面是每一行的数据,每一行又由一个tuple包裹。 56 | sheet.columns类似,不过里面是每个tuple是每一列的单元格。 57 | ``` 58 | 59 | ``` 60 | # 因为按行,所以返回A1, B1, C1这样的顺序 61 | for row in sheet.rows: 62 | for cell in row: 63 | print(cell.value) 64 | 65 | # A1, A2, A3这样的顺序 66 | for column in sheet.columns: 67 | for cell in column: 68 | print(cell.value) 69 | ``` 70 | 71 | >上面的代码就可以获得所有单元格的数据。如果要获得某行的数据呢?给其一个索引就行了,因为sheet.rows是生成器类型,不能使用索引,转换成list之后再使用索引,list(sheet.rows)[2]这样就获取到第三行的tuple对象。 72 | 73 | ``` 74 | for cell in list(sheet.rows)[2]: 75 | print(cell.value) 76 | ``` 77 | 78 | 6. 切片获取 79 | 80 | 还可以像使用切片那样使用。sheet['A1':'B3']返回一个tuple,该元组内部还是元组,由每行的单元格构成一个元组。 81 | 82 | ``` 83 | for row_cell in sheet['A1':'B3']: 84 | for cell in row_cell: 85 | print(cell) 86 | ``` 87 | 88 | ## 写入数据 89 | 90 | 1. 完整案例 91 | 92 | ``` 93 | from openpyxl import Workbook 94 | 95 | from openpyxl import load_workbook 96 | 97 | from openpyxl.writer.excel import ExcelWriter 98 | 99 | try: 100 | 101 | # 新建工作表 102 | wb=Workbook() 103 | # 新建一个工作表,可以指定索引,适当安排其在工作簿中的位置 104 | sheet=wb.create_sheet('Data', index=1) # 被安排到第二个工作表,index=0就是第一个位置 105 | 106 | # 删除某个工作表 107 | # wb.remove(wb) 108 | # del wb[sheet] 109 | # row = [1, 2, 3, 4, 5] 110 | # sheet.append(row) 111 | rows = [ 112 | ['Number', 'data1', 'data2'], 113 | [2, 40], 114 | [3, 40, 25], 115 | [4, 50, 30], 116 | [5, 30, 10], 117 | [6, 25, 5], 118 | [7, 50, 10111], 119 | ] 120 | for row in rows: 121 | sheet.append(row) 122 | wb.save(r'新歌检索失败1477881109469.xlsx') 123 | except Exception as ex: 124 | print(ex) 125 | ``` -------------------------------------------------------------------------------- /python/01-part1/unit9-OS.md: -------------------------------------------------------------------------------- 1 | #os 2 | 3 | 1. 获取当前目录 4 | 5 | import os 6 | print(os.path.abspath('.')) 7 | print(os.path) #真正的系统目录 8 | 9 | 2. 在当前目录下新建文件 10 | 11 | import os 12 | dir=os.path.join('public') 13 | os.mkdir(dir) 14 | >两个路径合成一个时,不要直接拼字符串,而要通过os.path.join()函数,这样可以正确处理不同操作系统的路径分隔符。 15 | 16 | >在Linux/Unix/Mac下,os.path.join()返回这样的字符串: 17 | part-1/part-2 18 | 19 | >而Windows下会返回这样的字符串: 20 | part-1\part-2 21 | 3. 删除目录 22 | 23 | os.rmdir('/Users/michael/testdir') 24 | 25 | 4. 拆分路径(获取文件名) 26 | 27 | 拆分路径时,不要直接去拆字符串,而要通过os.path.split()函数,这样可以把一个路径拆分为两部分,后一部分总是最后级别的目录或文件名 28 | 29 | os.path.split('/Users/michael/testdir/file.txt') 30 | 31 | 5. 拆分路径(获取文件扩展名) 32 | 33 | os.path.splitext('/path/to/file.txt') 34 | #('/path/to/file', '.txt') 35 | 6. 重命名文件 36 | 37 | os.rename('test.txt', 'test.py') 38 | 7. 删除文件 39 | 40 | os.remove('test.py') 41 | 42 | 8. 复制文件 43 | 44 | import shutil 45 | 46 | shutil.copy('user.txt','user.json') 47 | 1. getcwd() 48 | 49 | ``` 50 | #-*-coding:UTF-*- 51 | import os 52 | print('文件所在的目录为%s:'%(os.getcwd())) 53 | # ./表示当前目录 54 | #../表示上层目录 55 | print('当前目录下的文件和目录%s'%(os.listdir('./'))) 56 | 57 | #列出当前目录下的所有目录 58 | my_dirs=[x for x in os.listdir('.') if os.path.isdir(x)] 59 | 60 | #列出所有的.py文件 61 | 62 | my_py=[x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py'] 63 | ``` 64 | 2. demo-显示所有视频格式文件,mp4,avi,rmvb 65 | 66 | ``` 67 | import os 68 | 69 | def search_file(start_dir, target) : 70 | os.chdir(start_dir) 71 | 72 | for each_file in os.listdir(os.curdir) : 73 | ext = os.path.splitext(each_file)[1] 74 | if ext in target : 75 | vedio_list.append(os.getcwd() + os.sep + each_file + os.linesep) 76 | if os.path.isdir(each_file) : 77 | search_file(each_file, target) # 递归调用 78 | os.chdir(os.pardir) # 递归调用后切记返回上一层目录 79 | 80 | start_dir = input('请输入待查找的初始目录:') 81 | program_dir = os.getcwd() 82 | 83 | target = ['.mp4', '.avi', '.rmvb'] 84 | vedio_list = [] 85 | 86 | search_file(start_dir, target) 87 | 88 | f = open(program_dir + os.sep + 'vedioList.txt', 'w') 89 | f.writelines(vedio_list) 90 | f.close() 91 | ``` 92 | 93 | 94 | -------------------------------------------------------------------------------- /python/01-part1/unitX-内置模块.md: -------------------------------------------------------------------------------- 1 | #内置模块 2 | 3 | 1. datetime 4 | 1. time 5 | 6 | 7 | ``` 8 | import time 9 | from datetime import datetime,timedelta 10 | # time不是用来取时间 11 | # for i in range(3): 12 | # print(i) 13 | # time.sleep(2) 14 | 15 | 16 | ``` 17 | 18 | 2. 获取当前时间 19 | 20 | ``` 21 | date_now=datetime.now() 22 | # print(date_now) 23 | 24 | # frm_date=date_now.strftime('%Y-%m-%d') 25 | # 26 | # print(frm_date) 27 | 28 | ``` 29 | 格式参数: 30 | 31 | %Y 带世纪部分的十制年份 32 | 33 | %m 十进制表示的月份 34 | 35 | %d 十进制表示的每月的第几天 36 | 37 | %H 24小时制的小时 38 | 39 | %M 十时制表示的分钟数 40 | 41 | %S 十进制的秒数 42 | 43 | %c 标准时间,如:04/25/17 14:35:14 类似于这种形式 44 | 45 | 3. 获取昨天或者明天的时候:---------------------- 46 | 47 | 48 | ``` 49 | # yesday=date_now + timedelta(days=-1) 50 | # # temmorow=date_now + timedelta(days=1) 51 | # temmorow=date_now + timedelta(seconds=24*60*60*3) 52 | # 53 | # print(temmorow) 54 | ``` 55 | 56 | 世界标准时间 57 | 58 | datetimeInt = datetime.datetime.utcnow() + datetime.timedelta(hours=1) 59 | 60 | 4. 时间格式的相互转换------------------------- 61 | 62 | 63 | ```# 1. 字符串转datetime 64 | string = '2017/11/10 02:29:58'.replace('/','-') 65 | # string = '2017-11-10 02:29:58' 66 | time1 = datetime.strptime(string, '%Y-%m-%d %H:%M:%S') 67 | print(time1) 68 | print(type(time1)) 69 | 70 | # 2. datetime转string 71 | time1_str = datetime.strftime(time1, '%Y-%m-%d %H:%M:%S') 72 | print(type(time1_str)) 73 | print(time1_str) 74 | 75 | # 3. 时间戳转时间对象 76 | 77 | time2=time.time() #时间戳 78 | time2_str = datetime.fromtimestamp(time2) 79 | 80 | print(time2_str) 81 | 82 | # 4. 时间对象转为时间戳 83 | timeStamp = int(time.mktime(date_now.timetuple())) 84 | print(timeStamp) 85 | 86 | # 5. 计算时间差 87 | 88 | days=(date_now-time1).days 89 | seconds=(date_now-time1).seconds 90 | print(seconds) 91 | ``` 92 | 2. json 93 | 94 | JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式。它基于ECMAScript的一个子集。 95 | 96 | Python3 中可以使用 json 模块来对 JSON 数据进行编解码,它包含了两个函数: 97 | * json.dumps 将Python 字典类型转换为 JSON 对象 98 | * json.loads 将 JSON 对象转换为 Python 字典 99 | 100 | ``` 101 | import json 102 | # 字典对象 103 | 104 | dict_lesson={ 105 | "name":"python", 106 | "score":3 107 | } 108 | # json.dumps 将Python 字典类型转换为 JSON 对象 109 | # json.loads 将 JSON 对象转换为 Python 字典 110 | print(dict_lesson['score']) 111 | 112 | json_lesson=json.dumps(dict_lesson) 113 | 114 | print(type(json_lesson)) #str 115 | print(type(json.loads(json_lesson))) #dict 116 | ``` 117 | 118 | 如果你要处理的是文件而不是字符串,你可以使用 json.dump() 和 json.load() 来编码和解码JSON数据 119 | 120 | ``` 121 | content=[ 122 | {"name":"nick","age":"12"}, 123 | {"name":"tom","age":"13"}, 124 | {"name":"helen","age":"22"}, 125 | {"name":"tony","age":"32"} 126 | ] 127 | 128 | with open('users.json', 'w') as f: 129 | json.dump(content, f) 130 | 131 | with open('users.json','r+') as f: 132 | data = json.load(f) 133 | print(data) 134 | print(data[2]['name']) 135 | 136 | ``` 137 | 3. collections 138 | 139 | 我们都知道,Python拥有一些内置的数据类型,比如str, int, list, tuple, dict等, collections模块在这些内置数据类型的基础上,提供了几个额外的数据类型: 140 | 141 | * namedtuple(): 生成可以使用名字来访问元素内容的tuple子类 142 | * deque: 双端队列,可以快速的从另外一侧追加和推出对象 143 | * Counter: 计数器,主要用来计数 144 | * OrderedDict: 有序字典 145 | * defaultdict: 带有默认值的字典 146 | 147 | 148 | 1. namedtuple() 149 | 150 | namedtuple主要用来产生可以使用名称来访问元素的数据对象,通常用来增强代码的可读性, 在访问一些tuple类型的数据时尤其好用。 151 | 152 | from collections import namedtuple 153 | 154 | websites = [ 155 | ('Sohu', 'http://www.google.com/', u'张朝阳'), 156 | ('Sina', 'http://www.sina.com.cn/', u'王志东'), 157 | ('163', 'http://www.163.com/', u'丁磊') 158 | ] 159 | 160 | Website = namedtuple('Website', ['name', 'url', 'founder']) 161 | 162 | for website in websites: 163 | website = Website._make(website) 164 | print website 165 | 166 | 167 | 2. deque 168 | 169 | deque其实是 double-ended queue 的缩写,翻译过来就是双端队列,它最大的好处就是实现了从队列 头部快速增加和取出对象: .popleft(), .appendleft() 。 170 | 171 | 你可能会说,原生的list也可以从头部添加和取出对象啊?就像这样: 172 | 173 | l.insert(0, v) 174 | l.pop(0) 175 | 但是值得注意的是,list对象的这两种用法的时间复杂度是 O(n) ,也就是说随着元素数量的增加耗时呈 线性上升。而使用deque对象则是 O(1) 的复杂度,所以当你的代码有这样的需求的时候, 一定要记得使用deque。 176 | 177 | 作为一个双端队列,deque还提供了一些其他的好用方法,比如 rotate 等。 178 | 179 | 3. Counter 180 | 181 | 计数器是一个非常常用的功能需求,collections也贴心的为你提供了这个功能。 182 | 183 | from collections import Counter 184 | 185 | s = '''A Counter is a dict subclass for counting hashable objects. It is an unordered collection where elements are stored as dictionary keys and their counts are stored as dictionary values. Counts are allowed to be any integer value including zero or negative counts. The Counter class is similar to bags or multisets in other languages.'''.lower() 186 | 187 | c = Counter(s) 188 | # 获取出现频率最高的5个字符 189 | print c.most_common(5) 190 | 4. OrderedDict 191 | 192 | 在Python中,dict这个数据结构由于hash的特性,是无序的,这在有的时候会给我们带来一些麻烦, 幸运的是,collections模块为我们提供了OrderedDict,当你要获得一个有序的字典对象时,用它就对了。 193 | 194 | from collections import OrderedDict 195 | 196 | items = ( 197 | ('A', 1), 198 | ('B', 2), 199 | ('C', 3) 200 | ) 201 | 202 | regular_dict = dict(items) 203 | ordered_dict = OrderedDict(items) 204 | 205 | print 'Regular Dict:' 206 | for k, v in regular_dict.items(): 207 | print k, v 208 | 209 | print 'Ordered Dict:' 210 | for k, v in ordered_dict.items(): 211 | print k, v 212 | 213 | 5. more 214 | 215 | https://docs.python.org/3.7/library/collections.html#userdict-objects -------------------------------------------------------------------------------- /python/01-part2/Untitled.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [], 3 | "metadata": {}, 4 | "nbformat": 4, 5 | "nbformat_minor": 2 6 | } 7 | -------------------------------------------------------------------------------- /python/01-part2/images/修饰符.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhanforgit/python/2fc2d72bc7b08f3da8886d04150c7b918994ae28/python/01-part2/images/修饰符.png -------------------------------------------------------------------------------- /python/01-part2/images/元字符.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhanforgit/python/2fc2d72bc7b08f3da8886d04150c7b918994ae28/python/01-part2/images/元字符.png -------------------------------------------------------------------------------- /python/01-part2/images/量词.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhanforgit/python/2fc2d72bc7b08f3da8886d04150c7b918994ae28/python/01-part2/images/量词.png -------------------------------------------------------------------------------- /python/01-part2/python高级-课件.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhanforgit/python/2fc2d72bc7b08f3da8886d04150c7b918994ae28/python/01-part2/python高级-课件.pdf -------------------------------------------------------------------------------- /python/01-part2/unit1-面向对象.md: -------------------------------------------------------------------------------- 1 | # 面向对象 2 | ### 基础 3 | === 4 | 1. oop 5 | 6 | 面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。 7 | Python类提供了面向对象编程的所有标准功能:类继承机制允许多个基类,派生类可以重写其基类或类的任何方法,并且方法可以调用具有相同名称的基类的方法。对象可以包含任意数量和种类的数据。与模块一样,类也具有Python的动态特性:它们是在运行时创建的,并且可以在创建后进一步修改。 8 | 2. 定义类 9 | 10 | ``` 11 | class Employee: 12 | '所有员工的基类' 13 | # empCount 变量是一个类变量,它的值将在这个类的所有实例之间共享。你可以在内部类或外部类使用 Employee.empCount 访问。 14 | empCount = 0 15 | 16 | # 方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法 17 | def __init__(self, name, salary): 18 | self.name = name 19 | self.salary = salary 20 | Employee.empCount += 1 21 | 22 | # self 代表类的实例,self 在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。 23 | def displayCount(self): 24 | print ("Total Employee %d" % Employee.empCount) 25 | print (self.__class__) 26 | 27 | def displayEmployee(self): 28 | print("Name : ", self.name, ", Salary: ", self.salary) 29 | ee1= Employee('NICK',100000) 30 | ee2= Employee('ROSE',100000) 31 | 32 | ee1.displayCount() 33 | ee2.displayEmployee() 34 | ``` 35 | >类属性使用 类名.属性名 的方式去访问,对象也可以访问。但是如果对象修改,则只对当前对象适用(因为这是其实是增加对象属性) 36 | 3. 动态为对象添加、删除属性 37 | 38 | 只会影响到当前操作的对象 39 | 40 | ``` 41 | ee1= Employee('NICK',100000) 42 | ee2= Employee('ROSE',888888) 43 | 44 | ee1.age=22 45 | print(ee1.age) 46 | # del ee1.name 47 | ee1.displayEmployee() 48 | 49 | # print ee2.age #error 50 | 51 | print (hasattr(ee1, 'age') ) # 如果存在 'age' 属性返回 True。 52 | print (getattr(ee1, 'age') ) # 返回 'age' 属性的值 53 | setattr(ee2, 'age', 8) # 添加属性 'age' 值为 8 54 | print(ee2.age) 55 | delattr(ee1, 'age') # 删除属性 'age' 56 | ``` 57 | 4. 析构函数 58 | 59 | ``` 60 | def __del__(self): 61 | class_name = self.__class__.__name__ 62 | print(class_name, "销毁") 63 | ``` 64 | 65 | 5. 内置属性 66 | 67 | ``` 68 | print (Employee.__dict__) 69 | print (Employee.__doc__) 70 | # 类的所有父类构成元素(包含了一个由所有父类组成的元组) 71 | print (Employee.__bases__) 72 | ee1=Employee('NICK',200) 73 | dd2=ee1 74 | dd2.name='dog' 75 | # del ee1 76 | # ee1.displayEmployee() 77 | dd2.displayEmployee() 78 | print(isinstance(ee1,Employee)) 79 | print(isinstance(ee1,object)) 80 | ``` 81 | ### 高级 82 | === 83 | 6. 继承 84 | 85 | 86 | 类的继承 87 | 88 | 1:在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。 89 | 90 | 2:在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别在于类中调用普通函数时并不需要带上self参数 91 | 92 | 3:Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。 93 | 94 | ``` 95 | class Boss(Employee): 96 | def __init__(self,name,salary,jiangjin): 97 | super(Boss, self).__init__(name, salary) 98 | self.jiangjin = jiangjin 99 | 100 | 101 | def displayEmployee(self): 102 | print("Name : ", self.name, ", Salary: ", self.salary,'other jiangjin:',self.jiangjin) 103 | def __str__(self): 104 | pass 105 | ``` 106 | >python没有重载,因为函数名知识指向内存地址的变量。 107 | 7. 多重继承 108 | 109 | ``` 110 | #-*- coding:UTF-8 -*- 111 | 112 | # 多重继承 113 | 114 | class A(object): 115 | __scope='a scope' 116 | def __init__(self, a): 117 | print('init A...') 118 | self.a = a 119 | def show(self): 120 | print('i am A') 121 | 122 | class B(A): 123 | def __init__(self, a): 124 | super(B, self).__init__(a) 125 | print( 'init B...') 126 | def show(self): 127 | super(B,self).show() 128 | print(' and i am B too') 129 | 130 | class C(A): 131 | def __init__(self, a): 132 | super(C, self).__init__(a) 133 | print('init C...') 134 | 135 | def show(self): 136 | super(C, self).show() 137 | print(' and i am C too too') 138 | 139 | class D(B, C): 140 | def __init__(self, a): 141 | super(D, self).__init__(a) 142 | print('init D...') 143 | def show(self): 144 | super(D, self).show() 145 | print(' and i am D too too...') 146 | 147 | d=D(12) 148 | # print B.scope 149 | d.show() 150 | 151 | 152 | #d多重继承时为了从多个类中提取多个方法 153 | 154 | # 查看对象信息 155 | 156 | # print(isinstance(d,D)) 157 | # print(isinstance(d,A)) 158 | # 159 | # print(type(d)) 160 | # print(dir(d)) 161 | ``` 162 | 8. 你真的理解Python中MRO算法吗? 163 | 164 | MRO(Method Resolution Order):方法解析顺序。 165 | Python语言包含了很多优秀的特性,其中多重继承就是其中之一,但是多重继承会引发很多问题,比如二义性,Python中一切皆引用,这使得他不会像C++一样使用虚基类处理基类对象重复的问题,但是如果父类存在同名函数的时候还是会产生二义性,Python中处理这种问题的方法就是MRO。 166 | 167 | http://python.jobbole.com/85685/ 168 | 8. 使用接口的思想设计多重继承 169 | 170 | 整体可以分为类型类和功能类两种类,类型类实现主体继承树形结构,功能类作为独立的功能接口存在。 171 | 172 | ``` 173 | #-*- coding:UTF-8 -*- 174 | 175 | # 多重继承 176 | 177 | class Animal(object): 178 | def __init__(self,age): 179 | self.age=age 180 | 181 | # 大类: 182 | class Mammal(Animal): 183 | def __init__(self,age,foot): 184 | super(Mammal,self).__init__(age) 185 | self.foot=foot 186 | 187 | class Bird(Animal): 188 | def __init__(self,age,fly): 189 | super(Bird,self).__init__(age) 190 | self.fly=fly 191 | 192 | 193 | 194 | class RunnableMixIn(object): 195 | def run(self): 196 | print('Running...') 197 | 198 | class FlyableMixIn(object): 199 | def fly(self): 200 | print('Flying...') 201 | 202 | # 各种动物: 203 | class Dog(Mammal,RunnableMixIn): 204 | def __init__(self,age,foot,gender): 205 | super(Dog,self).__init__(age,foot) 206 | self.gender=gender 207 | def show(self): 208 | print('dog age is:',self.age,'ang have ',self.foot) 209 | class Bat(Mammal, RunnableMixIn, FlyableMixIn): 210 | pass 211 | 212 | class Parrot(Bird,RunnableMixIn, FlyableMixIn): 213 | pass 214 | 215 | class Ostrich(Bird,RunnableMixIn): 216 | pass 217 | 218 | dog=Dog(3,4,'male') 219 | 220 | dog.show() 221 | ``` -------------------------------------------------------------------------------- /python/01-part2/unit5-多线程进阶.md: -------------------------------------------------------------------------------- 1 | # 多线程-2 2 | 1. 线程池 3 | 2. 信号量Semahpore 4 | 3. Event 5 | 4. timer 6 | 5. 线程queue 7 | 6. paramiko模块 8 | 9 | 10 | [参考](https://www.cnblogs.com/smallmars/p/7149507.html) 11 | https://www.cnblogs.com/cocowool/p/6646044.html 12 | https://www.cnblogs.com/smallmars/p/7149507.html -------------------------------------------------------------------------------- /python/01-part2/unit6-单元测试源码.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhanforgit/python/2fc2d72bc7b08f3da8886d04150c7b918994ae28/python/01-part2/unit6-单元测试源码.zip -------------------------------------------------------------------------------- /python/01-part2/unitx-1生成器-迭代器.md: -------------------------------------------------------------------------------- 1 | ## 迭代器 2 | 1. 概述 3 | 4 | 迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。 5 | 6 | 2. 可迭代对象 7 | 8 | 迭代器提供了一个统一的访问集合的接口。只要是实现了__iter__()或 __getitem__()方法的对象,就可以使用迭代器进行访问。 9 | 10 | 序列:字符串、列表、元组 11 | 12 | 非序列:字典、文件 13 | 14 | 自定义类:用户自定义的类实现了__iter__()或__getitem__()方法的对象 15 | 16 | 迭代字典 17 | 18 |    d = {'a': 1, 'b': 2, 'c': 3} 19 | ​ 20 | for k in d: 21 | print(k) 22 | 23 | for k in d.keys(): 24 | print(k) 25 | 26 | for v in d.values(): 27 | print(v) 28 | 29 | for (k,v) in d.items(): 30 | print(k,v) 31 | 32 | 3. 迭代基础 33 | 34 | ``` 35 | f1=open('data.txt') 36 | 37 | # for line in f1.readlines(): #把所有行读入内存,遇到大文件效率差 38 | # print(line) 39 | 40 | # for line in f1: 41 | # print(line) 42 | 43 | # 文件对象就是自己的迭代器 44 | 45 | print(f1.__next__()) 46 | print(f1.__next__()) 47 | 48 | # 为了手动支持迭代,python3.0提供了一个next()方法,他会自动调用对象的_next_() 49 | 50 | print(next(f1)) 51 | ``` 52 | 53 | 4. iter() 和 next() 54 | 55 | 56 | 字符串/数组本身没有迭代对象 57 | 58 | ``` 59 | s='hello' 60 | 61 | iter01=iter(s) 62 | print(next(iter01)) 63 | print(next(iter01)) 64 | 65 | 66 | arr=[1,2,3,4] 67 | E=iter(arr) 68 | # print(E.__next__()) 69 | # print(next(E)) 70 | 71 | while True: 72 | try: 73 | X=E.__next__() 74 | except StopIteration: 75 | break 76 | print(X) 77 | ``` 78 | >字典对象有一个迭代器,每次返回字典的key 79 | 80 | ``` 81 | params={'name':'tom','age':12} 82 | for key in params: 83 | ... 84 | #所以不要下面的写法 85 | for key in params.keys(): 86 | ... 87 | 88 | ``` 89 | 5. range() 90 | 91 | range()支持多个迭代器,而其他内置函数不支持 92 | ``` 93 | arr=list(range(20)) 94 | print(arr) 95 | 96 | R=iter(range(100)) 97 | 98 | print(next(R)) 99 | print(next(R)) 100 | print(next(R)) 101 | 102 | 103 | ``` 104 | 5. enumerate函数 105 | 106 | Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身: 107 | 108 | mylist=['A', 'B', 'C'] 109 | for i, value in enumerate(mylist): 110 | print(i,value) 111 | 112 | 6. map() zip() filter() 113 | 和range()不同,以上三个函数都是自己的迭代器 114 | 115 | ``` 116 | M=map(abs,[2,-3,-1,3]) 117 | print(next(M)) 118 | ``` 119 | 120 | 121 | ## 生成器 122 | 123 | 1. 什么是生成器 124 | 125 | 通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。 126 | 127 | 所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。 128 | 129 | 2. 创建一个generator:方式一 130 | 131 | 只要把一个列表生成式的[]改成(),就创建了一个generator: 132 | 133 | L = [x * x for x in range(10)] 134 | #改为 135 | g = (x * x for x in range(10)) 136 | 137 | 如果要一个一个打印出来,可以通过generator的next()方法: 138 | 139 | print(g.__next__()) 140 | 141 | #或者 142 | 143 | print(next(g)) 144 | 145 | 简单的方式 146 | ​ 147 | for i in g: 148 | 149 | print(i) 150 | 3. 创建一个generator:方式二 151 | 152 | generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。 153 | 154 | 比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到: 155 | 156 | def fib(max): 157 | n, a, b = 0, 0, 1 158 | while n < max: 159 | print(b) 160 | a, b = b, a + b 161 | n = n + 1 162 | 163 | fib(10) 164 | 165 | >仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。 166 | 167 | >也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print b改为yield b就可以了: 168 | 169 | def fib(max): 170 | n, a, b = 0, 0, 1 171 | while n < max: 172 | yield b 173 | a, b = b, a + b 174 | n = n + 1 175 | 176 | nums=fib(10) 177 | 178 | for n in nums: 179 | print(n) 180 | 181 | 182 | ## 闭包 183 | 1. 闭包设计范式 184 | 185 | # def counter(index=0): 186 | # count=[index] 187 | # def incr(): 188 | # count[0]+=1 189 | # return count[0] 190 | # return incr 191 | 192 | 193 | ​ 194 | def counter(index=0): 195 | count=index 196 | def incr(): 197 | nonlocal count 198 | count+=1 199 | del count 200 | return count 201 | return incr 202 | 203 | inc=counter(5) 204 | 205 | print(inc()) 206 | print(inc()) 207 | 208 | 209 | ​ 210 | inc2=counter(50) 211 | 212 | 213 | ​ 214 | print(inc2()) 215 | print(inc2()) 216 | 217 | print(inc()) 218 | print(inc()) 219 | 220 | **注意** 221 | 222 | 1. 闭包优化了变量,原本需要类对象完成的工作,闭包就可以完成 223 | 2. 由于闭包引用了外部函数的局部变量,则外部函数的局部变量不会被及时释放,所以消耗内存。 -------------------------------------------------------------------------------- /python/01-part2/unitx-2垃圾回收.md: -------------------------------------------------------------------------------- 1 | ## 垃圾回收 2 | 1. 小对象对象池 3 | 4 | 整数在程序中的使用非常广泛,Python为了优化速度,使用了小整数对象池, 避免为整数频繁申请和销毁内存空间。 5 | 6 | Python 对小整数的定义是 [-5, 256] 这些整数对象是提前建立好的,不会被垃圾回收。在一个 Python 的程序中,无论这个整数处于LEGB中的哪个位置, 7 | 8 | 所有位于这个范围内的整数使用的都是同一个对象。同理,单个字母也是这样的。 9 | 10 | 我们可以通过引用计数查看: 11 | 12 | import sys 13 | a=2 14 | b=2 15 | print(sys.getrefcount(a)) 16 | 17 | print(id(a)) 18 | print(id(b)) 19 | 20 | print(a is b) #true 21 | print(a==b) #true 22 | 23 | 简单字符串(由数字、字母、下划线组成)也会加入小对象对象池 24 | 25 | s1='hello' 26 | s2='hello' 27 | 28 | s1 is s2 #true 29 | 30 | s3='hello world' 31 | s4='hello world' 32 | 33 | s4 is s3 #false 34 | 35 | s5='hello_world' 36 | s6='hello_world' 37 | 38 | s5 is s6 #true 39 | 40 | intern机制处理空格一个单词的复用机会大,所以创建一次,有空格创建多次,但是字符串长度大于20,就不是创建一次了。 41 | 42 | s1 = "abcd" 43 | s2 = "abcd" 44 | print(s1 is s2)# True 45 | 46 | s1 = "a" * 20 47 | s2 = "a" * 20 48 | print(s1 is s2)# True 49 | 50 | s1 = "a" * 21 51 | s2 = "a" * 21 52 | print(s1 is s2)# False 53 | 54 | s1 = "ab" * 10 55 | s2 = "ab" * 10 56 | print(s1 is s2)# True 57 | 58 | s1 = "ab" * 11 59 | s2 = "ab" * 11 60 | print(s1 is s2)# False 61 | 62 | 63 | 2. 大整数对象池。 64 | 65 | 说明: 66 | 67 | 终端是每次执行一次,所以每次的大整数都重新创建,而在pycharm中,每次运行是所有代码都加载都内存中,属于一个整体,所以 68 | 69 | 这个时候会有一个大整数对象池,即处于一个代码块的大整数是同一个对象。c1 和d1 处于一个代码块,而c1.b和c2.b分别有自己的代码块,所以不相等。 70 | 71 | 大数据对象不公用内存,引用计数为0则销毁。 72 | 73 | c1 = 1000 74 | d1 = 1000 75 | print(c1 is d1) # True 76 | 77 | class C1(object): 78 | a = 100 79 | b = 100 80 | c = 1000 81 | d = 1000 82 | 83 | 84 | class C2(object): 85 | a = 100 86 | b = 1000 87 | 88 | 89 | print(C1.a is C1.b) # True 90 | print(C1.a is C2.a) # True 91 | print(C1.c is C1.d) # True 92 | print(C1.b is C2.b) # False 93 | 94 | -------------------------------------------------------------------------------- /python/01-part2/单元测试源码/calculate_func.py: -------------------------------------------------------------------------------- 1 | def add(a, b): 2 | return a + b 3 | 4 | 5 | def minus(a, b): 6 | return a - b 7 | 8 | 9 | def multi(a, b): 10 | return a * b 11 | 12 | 13 | def divide(a, b): 14 | return a / b 15 | 16 | 17 | def login(username, password): 18 | if username == 'vip001' and password == '123456': 19 | return 'vip' 20 | else: 21 | return False 22 | def buy(token): 23 | if token == 'vip': 24 | return True 25 | else: 26 | return False -------------------------------------------------------------------------------- /python/01-part2/单元测试源码/test_calculate_func.py: -------------------------------------------------------------------------------- 1 | #导入unittest模块 2 | import unittest 3 | from calculate_func import * 4 | from parameterized import parameterized 5 | 6 | class TestCalculateFunc(unittest.TestCase): 7 | """Test mathfuc.py""" 8 | # num = 1 9 | @parameterized.expand( 10 | [ 11 | ['xiaogang', '123456', True], # 可以是list,也可以是元祖 12 | ['', '123456', True], 13 | ['xiaogang', '', False], 14 | ['adgadg', '123456', False] 15 | ] 16 | ) 17 | 18 | # def setUp(self): 19 | # print("do something before test.Prepare environment.") 20 | # 21 | # def tearDown(self): 22 | # print("do something after test.Clean up.") 23 | # @classmethod 24 | # def setUpClass(cls): 25 | # print("This setUpClass() method only called once.") 26 | # # cls.num=0 27 | # 28 | # @classmethod 29 | # def tearDownClass(cls): 30 | # print("This tearDownClass() method only called once too.") 31 | # # cls.num=2 32 | 33 | 34 | def test_login(self, username, passwd, flag): # 这里的参数对应上述列表里的元素,运行的时候会遍历上述列表里的二维列表直到所有元素都调用运行完成 35 | '''登录''' 36 | res = login(username, passwd) 37 | self.assertEqual(res, flag) 38 | 39 | # @unittest.skipIf(num>0,"num的值没有大于零") #此处调用类属性不需要加类名 40 | def test_add(self): 41 | """Test method add(a, b)""" 42 | self.assertEqual(3, add(1, 2)) 43 | self.assertNotEqual(2, add(2, 2)) 44 | 45 | 46 | def test_minus(self): 47 | """Test method minus(a, b)""" 48 | self.assertEqual(1, minus(3, 2)) 49 | def test_multi(self): 50 | """Test method multi(a, b)""" 51 | self.assertEqual(6, multi(2, 3)) 52 | def test_divide(self): 53 | """Test method divide(a, b)""" 54 | self.assertEqual(2, divide(6, 3)) 55 | self.assertEqual(2.5, divide(5, 2)) 56 | 57 | def login(self): # 注意,这里不以test开头命名,就是一普通方法,在执行测试用例的时候并不会运行,调用的时候才会 58 | res = login('vip001', '123456') 59 | self.assertEqual(res, 'vip') 60 | return res 61 | 62 | def test_login_cj(self): 63 | res = self.login() # 调用登录方法,获取sign 64 | self.jp = buy(res) 65 | self.assertEqual(self.jp, True) 66 | if __name__ == '__main__': 67 | unittest.main(verbosity=2) -------------------------------------------------------------------------------- /python/01-part2/单元测试源码/test_suite.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from test_calculate_func import TestCalculateFunc 3 | from HTMLTestRunner import HTMLTestRunner 4 | 5 | if __name__ == '__main__': 6 | suite = unittest.TestSuite() 7 | 8 | # tests = [TestCalculateFunc("test_add"), TestCalculateFunc("test_minus"), TestCalculateFunc("test_divide")] 9 | # suite.addTests(tests) 10 | # # 直接用addTest方法添加单个TestCase 11 | # suite.addTest(TestCalculateFunc("test_multi")) 12 | 13 | # 用addTests + TestLoader 14 | # loadTestsFromName(),传入'模块名.TestCase名' 15 | # suite.addTests(unittest.TestLoader().loadTestsFromName('test_calculate_func.TestCalculateFunc')) 16 | # suite.addTests(unittest.TestLoader().loadTestsFromNames(['test_calculate_func.TestCalculateFunc'])) 17 | 18 | # loadTestsFromTestCase(),传入TestCase 19 | suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCalculateFunc)) 20 | # runner = unittest.TextTestRunner(verbosity=2) 21 | # runner.run(suite) 22 | with open('HTMLReport.html', 'w') as f: 23 | runner = HTMLTestRunner(stream=f, 24 | title='MathFunc Test Report', 25 | description='generated by HTMLTestRunner.', 26 | verbosity=2 27 | ) 28 | runner.run(suite) -------------------------------------------------------------------------------- /python/01-part2/对象关系图.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzhanforgit/python/2fc2d72bc7b08f3da8886d04150c7b918994ae28/python/01-part2/对象关系图.jpg -------------------------------------------------------------------------------- /spider/1-基础/Xpath.md: -------------------------------------------------------------------------------- 1 | # Xpath 2 | **作者:詹亮** 3 | 4 | 5 | 1. 节点类型 6 | 1. 选取节点 7 | 8 | 9 | | 表达式 | 描述 | 10 | | --- | --- | 11 | | nodename | 选取此节点的所有子节点。 | 12 | | / | 从根节点选取| 13 | |//| 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 | 14 | | . | 选取当前节点。 | 15 | | .. | 选取当前节点的父节点。 | 16 | | @ | 选取属性。 | 17 | 18 | 3. 带谓词的选取 19 | 20 | | 路径表达式 | 结果 | 21 | | --- | --- | 22 | |/bookstore/book[1] |选取属于 bookstore 子元素的第一个 book 元素。| 23 | |/bookstore/book[last()] |选取属于 bookstore 子元素的最后一个 book 元素。| 24 | |/bookstore/book[last()-1] |选取属于 bookstore 子元素的倒数第二个 book 元素。| 25 | |/bookstore/book[position()<3] |选取最前面的两个属于 bookstore 元素的子元素的 book 元素。| 26 | |//title[@lang] |选取所有拥有名为 lang 的属性的 title 元素。| 27 | |//title[@lang='eng'] |选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。| 28 | |/bookstore/book[price>35.00] |选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。| 29 | |/bookstore/book[price>35.00]/title |选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。| 30 | 31 | **选取未知节点** 32 | 33 | |路径表达式| 结果| 34 | | --- | --- | 35 | |/bookstore/* |选取 bookstore 元素的所有子元素。| 36 | |//* |选取文档中的所有元素。| 37 | |//title[@*] |选取所有带有属性的 title 元素。| 38 | 39 | **选取若干路径** 40 | 41 | |路径表达式| 结果| 42 | | --- | --- | 43 | |//book/title \| //book/price |选取 book 元素的所有 title 和 price 元素。 44 | |//title \| //price |选取文档中的所有 title 和 price 元素。 45 | |/bookstore/book/title \| //price |选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。| 46 | 47 | 48 | -------------------------------------------------------------------------------- /spider/1-基础/unit1-爬虫基本认知.md: -------------------------------------------------------------------------------- 1 | # 爬虫基本认知 2 | **作者:詹亮** 3 | 4 | 5 | 1. 什么是爬虫 6 | 7 | spider,即网络爬虫,大家可以理解为在网络上爬行的一直蜘蛛,互联网就比作一张大网,而爬虫便是在这张网上爬来爬去的蜘蛛咯,如果它遇到资源,那么它就会抓取下来。想抓取什么?这个由你来控制它咯。 8 | 9 | 比如它在抓取一个网页,在这个网中他发现了一条道路,其实就是指向网页的超链接,那么它就可以爬到另一张网上来获取数据。这样,整个连在一起的大网对这之蜘蛛来说触手可及,分分钟爬下来不是事儿。 10 | 11 | 2. 现在是"大数据时代",那数据从何而来? 12 | 13 | * 企业产生的用户数据:百度指数、阿里指数、TBI腾讯浏览指数、新浪微博指数 14 | 15 | * 数据平台购买数据:数据堂、国云数据市场、贵阳大数据交易所 16 | 17 | * 政府/机构公开的数据:中华人民共和国国家统计局数据、世界银行公开数据、联合国数据、纳斯达克。 18 | 19 | * 数据管理咨询公司:麦肯锡、埃森哲、艾瑞咨询 20 | 21 | * 爬取网络数据:如果需要的数据市场上没有,或者不愿意购买,那么可以选择招/做一名爬虫工程师,自己动手丰衣足食。拉勾网Python爬虫职位 22 | 23 | 4. 关于Python爬虫,我们需要学习的有: 24 | 25 | 1. Python基础语法学习(基础知识) 26 | 27 | 2. HTML页面的内容抓取(数据抓取) 28 | 29 | 3. HTML页面的数据提取(数据清洗) 30 | 31 | 4. Scrapy框架以及scrapy-redis分布式策略(第三方框架) 32 | 33 | 6. spider(Spider)、反爬虫(Anti-Spider)、反反爬虫(Anti-Anti-Spider)之间的斗争.... 34 | 35 | 2. 通用爬虫和聚焦爬虫 36 | 37 | 1. 通用 38 | baidu google bing 39 | 40 | 2. 聚焦 41 | 42 | 2. 浏览网页的过程 43 | 44 | 在用户浏览网页的过程中,我们可能会看到许多好看的图片,比如 http://image.baidu.com/ ,我们会看到几张的图片以及百度搜索框,这个过程其实就是用户输入网址之后,经过DNS服务器,找到服务器主机,向服务器发出一个请求,服务器经过解析之后,发送给用户的浏览器 HTML、JS、CSS 等文件,浏览器解析出来,用户便可以看到形形色色的图片了。 45 | 46 | 因此,用户看到的网页实质是由 HTML 代码构成的,爬虫爬来的便是这些内容,通过分析和过滤这些 HTML 代码,实现对图片、文字等资源的获取。 47 | 48 | 3. URL的含义 49 | 50 | URL,即统一资源定位符,也就是我们说的网址,统一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。 51 | URL的格式由三部分组成: 52 | ①第一部分是协议(或称为服务方式)。 53 | ②第二部分是存有该资源的主机IP地址(有时也包括端口号)。 54 | ③第三部分是主机资源的具体地址,如目录和文件名等。 55 | 爬虫爬取数据时必须要有一个目标的URL才可以获取数据,因此,它是爬虫获取数据的基本依据,准确理解它的含义对爬虫学习有很大帮助。 56 | 57 | [提供给开发者 10 款最好的 Python IDE](https://www.oschina.net/news/57468/best-python-ide-for-developers) 58 | 59 | -------------------------------------------------------------------------------- /spider/1-基础/unit2-1-案例-批量爬取淘宝数据.py: -------------------------------------------------------------------------------- 1 | from urllib import request,parse 2 | import random 3 | 4 | import ssl 5 | 6 | ua_list = [ 7 | "Mozilla/5.0 (Windows NT 6.1; ) Apple.... ", 8 | "Mozilla/5.0 (X11; CrOS i686 2268.111.0)... ", 9 | "Mozilla/5.0 (Macintosh; U; PPC Mac OS X.... ", 10 | "Mozilla/5.0 (Macintosh; Intel Mac OS... " 11 | ] 12 | def loadPage(url,filename): 13 | print("正在下载" + filename) 14 | 15 | headers = {"User-Agent": "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;"} 16 | 17 | user_agent = random.choice(ua_list) 18 | ua_header = {"User-Agent": user_agent} 19 | req = request.Request(url, headers=ua_header) 20 | response = request.urlopen(req) 21 | return response.read() 22 | 23 | def writeFile(html, filename): 24 | """ 25 | 作用:保存服务器响应文件到本地磁盘文件里 26 | html: 服务器响应文件 27 | filename: 本地磁盘文件名 28 | """ 29 | print("正在存储" + filename) 30 | with open(filename, 'w') as f: 31 | f.write(html.decode()) 32 | print("-" * 20) 33 | 34 | def taoboSpider(url, beginPage, endPage): 35 | """ 36 | 作用:负责处理url,分配每个url去发送请求 37 | url:需要处理的第一个url 38 | beginPage: 爬虫执行的起始页面 39 | endPage: 爬虫执行的截止页面 40 | """ 41 | 42 | 43 | for page in range(beginPage, endPage + 1): 44 | pn = (page - 1) * 60 45 | 46 | filename = "第" + str(page) + "页.html" 47 | # 组合为完整的 url,并且pn值每次增加50 48 | fullurl = url + "&s=" + str(pn) 49 | #print fullurl 50 | 51 | # 调用loadPage()发送请求获取HTML页面 52 | html = loadPage(fullurl, filename) 53 | # 将获取到的HTML页面写入本地磁盘文件 54 | writeFile(html, filename) 55 | 56 | if __name__ == "__main__": 57 | 58 | kw ='' 59 | # 输入起始页和终止页,str转成int类型 60 | beginPage = 1 61 | endPage = 4 62 | ssl._create_default_https_context = ssl._create_unverified_context 63 | url = "https://s.taobao.com/list?spm=a217f.8051907.312344.2.7e383308OlmjDv&q=T%E6%81%A4&cat=16&seller_type=taobao&oetag=6745&source=qiangdiao&bcoffset=12&" 64 | key = parse.urlencode({"kw" : kw}) 65 | 66 | # 组合后的url示例:http://tieba.baidu.com/f?kw=lol 67 | url = url + key 68 | taoboSpider(url, beginPage, endPage) -------------------------------------------------------------------------------- /spider/1-基础/unit2-Urllib-opener.md: -------------------------------------------------------------------------------- 1 | # Handler处理器 和 自定义Opener 2 | **作者:詹亮** 3 | 4 | 5 | 1. 介绍 6 | 7 | opener是 urllib.OpenerDirector 的实例,我们之前一直都在使用的urlopen,它是一个特殊的opener(也就是模块帮我们构建好的)。 8 | 9 | 但是基本的urlopen()方法不支持代理、cookie等其他的HTTP/HTTPS高级功能。所以要支持这些功能: 10 | 11 | 使用相关的 Handler处理器 来创建特定功能的处理器对象; 12 | 然后通过 urllib.build_opener()方法使用这些处理器对象,创建自定义opener对象; 13 | 使用自定义的opener对象,调用open()方法发送请求。 14 | 如果程序里所有的请求都使用自定义的opener,可以使用urllib.install_opener() 将自定义的 opener 对象 定义为 全局opener,表示如果之后凡是调用urlopen,都将使用这个opener(根据自己的需求来选择) 15 | 16 | 2. 新建opener 17 | 18 | 19 | 20 | ​ 21 | 22 | from urllib import request,parse 23 | import urllib 24 | import ssl 25 | ssl._create_default_https_context = ssl._create_unverified_context 26 | # 构建一个HTTPHandler 处理器对象,支持处理HTTP请求 27 | # http_handler = request.HTTPHandler() 28 | 29 | # 构建一个HTTPHandler 处理器对象,支持处理HTTPS请求 30 | http_handler = request.HTTPSHandler() 31 | 32 | # 调用request.build_opener()方法,创建支持处理HTTP请求的opener对象 33 | opener = request.build_opener(http_handler) 34 | 35 | url='https://www.liepin.com/sh/zhaopin/pn1/?' \ 36 | 'd_pageSize=40&siTag=&d_headId=7523ef4c1e412df5e007f3cfd117447d&d_ckId=7523ef4c1e412df5e007f3cfd117447d&d_sfrom=' \ 37 | 'search_city&' 38 | str={ 39 | "key":"python", 40 | "d_curPage":0 41 | 42 | } 43 | # 44 | url=url+parse.urlencode(str) 45 | 46 | print(url) 47 | # 构建 Request请求 48 | request = request.Request(url) 49 | 50 | # 调用自定义opener对象的open()方法,发送request请求 51 | f = opener.open(request) 52 | 53 | # 获取服务器响应内容 54 | with open('liepin.html','w+') as fp: 55 | fp.write(f.read().decode()) 56 | 57 | >如果在 HTTPHandler()增加 debuglevel=1参数,还会将 Debug Log 打开,这样程序在执行的时候,会把收包和发包的报头在屏幕上自动打印出来,方便调试,有时可以省去抓包的工作。 58 | 59 | https_handler = urllib2.HTTPSHandler(debuglevel=1) 60 | 61 | 3. ProxyHandler处理器(代理设置) 62 | 63 | 使用代理IP,这是爬虫/反爬虫的第二大招,通常也是最好用的。 64 | 65 | 很多网站会检测某一段时间某个IP的访问次数(通过流量统计,系统日志等),如果访问次数多的不像正常人,它会禁止这个IP的访问。 66 | 67 | 所以我们可以设置一些代理服务器,每隔一段时间换一个代理,就算IP被禁止,依然可以换个IP继续爬取。 68 | 69 | 免费的开放代理获取基本没有成本,我们可以在一些代理网站上收集这些免费代理,测试后如果可以用,就把它收集起来用在爬虫上面。 70 | 71 | 免费短期代理网站举例: 72 | 73 | [西刺免费代理IP](http://www.xicidaili.com/) 74 | 75 | [快代理免费代理](http://www.kuaidaili.com/free/inha/) 76 | 77 | [Proxy360代理](http://www.proxy360.cn/default.aspx) 78 | 79 | [全网代理IP](http://www.goubanjia.com/free/index.shtml) 80 | 81 | 82 | **新建代理opener** 83 | 84 | from urllib import request,parse 85 | import urllib 86 | import ssl 87 | ssl._create_default_https_context = ssl._create_unverified_context 88 | 89 | # 构建了两个代理Handler,一个有代理IP,一个没有代理IP 90 | httpproxy_handler = request.ProxyHandler({"http" : "110.73.1.105:8123"}) 91 | nullproxy_handler = request.ProxyHandler({}) 92 | 93 | proxySwitch = True #定义一个代理开关 94 | 95 | # 通过 request.build_opener()方法使用这些代理Handler对象,创建自定义opener对象 96 | # 根据代理开关是否打开,使用不同的代理模式 97 | if proxySwitch: 98 | opener = request.build_opener(httpproxy_handler) 99 | else: 100 | opener = request.build_opener(nullproxy_handler) 101 | 102 | request = request.Request("http://www.baidu.com/") 103 | 104 | # 1. 如果这么写,只有使用opener.open()方法发送请求才使用自定义的代理,而urlopen()则不使用自定义代理。 105 | response = opener.open(request) 106 | 107 | # 2. 如果这么写,就是将opener应用到全局,之后所有的,不管是opener.open()还是urlopen() 发送请求,都将使用自定义代理。 108 | # urllib2.install_opener(opener) 109 | # response = urlopen(request) 110 | print(response.read()) 111 | 112 | 如果代理IP足够多,就可以像随机获取User-Agent一样,随机选择一个代理去访问网站。 113 | 114 | proxy_list = [ 115 | {"http" : "110.73.1.105:8123"}, 116 | {"http" : "110.73.40.20:8123"}, 117 | {"http" : "124.88.67.81:80"}, 118 | {"http" : "124.88.67.81:80"}, 119 | {"http" : "124.88.67.81:80"} 120 | ] 121 | 122 | # 随机选择一个代理 123 | proxy = random.choice(proxy_list) 124 | httpproxy_handler = request.ProxyHandler(proxy) 125 | 126 | 4. handler 127 | 128 | from urllib import request 129 | from urllib.error import URLError 130 | 131 | 132 | password_mgr = request.HTTPPasswordMgrWithDefaultRealm() 133 | top_level_url = 'http://localhost:8080/users/login' 134 | req = request.Request(top_level_url) 135 | try: 136 | # 创建一个密码管理者 137 | # 如果知道 realm, 我们可以使用他代替 ``None``. 138 | # password_mgr.add_password(None, top_level_url, username, password) 139 | password_mgr.add_password(None, top_level_url, '13812790421', '123456') 140 | 141 | # 创建了一个新的handler 142 | handler = request.HTTPBasicAuthHandler(password_mgr) 143 | 144 | # 创建 "opener" (OpenerDirector 实例) 145 | opener = request.build_opener(handler) 146 | a_url ='http://localhost:8080/users/getAllUsers' 147 | 148 | # 使用 opener 获取一个URL 149 | response =opener.open(a_url) 150 | 151 | # 安装 opener. 152 | # 现在所有调用 urllib2.urlopen 将用我们的 opener. 153 | urllib.install_opener(opener) 154 | except URLError as e: 155 | if hasattr(e, 'code'): 156 | print ('The server couldn\'t fulfill the request.') 157 | print ('Error code: ', e.code) 158 | elif hasattr(e, 'reason'): 159 | print ('We failed to reach a server.') 160 | print ('Reason: ', e.reason()) 161 | else: 162 | print (response.read()) 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /spider/1-基础/unit3-Urllib-Requests.md: -------------------------------------------------------------------------------- 1 | # Requests 2 | **作者:詹亮** 3 | 4 | 5 | 1. 介绍 6 | 7 | Requests 继承了urllib的所有特性。Requests支持HTTP连接保持和连接池,支持使用cookie保持会话,支持文件上传,支持自动确定响应内容的编码,支持国际化的 URL 和 POST 数据自动编码。 8 | 9 | requests 的底层实现其实就是 urllib3 10 | 11 | Requests的文档非常完备,中文文档也相当不错。Requests能完全满足当前网络的需求,支持Python 2.6—3.5,而且能在PyPy下完美运行。 12 | 13 | [开源地址](https://github.com/kennethreitz/requests) 14 | 15 | [中文文档 API](http://docs.python-requests.org/zh_CN/latest/index.html) 16 | 17 | 2. 安装 18 | 19 | pip install requests 20 | 21 | 3. get请求 22 | 23 | import requests 24 | 25 | url='https://www.liepin.com/sh/zhaopin/pn1/?' \ 26 | 'd_pageSize=40&siTag=&d_headId=7523ef4c1e412df5e007f3cfd117447d&d_ckId=7523ef4c1e412df5e007f3cfd117447d&d_sfrom=' \ 27 | 'search_city&' 28 | qs={ 29 | "key":"python", 30 | "d_curPage":0 31 | 32 | } 33 | 34 | headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} 35 | # params 接收一个字典或者字符串的查询参数,字典类型自动转换为url编码,不需要urlencode() 36 | response = requests.get(url, params = qs, headers = headers) 37 | 38 | # 查看响应内容,response.text 返回的是Unicode格式的数据 39 | print(response.text) 40 | # 查看响应内容,response.content返回的字节流数据 41 | print(response.content.decode('gbk')) 42 | 43 | # 查看完整url地址 44 | print(response.url) 45 | 46 | # 查看响应头部字符编码 47 | print(response.encoding) 48 | 49 | ### 解决乱码 50 | 51 | response.encoding=response.apparent_encoding 52 | 53 | # 查看响应码 54 | print(response.status_code) 55 | #查看以一个 Python 字典形式展示的服务器响应头 56 | 57 | print(response.headers) 58 | 59 | >但是这个字典比较特殊:它是仅为 HTTP 头部而生的。根据 RFC 2616, HTTP 头部是大小写不敏感的。 60 | 61 | 因此,我们可以使用任意大写形式来访问这些响应头字段: 62 | 63 | r.headers['Content-Type'] 64 | r.headers.get('content-type') 65 | 66 | 3. post 请求 67 | 68 | response = requests.post(url, data = data,headers=headers) 69 | 70 | 如果是json文件可以直接显示 71 | 72 | print(response.json()) 73 | 74 | >如果 JSON 解码失败, r.json() 就会抛出一个异常。例如,响应内容是 401 (Unauthorized),尝试访问 r.json() 将会抛出 ValueError: No JSON object could be decoded 异常。 75 | 76 | >需要注意的是,成功调用 r.json() 并**不**意味着响应的成功。有的服务器会在失败的响应中包含一个 JSON 对象(比如 HTTP 500 的错误细节)。这种 JSON 会被解码返回。要检查请求是否成功,请使用 r.raise_for_status() 或者检查 r.status_code 是否和你的期望相同。 77 | 78 | 4. 代理 79 | 80 | 使用代理IP,这是爬虫/反爬虫的第二大招,通常也是最好用的。 81 | 82 | 很多网站会检测某一段时间某个IP的访问次数(通过流量统计,系统日志等),如果访问次数多的不像正常人,它会禁止这个IP的访问。 83 | 84 | 所以我们可以设置一些代理服务器,每隔一段时间换一个代理,就算IP被禁止,依然可以换个IP继续爬取。 85 | 86 | 免费的开放代理获取基本没有成本,我们可以在一些代理网站上收集这些免费代理,测试后如果可以用,就把它收集起来用在爬虫上面。 87 | 88 | 免费短期代理网站举例: 89 | 90 | [西刺免费代理IP](http://www.xicidaili.com/) 91 | 92 | [快代理免费代理](http://www.kuaidaili.com/free/inha/) 93 | 94 | [Proxy360代理](http://www.proxy360.cn/default.aspx) 95 | 96 | [全网代理IP](http://www.goubanjia.com/free/index.shtml) 97 | 如果需要使用代理,你可以通过为任意请求方法提供 proxies 参数来配置单个请求 98 | 99 | import requests 100 | 101 | # 根据协议类型,选择不同的代理 102 | proxies = { 103 | "http": "http://12.34.56.79:9527", 104 | "https": "http://12.34.56.79:9527", 105 | } 106 | 107 | response = requests.get("http://www.baidu.com", proxies = proxies) 108 | print response.text 109 | 110 | 5. 处理HTTPS请求 SSL证书验证 111 | 112 | 要想检查某个主机的SSL证书,你可以使用 verify 参数(也可以不写) 113 | 114 | import requests 115 | response = requests.get("https://www.baidu.com/", verify=True) 116 | 117 | # 也可以省略不写 118 | # response = requests.get("https://www.baidu.com/") 119 | print(r.text) 120 | 121 | 6. Cookies 和 Session 122 | 123 | 1. cookies 124 | 125 | 如果一个响应中包含了cookie,那么我们可以利用 cookies参数拿到: 126 | 127 | 128 | import requests 129 | 130 | response = requests.get("http://www.baidu.com/") 131 | 132 | # 7. 返回CookieJar对象: 133 | cookiejar = response.cookies 134 | 135 | # 8. 将CookieJar转为字典: 136 | cookiedict = requests.utils.dict_from_cookiejar(cookiejar) 137 | 138 | print cookiejar 139 | 140 | print cookiedict 141 | 运行结果: 142 | 143 | ]> 144 | 145 | {'BDORZ': '27315'} 146 | 147 | 如果准备发送一个cookies给服务器 148 | 149 | response = requests.get("http://www.baidu.com/",cookies={'BDORZ': '27318'}) 150 | 2. Session 151 | 152 | 在 requests 里,session对象是一个非常常用的对象,这个对象代表一次用户会话:从客户端浏览器连接服务器开始,到客户端浏览器与服务器断开。 153 | 154 | 会话能让我们在跨请求时候保持某些参数,比如在同一个 Session 实例发出的所有请求之间保持 cookie 。 155 | 156 | 模拟人人网登录 157 | 158 | import requests 159 | 160 | # 1. 创建session对象,可以保存Cookie值 161 | ssion = requests.session() 162 | 163 | # 2. 处理 headers 164 | headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} 165 | 166 | # 3. 需要登录的用户名和密码 167 | data = {"email":"13812790420", "password":"zl321324"} 168 | 169 | # 4. 发送附带用户名和密码的请求,并获取登录后的Cookie值,保存在ssion里 170 | ssion.post("http://www.renren.com/PLogin.do", data = data) 171 | 172 | # 5. ssion包含用户登录后的Cookie值,可以直接访问那些登录后才可以访问的页面 173 | response = ssion.get("http://www.renren.com/969803141/profile") 174 | 175 | # 6. 打印响应内容 176 | print(response.text) 177 | 178 | 179 | 模拟豆瓣登录。然后查看个人日志 180 | 181 | import requests 182 | s = requests.Session() 183 | # 登录接口 184 | url_login = 'https://accounts.douban.com/login' 185 | # 登录后查看日志 186 | url_note = 'https://www.douban.com/note/707553111/' 187 | 188 | formdata = { 189 | 'source': 'index_nav', 190 | 'redir': 'https://www.douban.com', 191 | 'form_email': '13812790420', 192 | 'form_password': '321324', 193 | 'login': u'登录' 194 | } 195 | headers = { 196 | 'user-agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'} 197 | 198 | r = s.post(url_login, data=formdata, headers=headers) 199 | 200 | response=s.get(url_note) 201 | 202 | print(response.text) 203 | -------------------------------------------------------------------------------- /spider/1-基础/unit4_1-页面解析-XML.md: -------------------------------------------------------------------------------- 1 | # spider-页面解析-XML 2 | **作者:詹亮** 3 | 4 | 5 | 2. XML 6 | 7 | 1. 什么是XML 8 | 9 | * XML 指可扩展标记语言(EXtensible Markup Language) 10 | * XML 是一种标记语言,很类似 HTML 11 | * XML 的设计宗旨是传输数据,而非显示数据 12 | * XML 的标签需要我们自行定义。 13 | * XML 被设计为具有自我描述性。 14 | * XML 是 W3C 的推荐标准 15 | 16 | 2. 什么是XPath? 17 | 18 | XPath (XML Path Language) 是一门在 XML 文档中查找信息的语言,可用来在 XML 文档中对元素和属性进行遍历。 19 | 20 | XPath 开发工具 21 | 22 | - 开源的XPath表达式编辑工具:XMLQuire(XML格式文件可用) 23 | - Chrome插件 XPath Helper 24 | - Firefox插件 XPath Checker 25 | 26 | 3. 示例文档 27 | 28 | 29 | 30 | 31 | 32 | 33 | Everyday Italian 34 | Giada De Laurentiis 35 | 2005 36 | 30.00 37 | 38 | 39 | 40 | Harry Potter 41 | J K. Rowling 42 | 2005 43 | 29.99 44 | 45 | 46 | 47 | XQuery Kick Start 48 | James McGovern 49 | Per Bothner 50 | Kurt Cagle 51 | James Linn 52 | Vaidyanathan Nagarajan 53 | 2003 54 | 49.99 55 | 56 | 57 | 58 | Learning XML 59 | Erik T. Ray 60 | 2003 61 | 39.95 62 | 63 | 64 | 65 | 4. 安装lxml 66 | 67 | pip install lxml 68 | 4. 常用方法 69 | 70 | 1. etree.parse() 71 | 72 | 读取xml文件,结果为**xml对象**(不是字符串) 73 | 2. etree.HTML(string_html) 74 | 75 | 将字符串形势的html文件转换为xml对象 76 | 3. etree.tostring(htmlelement, encoding="utf-8").decode("utf-8") 77 | 78 | etree.tostring(html,encoding="utf-8", pretty_print=True).decode() 79 | 80 | 按字符串序列化HTML文档 81 | 5. 选择器 82 | 83 | |表达式| 描述| 84 | |---|---|---| 85 | |nodename| 选取此节点的所有子节点。| 86 | |/ |从根节点选取。| 87 | |// |从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。| 88 | |. |选取当前节点。| 89 | |.. |选取当前节点的父节点。| 90 | |@ |选取属性。| 91 | 92 | 范例 93 | 94 | bookstore 选取 bookstore 元素的所有子节点(如果只有一个的话)。 95 | /bookstore 选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径! 96 | bookstore/book 选取属于 bookstore 的直接子元素的所有 book 元素。 97 | //book 选取所有 book 子元素,而不管它们在文档中的位置。 98 | bookstore//book 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。 99 | bookstore//book/@lang 选取book元素的lang属性值。 100 | bookstore//book[@class="book-css"]/title 选取class属性值为“book-css”的book元素的title。 101 | //*[@class="bold"] 获取 class 值为 bold 的标签名 102 | 103 | **使用属性时,不要忘记@符号** 104 | > /表示直接子元素,//表示所有子孙元素 105 | 106 | 107 | 读取案例-xml 108 | 109 | #from lxml import etree #这样写后面会出现红色波浪线 110 | 111 | import lxml.html 112 | etree = lxml.html.etree 113 | # 读取文件:这个时候只时候读取xml格式的文件,显然局限性太强!!!!! 114 | html = etree.parse('data.xml') 115 | # 转化为字节字符串 116 | # result = etree.tostring(html, pretty_print=True) 117 | # print(type(html)) # 显示etree.parse() 返回类型 118 | # print(result) 119 | titles = html.xpath('/bookstore/book/title') 120 | 121 | for tt in titles: 122 | print(tt.text) 123 | 124 | # 如果不是直接子元素就要用// 125 | 126 | titles = html.xpath('/bookstore//title') 127 | 128 | for tt in titles: 129 | print(tt.text) 130 | 6. lxml读取html文件 131 | ​ 132 | 自己创建html解析器,增加parser参数 133 | 134 | import lxml.html 135 | etree = lxml.html.etree 136 | parser = etree.HTMLParser(encoding="utf-8") 137 | htmlelement = etree.parse("liepin.html", parser=parser) 138 | print(htmlelement) 139 | html_string=etree.tostring(htmlelement, encoding="utf-8").decode("utf-8") 140 | 141 | #读取innerText 142 | links=htmlelement.xpath('//div/div/span/a') 143 | 144 | for link in links: 145 | print(link.text) 146 | 147 | #读取属性的值 148 | 149 | with open('liepin.html','r+') as fp: 150 | content=fp.read() 151 | html=etree.HTML(content) 152 | links = html.xpath('//div/div/span/@title') 153 | for title in titles: 154 | print(title) 155 | 156 | 不缓存文件,直接读取爬取的html字符串 157 | 158 | response=requests.get(url) 159 | etree = lxml.html.etree 160 | parser = etree.HTMLParser(encoding="utf-8") 161 | # 162 | htmlelement = etree.HTML(response.text) -------------------------------------------------------------------------------- /spider/1-基础/unit4_2-页面解析-CSS.md: -------------------------------------------------------------------------------- 1 | # spider-页面解析-CSS 2 | **作者:詹亮** 3 | 4 | 5 | ## BeautifulSoup4 6 | 3. CSS 选择器:BeautifulSoup4 7 | 8 | lxml 只会局部遍历,而Beautiful Soup 是基于HTML DOM的,会载入整个文档,解析整个DOM树,因此时间和内存开销都会大很多,所以性能要低于lxml。 9 | 10 | BeautifulSoup 用来解析 HTML 比较简单,API非常人性化,支持CSS选择器、Python标准库中的HTML解析器,也支持 lxml 的 XML解析器。 11 | 12 | Beautiful Soup 3 目前已经停止开发,推荐现在的项目使用Beautiful Soup 4。使用 pip 安装即可:pip install beautifulsoup4 13 | 14 | 1. 安装 15 | 16 | pip install beautifulsoup4 17 | 2. tag (可以使用文档对象直接.标签名获取) 18 | 19 | from bs4 import BeautifulSoup 20 | 21 | # html='....' 22 | #创建 Beautiful Soup 对象 23 | # soup = BeautifulSoup(html) 24 | 25 | #打开本地 HTML 文件的方式来创建对象 26 | soup = BeautifulSoup(open('data.xml'),"lxml") 27 | 28 | #格式化输出 soup 对象的内容 29 | # print(soup.prettify()) 30 | print(soup.book) 31 | 32 | >我们可以利用 soup 加标签名轻松地获取这些标签的内容,这些对象的类型是bs4.element.Tag。但是注意,它查找的是在所有内容中的第一个符合要求的标签。 33 | print(soup.book) 34 | 3. 对于 Tag,它有两个重要的属性,是 name 和 attrs 35 | 36 | from bs4 import BeautifulSoup 37 | 38 | # html='....' 39 | #创建 Beautiful Soup 对象 40 | # soup = BeautifulSoup(html) 41 | 42 | #打开本地 HTML 文件的方式来创建对象 43 | soup = BeautifulSoup(open('liepin.html'),"lxml") 44 | 45 | #格式化输出 soup 对象的内容 46 | # print(soup.prettify()) 47 | 48 | nodes=soup.select('div.company-info p a') 49 | 50 | nodes=soup.select('div#div01 div.company-info > p[name="pr"] a') 51 | 52 | for node in nodes: 53 | #获取节点名称 54 | print(node.name) 55 | 56 | #获取节点所有属性 57 | print(node.attrs) 58 | 59 | #获取节点href属性的值 60 | print(node['href']) 61 | # print(node.get('href')) 62 | 63 | 64 | #获取节点的值 65 | print(node.string) 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /spider/2-scrapy/unit1-scrapy.md: -------------------------------------------------------------------------------- 1 | # scrapy 2 | **作者:詹亮** 3 | 4 | 5 | 6 | ### 安装环境 7 | 1. 站点 8 | 9 | [Scrapy框架官方网址](http://doc.scrapy.org/en/latest) 10 | 11 | [Scrapy中文维护站点](http://scrapy-chs.readthedocs.io/zh_CN/latest/index.html) 12 | 2. 安装 13 | 14 | pip install Scrapy 15 | 16 | >安装后,只要在命令终端输入 scrapy可以检验是否安装成功。 17 | 18 | windows安装错误: 19 | 20 | [Scrapy安装错误:](MicrosoftVisualC++14.0isrequired... 21 | https://blog.csdn.net/nima1994/article/details/74931621) 22 | 23 | 下载地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted 24 | 25 | ### 1.命令 26 | 27 | 28 | 29 | 1. 创建项目 30 | 31 | ``` 32 | scrapy startproject myproject 33 | ``` 34 | 35 | 项目目录结构: 36 | 下面来简单介绍一下各个主要文件的作用: 37 | 38 | - scrapy.cfg :项目的配置文件 39 | 40 | - mySpider/ :项目的Python模块,将会从这里引用代码 41 | 42 | - mySpider/items.py :项目的目标文件 43 | 44 | - mySpider/pipelines.py :项目的管道文件 45 | 46 | - mySpider/settings.py :项目的设置文件 47 | 48 | - mySpider/spiders/ :存储爬虫代码目录 49 | 2. 创建一个新的spider 50 | 51 | ``` 52 | scrapy genspider mydomain mydomain.com 53 | ``` 54 | 55 | 要建立一个Spider, 你必须用scrapy.Spider类创建一个子类,并确定了三个强制的属性 和 一个方法。 56 | 57 | 1. name = "" :这个爬虫的识别名称,必须是唯一的,在不同的爬虫必须定义不同的名字。 58 | 59 | 2. allow_domains = [] 是搜索的域名范围,也就是爬虫的约束区域,规定爬虫只爬取这个域名下的网页,不存在的URL会被忽略。 60 | 61 | 3. start_urls = () :爬取的URL元祖/列表。爬虫从这里开始抓取数据,所以,第一次下载的数据将会从这些urls开始。其他子URL将会从这些起始URL中继承性生成。 62 | 63 | 4. parse(self, response) :解析的方法,每个初始URL完成下载后将被调用,调用的时候传入从每一个URL传回的Response对象来作为唯一参数,主要作用如下: 64 | 65 | 负责解析返回的网页数据(response.body),提取结构化数据(生成item) 66 | 生成需要下一页的URL请求。 67 | 68 | 3. 查看所有爬虫 69 | 70 | ``` 71 | scrapy list 72 | ``` 73 | 执行爬虫 74 | 75 | ``` 76 | scrapy crawl 77 | ``` 78 | 执行爬虫,并把结果保存到指定文件 79 | 80 | ``` 81 | scrapy crawl runoob -o taobo.json 82 | ``` 83 | 利用命令行,抓取指定URL的代码 84 | 85 | ``` 86 | scrapy fetch https://s.taobao.com/list?q=iphone 87 | ``` 88 | >备注的部分 89 | 90 | 4. DEMO 91 | 92 | 1. 构建item模型 93 | 打开mySpider目录下的items.py 94 | 95 | Item 定义结构化数据字段,用来保存爬取到的数据,有点像Python中的dict,但是提供了一些额外的保护减少错误。 96 | 97 | 可以通过创建一个 scrapy.Item 类, 并且定义类型为 scrapy.Field的类属性来定义一个Item(可以理解成类似于ORM的映射关系)。 98 | 99 | 接下来,创建一个ItcastItem 类,和构建item模型(model)。 100 | 101 | import scrapy 102 | from scrapy.item import Item, Field 103 | 104 | class MyteachspiderItem(scrapy.Item): 105 | # define the fields for your item here like: 106 | # name = scrapy.Field() 107 | pass 108 | 109 | class Website(Item): 110 | 111 | title = Field() 112 | link = Field() 113 | desc = Field() 114 | 115 | 2. 新建爬虫 116 | 117 | scrapy genspider runoob runoob.com 118 | 119 | 3. 定义爬虫 120 | 121 | # -*- coding: utf-8 -*- 122 | import scrapy 123 | 124 | from myTeachSpider.items import Website 125 | class RunoobSpider(scrapy.Spider): 126 | name = "runoob" 127 | allowed_domains = ["runoob.com"] 128 | start_urls = [ 129 | "http://www.runoob.com/html/html-tutorial.html", 130 | "http://www.runoob.com/css/css-tutorial.html", 131 | ] 132 | 133 | def parse(self, response): 134 | 135 | items=[] 136 | 137 | for sel in response.xpath('//ul/li'): 138 | item = Website() 139 | # extract()方法返回的都是unicode字符串 140 | # xpath返回的是包含一个元素的列表 141 | item['title'] = sel.xpath('a/text()').extract() 142 | item['link'] = sel.xpath('a/@href').extract() 143 | item['desc'] = sel.xpath('text()').extract() 144 | 145 | items.append(item) 146 | # 将获取的数据交给pipelines 147 | # yield item 148 | 149 | # 返回数据,不经过pipeline 150 | return items 151 | 152 | 4. 执行爬虫并保存到指定文件 153 | 154 | scrapy crawl runoob -o runoob.json 155 | 156 | 新建run.py 157 | 158 | from scrapy.cmdline import execute 159 | execute(['scrapy', 'crawl', 'runoobSpider']) 160 | 161 | #execute('scrapy crawl runoobSpider -o items.csv -t csv'.split()) 162 | -------------------------------------------------------------------------------- /spider/2-scrapy/unit2-shell.md: -------------------------------------------------------------------------------- 1 | # python shell 2 | **作者:詹亮** 3 | 4 | 5 | 1. 选择器 6 | 7 | | | CSS | Xpath | 备注 | 8 | | --- | --- | --- | --- | 9 | | 含有属性 | response.css('div[class]') | response.xpath('//div[@class]') | css可以简写为 div.class 甚至 .class,div#abc 或 #abc 则对应于id=abc | 10 | | 匹配属性值 | response.css('div[class="quote"]') | response.xpath('//div[@class="quote"]') |
response.xpath('//small[text()="Albert Einstein"]')
11 | | 12 | | 匹配部分属性值 | response.css('div[class*="quo"]') | response.xpath('//div[contains(@class,"quo")]') | response.xpath('//small[contains(text(),"Einstein")]') | 13 | | 提取属性值 | response.css('small::attr(class)') | response.xpath('//small/@class') | css里面text排除在attr以外,所以不支持上面两个过滤text??? | 14 | | 提取文字 | response.css('small::text') | response.xpath('//small/text()') | | 15 | 16 | 2. scrapy shell 17 | 18 | Scrapy终端是一个交互终端,供您在未启动spider的情况下尝试及调试您的爬取代码。 其本意是用来测试提取数据的代码,不过您可以将其作为正常的Python终端,在上面测试任何的Python代码。 19 | 20 | 该终端是用来测试XPath或CSS表达式,查看他们的工作方式及从爬取的网页中提取的数据。 在编写您的spider时,该终端提供了交互性测试您的表达式代码的功能,免去了每次修改后运行spider的麻烦。 21 | 22 | 一旦熟悉了Scrapy终端后,您会发现其在开发和调试蜘蛛时发挥的巨大作用。 23 | 24 | 如果您安装了IPython中,Scrapy终端将使用IPython的(替代标准的Python终端)。 IPython的终端与其他相比更为强大,提供智能的自动补全,高亮输出,及其他特性。 25 | 26 | 我们强烈推荐您安装IPython,特别是如果您使用Unix系统(IPython在Unix下工作的很好)。详情请参考IPython安装指南。 27 | 28 | ``` 29 | pip install ipython 30 | ``` 31 | 32 | 启动终端 33 | 34 | ``` 35 | scrapy shell < url > 36 | 37 | ``` 38 | 39 | **使用终端** 40 | 41 | Scrapy终端仅仅是一个普通的Python终端(或IPython)。其提供了一些额外的快捷方式。 42 | 43 | 可用的快捷命令(快捷方式) 44 | 45 | * shelp() - 打印可用对象及快捷命令的帮助列表 46 | * fetch(request_or_url) - 根据给定的请求(请求)或URL获取一个新的回复,并更新相关的对象 47 | * view(response)- 在本机的浏览器打开给定的响应。其会在响应的身体中添加一个标记,使得外部链接(例如图片和css)能正确显示。注意,该操作会在本地创建一个临时文件,且该文件不会被自动删除。 48 | 49 | **可用的Scrapy对象** 50 | Scrapy终端根据下载的页面会自动创建一些方便使用的对象,例如 Response对象及 Selector对象(对HTML及XML内容)。 51 | 52 | 这些对象有: 53 | 54 | * crawler- 当前Crawler对象。 55 | * spider- 处理URL的蜘蛛。对当前URL没有处理的Spider时则为一个Spider对象。 56 | * request- 最近获取到的页面的Request对象。您可以使用replace()修改该请求。或者使用fetch快捷方式来获取新的请求。 57 | * response- 包含最近获取到的页面的Response对象。 58 | * sel- 根据最近获取到的响应构造的Selector对象(ipython已经废弃)。 59 | * settings- 当前的Scrapy设置 60 | 61 | Scrapy Selectors 内置 XPath 和 CSS Selector 表达式机制 62 | 63 | 64 | Selector有四个基本的方法,最常用的还是xpath: 65 | 66 | * xpath(): 传入xpath表达式,返回该表达式所对应的所有节点的selector list列表 67 | * extract(): 序列化该节点为Unicode字符串并返回list 68 | * css(): 传入CSS表达式,返回该表达式所对应的所有节点的selector list列表,语法同 BeautifulSoup4 69 | * re(): 根据传入的正则表达式对数据进行提取,返回Unicode字符串list列表 70 | * getall():返回Unicode字符串list列表 71 | 72 | 操作对象(选择器方法( .xpath() or .css() )返回相同类型的选择器列表): 73 | 74 | ``` 75 | #xpath 76 | #div的所有超链接直接子元素 77 | response.xpath('//div/a').extract()[0] 78 | 79 | #div的所有超链接子元素 80 | response.xpath('//div//a').extract()[0] 81 | #获取超链接的内容文本 82 | response.xpath('//div/a/text()').extract()[0] 83 | 84 | #获取超链接href的值 85 | response.xpath('//div/a/@href').extract()[0] 86 | response.xpath('//div/a/@href').extract_first() 87 | 88 | #查找href属性中包含image 89 | response.xpath('//a[contains(@href, "image")]/@href').extract() 90 | 91 | #获取同时具有title和data-id属性的超链接元素 92 | response.xpath('//ul/li/a[@title][@data-id]').extract() 93 | 94 | 95 | response.xpath('//ul/li/a[@href="javascript:;"]/text()').extract()[0] 96 | 97 | 98 | #css 99 | #获取超链接的内容文本 100 | response.css('ul li a[href]::text').extract() 101 | 102 | #获取超链接href的值 103 | response.css('ul li a::attr(href)').extract() 104 | 105 | response.css('a[href*=image]::attr(href)').extract() 106 | response.css('ul li a[href^="java"]::attr(href)').extract() 107 | 108 | #超链接包含 href,title,data-id属性的 109 | response.css('ul li a[href][title][data-id]::attr(href)').extract() 110 | 111 | 112 | 113 | ``` 114 | 115 | **在实际操作中我们要结合正则表达式使用选择器(selectors)** 116 | 117 | response.xpath('//a[contains(@href, "image")]/text()').re(r'Name:\s*(.*)') 118 | 119 | --- 120 | 121 | ``` 122 | #重新抓取另一个页面 123 | fetch('http://127.0.0.1:63343/Test/test2.html?_ijt=o3iv4mthvqaq609l51a5c1p6b') 124 | 125 | #查看url 126 | response.url 127 | 128 | #改变请求方式 129 | request = request.replace(method="POST") 130 | #重新抓取 131 | fetch(request) 132 | 133 | #退出终端 134 | 135 | exit 136 | 137 | ``` 138 | 139 | 140 | 141 | ##思考 142 | 143 | for p in divs.xpath('.//p'): # extracts all

inside 144 | print p.extract() 145 | 146 | for p in divs.xpath('p'): 147 | print p.extract() -------------------------------------------------------------------------------- /spider/2-scrapy/unit3-item.md: -------------------------------------------------------------------------------- 1 | # python items & spider 2 | **作者:詹亮** 3 | 4 | 5 | 6 | 3. Items 7 | 8 | 1. item值操作 9 | 10 | #获取item属性值 11 | item['title'] 12 | item.get('title') 13 | 14 | item.keys() 15 | item.items() 16 | 17 | 18 | 2. spider 19 | 20 | 对spider来说,爬取的循环类似下文: 21 | 22 | 1. 以初始的URL初始化Request,并设置回调函数。 当该request下载完毕并返回时,将生成response,并作为参数传给该回调函数。 23 | 24 | >spider中初始的request是通过调用 start_requests() 来获取的。 25 | start_requests() 读取 start_urls 中的URL, 并以 parse 为回调函数生成 Request 。 26 | 27 | 3. 在回调函数内分析返回的(网页)内容,返回 Item 对象或者 Request 或者一个包括二者的可迭代容器。 返回的Request对象之后会经过Scrapy处理,下载相应的内容,并调用设置的callback函数(函数可相同)。 28 | 4. 在回调函数内,您可以使用 选择器(Selectors) (您也可以使用BeautifulSoup, lxml 或者您想用的任何解析器) 来分析网页内容,并根据分析的数据生成item。 29 | 5. 最后,由spider返回的item将被存到数据库(由某些 Item Pipeline 处理)或使用 Feed exports 存入到文件中。 30 | 31 | 虽然该循环对任何类型的spider都(多少)适用,但Scrapy仍然为了不同的需求提供了多种默认spider。 32 | 33 | 2. allowed_domains 34 | 35 | 36 | 可选。包含了spider允许爬取的域名(domain)列表(list)。 当 OffsiteMiddleware 启用时, 域名不在列表中的URL不会被跟进。 37 | 38 | 3. start_urls 39 | 40 | URL列表。当没有制定特定的URL时,spider将从该列表中开始进行爬取。 因此,第一个被获取到的页面的URL将是该列表之一。 后续的URL将会从获取到的数据中提取。 41 | 42 | 这个列表中的url会被依次取出并爬取。 43 | 3. start_requests() 44 | 45 | 如果您想要修改最初爬取某个网站的Request对象,您可以重写(override)该方法。 46 | 47 | start_url = [''] 48 | def start_requests(self): 49 | for i in range(100): # 爬31页数据差不多了 50 | url = self.start_url[0] + '&s=' + str(i * 44) 51 | yield scrapy.FormRequest(url=url, callback=self.parse) 52 | 53 | **回顾url** 54 | 55 | from urllib import parse 56 | import string 57 | 58 | #生成url 59 | 60 | qs={ 61 | "page_start":20*4 62 | } 63 | 64 | url=url+parse.urlencode(qs) 65 | 66 | #解决url中文的问题 67 | url='https://s.taobao.com/search?q=手机&imgfile=&commend=all&ssid=s5-e&search_type=item&sourceId=tb.index&spm=a21bo.2017.201856-taobao-item.1&ie=utf8&initiative_id=' \ 68 | 'tbindexz_20170306&p4ppushleft=5%2C48&' 69 | 70 | url=parse.quote(url,safe=string.printable) 71 | 72 | 73 | print(url) 74 | 75 | 76 | [动态爬虫](https://blog.csdn.net/sdulsj/article/details/52984824) 77 | 78 | 79 | -------------------------------------------------------------------------------- /spider/3-NOSQL/mongoDB 用户.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg936\cocoartf1561\cocoasubrtf200 2 | {\fonttbl\f0\fnil\fcharset134 PingFangSC-Regular;\f1\fswiss\fcharset0 Helvetica;} 3 | {\colortbl;\red255\green255\blue255;} 4 | {\*\expandedcolortbl;;} 5 | \paperw11900\paperh16840\margl1440\margr1440\vieww10800\viewh8400\viewkind0 6 | \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0 7 | 8 | \f0\fs24 \cf0 \'b9\'dc\'c0\'ed\'d4\'b1 9 | \f1 \ 10 | \ 11 | 12 | \f0 \'ca\'fd\'be\'dd\'bf\'e2 13 | \f1 14 | \f0 \'d3\'c3\'bb\'a7\'c3\'fb 15 | \f1 16 | \f0 \'c3\'dc\'c2\'eb 17 | \f1 \ 18 | admin useradmin adminpassword\ 19 | \ 20 | liepin lili 123456\ 21 | } -------------------------------------------------------------------------------- /spider/3-NOSQL/unit3-mongoDB-python.md: -------------------------------------------------------------------------------- 1 | ###pymongo 2 | 3 | 1. 安装连接驱动 4 | 5 | pip install pymongo 6 | 7 | 2. 连接 8 | 9 | 连接方式: 10 | 11 | 1)默认client = MongoClient() 12 | 13 | 2) 通过host+port的方式:client = MongoClient(host,port) 14 | 15 | 3) 通过uri的方式:client = MongoClient(uri) 16 | 17 | 示例: 18 | 19 | from pymongo import MongoClient 20 | #conn = MongoClient('127.0.0.1', 27017) 21 | 22 | uri = 'mongodb://lili:123456@127.0.0.1:27017/liepin' 23 | conn = MongoClient(uri) 24 | db = conn.liepin #连接liepin数据库,没有则自动创建 25 | col_user = db.user 26 | for u in col_user.find(): 27 | print(u['name']) 28 | 3. 数据库连接uri 29 | 30 | mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]] 31 | 32 | 1. mongodb:// 这是固定的格式,必须要指定。 33 | 34 | 1. username:password@ 可选项,如果设置,在连接数据库服务器之后,驱动都会尝试登陆这个数据库 35 | 36 | 1. host1 必须的指定至少一个host, host1 是这个URI唯一要填写的。它指定了要连接服务器的地址。如果要连接复制集,请指定多个主机地址。 37 | 38 | 1. portX 可选的指定端口,如果不填,默认为27017 39 | 40 | 1. /database 如果指定username:password@,连接并验证登陆指定数据库。若不指定,默认打开 test 数据库。 41 | 42 | 1. ?options 是连接选项。如果不使用/database,则前面需要加上/。所有连接选项都是键值对name=value,键值对之间通过&或;(分号)隔开 43 | 44 | 4. 添加数据 45 | 46 | 插入数据(insert插入一个列表多条数据不用遍历,效率高, save需要遍历列表,一个个插入,save通常用来更新数据....) 47 | 48 | my_set.insert({"name":"zhangsan","age":18}) 49 | #或 50 | my_set.save({"name":"zhangsan","age":18}) 51 | 52 | 案例: 53 | 54 | from pymongo import MongoClient 55 | import json 56 | uri = 'mongodb://lzhan:123456@127.0.0.1:27017/jumei' 57 | try: 58 | conn = MongoClient(uri) 59 | db = conn.jumei # 连接jumei数据库,没有则自动创建 60 | col_user = db.user 61 | with open('data/users.json') as fp: 62 | users=json.load(fp) 63 | # 添加用户 64 | col_user.insert(users) 65 | conn.close() 66 | except Exception as ex: 67 | print(ex) 68 | 5. 修改数据 69 | 70 | my_set.update( 71 | , #查询条件 72 | , #update的对象和一些更新的操作符 73 | { 74 | upsert: , #如果不存在update的记录,是否插入 75 | multi: , #可选,mongodb 默认是false,只更新找到的第一条记录 76 | writeConcern: #可选,抛出异常的级别。 77 | } 78 | ) 79 | 80 | 案例 81 | 82 | result=col_user.update({"name":"python"},{"$set":{"age":40}}) 83 | 84 | 6. 删除数据 85 | 86 | my_set.remove( 87 | , #(可选)删除的文档的条件 88 | { 89 | justOne: , #(可选)如果设为 true 或 1,则只删除一个文档 90 | writeConcern: #(可选)抛出异常的级别 91 | } 92 | ) 93 | 94 | 7. 查询数据 95 | 96 | my_set.find() 97 | 98 | 8. 模块化案例 99 | 100 | #-*-coding:utf-8-*- 101 | import logging 102 | import setting 103 | import time,datetime 104 | from setting import mongo_host,mongo_port,mongo_db_name_data,mongo_db_name_linkbase,mongo_db_name_task 105 | import pymongo 106 | 107 | logging.basicConfig(filename='log',level=logging.INFO) 108 | 109 | 110 | class Connect_mongo(object): 111 | def __init__(self): 112 | self.mongo_host = mongo_host 113 | self.mongo_port = mongo_port 114 | self.conn() 115 | 116 | def conn(self): 117 | self.client = pymongo.MongoClient(host=self.mongo_host,port=self.mongo_port) 118 | self.db_data = self.client[mongo_db_name_data] 119 | self.db_linkbase = self.client[mongo_db_name_linkbase] 120 | self.db_linkbase_collection = self.db_linkbase.linkbase 121 | self.db_task = self.client[mongo_db_name_task] 122 | 123 | def insert_db(self,item): 124 | setting.my_logger.info('当前插入数据库的最终数据为%s'%item) 125 | self.db_data.xxx_data.update({"car_id":item['car_id']},item,True) 126 | self.client.close() 127 | 128 | def save_linkbase(self,response_result,spider_name,hash_url,item_type): 129 | if item_type == 'carinfo_item': 130 | linkinfo = {} 131 | linkinfo['status'] = response_result.status_code 132 | linkinfo['url'] = response_result.url 133 | linkinfo['spider_name'] = spider_name 134 | linkinfo['hash_url'] = hash_url 135 | #保存到linkbase 136 | self.db_linkbase_collection.update({"status":linkinfo['status'],"hash_url":hash_url},linkinfo,True) 137 | self.client.close() 138 | else: 139 | self.db_linkbase_collection.create_index([("over_time", pymongo.ASCENDING)], expireAfterSeconds=7200) 140 | linkinfo = {} 141 | linkinfo['status'] = response_result.status_code 142 | linkinfo['url'] = response_result.url 143 | linkinfo['spider_name'] = spider_name 144 | linkinfo['hash_url'] = hash_url 145 | linkinfo['over_time'] = datetime.datetime.utcnow() 146 | #保存到linkbase 147 | self.db_linkbase_collection.update({"status":linkinfo['status'],"hash_url":hash_url},linkinfo,True) 148 | self.client.close() 149 | 150 | def save_task(self,task): 151 | setting.my_logger.info('当前插入数据库的task信息为%s'%task) 152 | self.db_task.xxx_task.update({'url':task['url']},task,True) 153 | self.client.close() 154 | 155 | def get_task(self,max_requests=10): 156 | task = [] 157 | for i in range(max_requests): 158 | result = self.db_task.xxx_task.find_one_and_delete({}) 159 | task.append(result) 160 | return task 161 | 162 | def duplicate_removal(self,hash_data): 163 | result = self.db_linkbase.linkbase.find_one({'hash_url':hash_data}) 164 | if result == None: 165 | return True 166 | else: 167 | return False 168 | 169 | 170 | mongo_insert = Connect_mongo() -------------------------------------------------------------------------------- /spider/3-NOSQL/unit4-云服务器.md: -------------------------------------------------------------------------------- 1 | # mongoDB云服务器 2 | 3 | ##mongoDB 4 | 1. 下载安装文件 5 | 6 | curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.2.tgz # 下载 7 | tar -zxvf mongodb-linux-x86_64-3.0.6.tgz # 解压 8 | mv mongodb-linux-x86_64-3.0.6/ /usr/local/mongodb # 将解压包拷贝到指定目录 9 | 2. MongoDB 的可执行文件位于 bin 目录下,所以可以将其添加到 PATH 路径中: 10 | 11 | export PATH=/bin:$PATH 12 | source /etc/profile 13 | 查看配置信息 14 | 15 | echo $PATH 16 | 3. 创建工作目录 17 | 18 | mkdir -p /data/db 19 | mkdir -p /data/log 20 | 21 | 这个时候就可以本机测试了,开通服务 mongod --dbpath /data/db;打开客户端 mongo 22 | 23 | 4. 添加配置文件 24 | 25 | 这里为了方便,我们把配置文件mongodb.conf 放到了bin目录下(/etc/local/mongodb/bin) 26 | 27 | 文件信息 28 | 29 | dbpath=/data/db 30 | logpath=/data/log/mongodb.log 31 | logappend=true 32 | port=27017 33 | fork=true 34 | bind_ip=0.0.0.0 35 | ##auth = true # 先关闭, 创建好用户在启动 36 | 37 | **为了可以远程访问,bind_ip=0.0.0.0一定要加入 38 | 39 | 5. 通过配置文件启动 40 | 41 | mongod -f /usr/local/mongodb/bin/mongodb.conf 42 | 43 | 出现以下信息即表示启动成功 44 | 45 | about to fork child process, waiting until server is ready for connections. 46 | forked process: 2400 47 | child process started successfully, parent exiting 48 | 6. 配置防火墙(此步骤可以跳过*********) 49 | 50 | 查看现有的防火漆配置信息 51 | 52 | more /etc/sysconfig/iptables 53 | 54 | 将27017端口添加到防火墙中 55 | 56 | vi /etc/sysconfig/iptables 57 | -A INPUT -m state --state NEW -m tcp -p tcp --dport 27017 -j ACCEPT 58 | /etc/init.d/iptables reload 59 | 60 | 注:如若不想修改iptables表,可以直接输入下面命令: 61 | 62 | # iptables -I INPUT -p tcp --dport 8889 -j ACCEPT 63 | 64 | 若/etc/sysconfig/iptables不存在, 65 | 66 | 原因:在新安装的linux系统中,防火墙默认是被禁掉的,一般也没有配置过任何防火墙的策略,所有不存在/etc/sysconfig/iptables文件。 67 | 68 | 解决: 69 | 70 | 在控制台使用iptables命令随便写一条防火墙规则,如:iptables -P OUTPUT ACCEPT 71 | 72 | 使用service iptables save进行保存,默认就保存到了/etc/sysconfig目录下的iptables文件中 73 | 74 | [参考文档](https://www.cnblogs.com/blog-yuesheng521/p/7198829.html) 75 | 76 | 5. 配置mongodb开机启动,设置mongodb.service启动服务 77 | 78 | 79 | 80 | 1. 新建配置文件 81 | 82 | cd /lib/systemd/system 83 | vi mongodb.service 84 | 85 | 2. 配置信息 86 | 87 | [Unit] 88 | Description=mongodb 89 | After=network.target remote-fs.target nss-lookup.target 90 | 91 | [Service] 92 | Type=forking 93 | ExecStart=/usr/local/mongodb/bin/mongod --config /usr/local/mongodb/bin/mongodb.conf 94 | ExecReload=/bin/kill -s HUP $MAINPID 95 | ExecStop=/usr/local/mongodb/bin/mongod --shutdown --config /usr/local/mongodb/bin/mongodb.conf 96 | PrivateTmp=true 97 | 98 | [Install] 99 | WantedBy=multi-user.target 100 | 101 | 3. 设置mongodb.service权限 102 | 103 | chmod 754 mongodb.service 104 | 105 | 4. 系统mongodb.service操作命令 106 | 107 | #启动服务 108 | systemctl start mongodb.service 109 | #关闭服务 110 | systemctl stop mongodb.service 111 | #开机启动 112 | systemctl enable mongodb.service 113 | 114 | 6. shell 管理进程 115 | 116 | 查看mongodb的进程的方式: 117 | 118 | ps -ef | grep mongodb 119 | 120 | 杀死mongodb进程的方式: 121 | 122 | pkill mongod 123 | 124 | 125 | ##mysql 126 | 127 | 1. 安装前看是否安装过mysql 128 | 129 | yum list installed mysql* 130 | 131 | 2. 删除mysql 132 | 133 | yum remove mysql* 134 | 135 | 3. 查看yum库下是否有mysql-server 136 | 137 | yum list mysql* 138 | #或者 139 | yum list | grep mysql 或 yum -y list mysql* 140 | 141 | 如果没有(一般在centos7下没有) 142 | 143 | wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm 144 | 145 | rpm -ivh mysql-community-release-el7-5.noarch.rpm 146 | 147 | 4. ####安装mysql 148 | 149 | yum install mysql-server 150 | yum install mysql-devel 151 | 152 | 5. mysql配置文件 153 | 154 | /etc/my.cnf的[mysqld]中加入character-set-server=utf8 155 | 156 | 6. 启动mysql服务: 157 | 158 | service mysqld start 159 | 或者/etc/init.d/mysqld start 160 | 161 | service mysqld start 162 | service mysqld stop 163 | service mysqld restart 164 | service mysqld status 165 | 166 | **设置开机启动:** 167 | 168 | 7. 创建root管理员: 169 | 170 | 假如: 171 | mysqladmin -u root password 666666 172 | 登录: 173 | mysql -u root -p 174 | 如果忘记密码,则执行以下代码 175 | service mysqld stop 176 | mysqld_safe --user=root --skip-grant-tables 177 | 加入密码**** 178 | mysql -u root 179 | use mysql 180 | update user set password=password("666666") where user="root"; 181 | flush privileges; 182 | 183 | 8. 开放防火墙的端口号 184 | 185 | mysql增加权限:mysql库中的user表新增一条记录host为“%”,user为“root”。 186 | use mysql; 187 | UPDATE user SET `Host` = '%' WHERE `User` = 'root' LIMIT 1; 188 | %表示允许所有的ip访问 189 | 190 | --------------------------------------------------------------------------------