目前市面上有非常多的模板系统，其中最知名最好用的就是DTL和Jinja2。 DTL 是 Django Template Language 三个单词的缩写，也就是Django自带的模板语言。当然也可以配置Django支持Jinja2等其他模板引擎，但是作为Django内置的模板语言，和Django可以达到无缝衔接而不会产生一些不兼容的情况。DTL与普通的HTML文件的区别DTL模板是一种带有特殊语法的HTML文件，这个HTML文件可以被Django编译，可以传递参数进去，实现数据动态化。在编译完成后，生成一个普通的HTML文件，然后发送给客户端。渲染模板渲染模板有多种方式。列举两种常用的方式。render_to_string ：找到模板，然后将模板编译后渲染成Python的字符串格式。最后再通过HttpResponse 类包装成一个 HttpResponse 对象返回回去。示例代码如下：from django.template.loader import render_to_string from django.http import HttpResponse def book_detail(request,book_id): html = render_to_string("detail.html") return HttpResponse(html)django还提供了一个更加简便的方式，直接将模板渲染成字符串和包装成 HttpResponse 对象一步到位完成。示例代码如下：from django.shortcuts import render def book_list(request): return render(request,'list.html')模板查找路径配置：在项目的 settings.py 文件中。有一个 TEMPLATES 配置，这个配置包含了模板引擎的配置，模板查找路径的配置，模板上下文的配置等。模板路径可以在两个地方配置。DIRS ：这是一个列表，在这个列表中可以存放所有的模板路径，以后在视图中使用 render 或者render_to_string 渲染模板的时候，会在这个列表的路径中查找模板。APP_DIRS ：默认为 True ，这个设置为 True 后，会在 INSTALLED_APPS 的安装了的 APP 下的templates 文件夹中查找模板。TEMPLATES = [ { .... # 定义存放模板的目录，这里使用 templates 目录 "DIRS": [BASE_DIR / "templates"], "APP_DIRS": True, "OPTIONS": { ... }, ] 查找顺序：比如代码 render('list.html') 。先会在 DIRS 这个列表中依次查找路径下有没有这个模板，如果有，就返回。如果 DIRS 列表中所有的路径都没有找到，那么会先检查当前这个视图所处的 app 是否已经安装，如果已经安装了，那么就先在当前这个 app 下的 templates 文件夹中查找模板，如果没有找到，那么会在其他已经安装了的 app 中查找。如果所有路径下都没有找到，那么会抛出一个 TemplateDoesNotExist 的异常。DTL模板语法变量：模板中可以包含变量， Django 在渲染模板的时候，可以传递变量对应的值过去进行替换。变量的命名规范和 Python 非常类似，只能是阿拉伯数字和英文字符以及下划线的组合，不能出现标点符号等特殊字符。变量需要通过视图函数渲染，视图函数在使用 render 或者 render_to_string 的时候可以传递一个context 的参数，这个参数是一个字典类型。以后在模板中的变量就从这个字典中读取值的。示例代码如下：# views.py代码 def profile(request): return render(request,'profile.html',context={'username':'陌上花'}) # profile.html模板代码 {{ username }} 除了变量，还可以是字典，列表以及对象。模板中的变量同样也支持 点(.) 的形式。# views.py代码 def info(request): # 1. 普通的变量 username = "悦来小陌" # 2. 字典类型 book = {"firm": "悦来集团", "name": "henry"} # 3. 列表 books = [ {"name": "全职高手", "author": "蝴蝶蓝"}, {"name": "斗破苍穹", "author": "天蚕土豆"}, ] # 4. 对象 class Person: def __init__(self, realname): self.realname = realname context = { "username": username, "book": book, "books": books, "Person": Person("陌上花"), } return render(request, "info.html", context=context) # infp.html模板代码 {{username}} 公司名称:{{book.firm}}, CEO: {{book.name}} 下标为 0 的小说作者是: {{books.0.author}} 下标为 1 的小说是: {{books.1.name}} 姓名为: {{Person.realname}} 在出现了点的情况，比如book.firm ，模板是按照以下方式进行解析的： 如果 book 是一个字典，那么就会查找这个字典的 firm 这个 key 对应的值。 如果 person 是一个对象，那么就会查找这个对象的 realname 属性，或者是 realname 这个方法。 如果出现的是 books.1 ，会判断 books 是否是一个列表或者元组或者任意的可以通过下标访问的对象，如果是的话就取这个列表的第1个值。如果不是就获取到的是一个空的字符串。 有以下几点需要注意： 不能通过中括号的形式访问字典和列表中的值，比如dict['key']和list[1]是不支持的！DTL模板语法里改为点（.）来访问，对应的应该是dict.key 和list.1 因为使用点（.）语法获取对象值的时候，可以获取这个对象的属性，如果这个对象是一个字典，也可以获取这个字典的值。所以在给这个字典添加key的时候，千万不能和字典中的一些属性重复。比如items，因为items是字典的方法，那么如果给这个字典添加一个items作为key，那么以后就不能再通过item来访问这个字典的键值对了。 常用的模板标签if 标签if 标签相当于 Python 中的 if 语句，有 elif 和 else 相对应，但是所有的标签都需要用标签符号（ {%%} ）进行包裹。if 标签中可以使用 ==、!=、<、<=、>、>=、in、not in、is、is not 等判断运算符。还有注意的是，使用if时有起始标签{% if %}，就要有结束标签{% endif %}{% if num > 18 %} 数字大于 18 {% elif num == 18 %} 数字等于 18 {% else %} 数字小于 18 {% endif %}for...in... 标签for...in... 类似于 Python 中的 for...in... 。可以遍历列表、元组、字符串、字典等一切可以遍历的对象。{% for person in persons %} {{ person.name }} {% endfor %}如果想要反向遍历，那么在遍历的时候就加上一个 reversed 。{% for person in persons reversed %} {{ person.name }} {% endfor %}遍历字典的时候，需要使用 items 、 keys 和 values 等方法。在 DTL 中，执行一个方法不能使用圆括号的形式。遍历字典示例代码如下： {% for key,value in person.items %} key：{{ key }} value：{{ value }} {% endfor %}在 for 循环中， DTL 提供了一些变量可供使用。这些变量如下：forloop.counter ：当前循环的下标。以1作为起始值。forloop.counter0 ：当前循环的下标。以0作为起始值。forloop.revcounter ：当前循环的反向下标值。比如列表有5个元素，那么第一次遍历这个属性是等于5，第二次是4，以此类推。并且是以1作为最后一个元素的下标。forloop.revcounter0 ：类似于 forloop.revcounter 。不同的是最后一个元素的下标是从0开始。forloop.first ：是否是第一次遍历。forloop.last ：是否是最后一次遍历。forloop.parentloop ：如果有多个循环嵌套，那么这个属性代表的是上一级的for循环。for...in...empty 标签这个标签使用跟 for...in... 是一样的，只不过是在遍历的对象如果没有元素的情况下，会执行 empty 中的内容。{% for person in persons %} {{ person }} {% empty %} 暂时还没有任何人 {% endfor %}with 标签在模版中定义变量。有时候一个变量访问的时候比较复杂，那么可以先把这个复杂的变量缓存到一个变量上，以后就可以直接使用这个变量就可以了。context = { "persons": ["xiaomo","henry"] } {% with lisi=persons.1 %} {{ lisi }} {% endwith %}有几点需要强烈的注意：在 with 语句中定义的变量，只能在 {%with%}{%endwith%} 中使用，不能在这个标签外面使用。定义变量的时候，不能在等号左右两边留有空格。比如 {% with lisi = persons.1%} 是错误的。还有另外一种写法同样也是支持的： {% with persons.1 as lisi %} {{ lisi }} {% endwith %}url 标签在模版中，经常要写一些 url ，比如某个a标签中需要定义 href 属性。当然如果通过硬编码的方式直接将这个 url 写死在里面也是可以的。但是这样对于以后项目维护可能不是一件好事。因此建议使用这种反转的方式来实现，类似于 django 中的 reverse 一样。图书列表页面如果 url 反转的时候需要传递参数，那么可以在后面传递。但是参数分位置参数和关键字参数。位置参数和关键字参数不能同时使用。# path部分 path('detail/<book_id>/',views.book_detail,name='detail') # url反转，使用位置参数 图书详情页面 # url反转，使用关键字参数 图书详情页面spaceless 标签移除html标签中的空白字符。包括空格、tab键、换行等。 {% spaceless %} Foo {% endspaceless %}那么在渲染完成后，会变成以下的代码： Foo aceless 只会移除html标签之间的空白字符。而不会移除标签与文本之间的空白字符。autoescape 标签开启和关闭这个标签内元素的自动转义功能。自动转义是可以将一些特殊的字符。比如<转义成 html 语法能识别的字符，会被转义成<，而>会被自动转义成 >。模板中默认是已经开启了自动转义的。# 传递的上下文信息 context = { "info":"百度" } # 模板中关闭自动转义 {% autoescape off %} {{ info }} {% endautoescape %}那么就会显示百度的一个超链接。如果把 off 改成 on ，那么就会显示成一个普通的字符串。{% autoescape on %} {{ info }} {% endautoescape %}更多标签可以查看官方文档：https://docs.djangoproject.com/zh-hans/5.0/ref/templates/builtins/模板常用过滤器在模版中，有时候需要对一些数据进行处理以后才能使用，一般在 Python 中是通过函数的形式来完成的。而在模版中，则是通过过滤器来实现的，过滤器使用的是|来使用。比如使用 add 过滤器，那么示例代码如下：开发中常用的过滤器cut移除值中所有指定的字符串。类似于 python 中的 replace(args,"") ，语法：示例 # 数据 greet = "Hello World, Hello Python, Hello Django" # 模板 {{greet}} > Hello World, Hello Python, Hello Django # 移除空格 > HelloWorld,HelloPython,HelloDjango # 移除逗号 >Hello World Hello Python Hello Django date将一个日期按照指定的格式，格式化成字符串。示例代码如下：# 数据 context = { "birthday": datetime.now() } # 模版 那么将会输出 2024/07/27 。其中Y代表的是四位数字的年份，m代表的是两位数字的月份，d代表的是两位数字的日。 还有更多时间格式化的方式。见下表。Y：四位数字的年份 （2024）m ：两位数字的月份（01-12） n ：月份，1-9前面没有0前缀（1-12） d ：两位数字的天（01-31） j ：天，但是1-9前面没有0前缀（1-31） g ：小时，12小时格式的，1-9前面没有0前缀（1-12） h ：小时，12小时格式的，1-9前面有0前缀（01-12） G ：小时，24小时格式的，1-9前面没有0前缀（1-23） H ：小时，24小时格式的，1-9前面有0前缀（01-23） i ：分钟，1-9前面有0前缀（00-59） s ：秒，1-9前面有0前缀（00-59）default如果值被评估为 False 。比如 [] ， "" ， None ， {} 等这些在 if 判断中为 False 的值，都会使用default 过滤器提供的默认值。语法 如果 value 是等于一个空的字符串。比如 ""# 数据 context = { "profile": "", } # 空字符就不会显示 {{profile_none}} # 由于是空字符，就会显示 default里定义的文字 这个家伙很懒,什么都没留下. default_if_none如果值是 None ，那么将会使用 default_if_none 提供的默认值。这个和 default 有区别， default 是所有被评估为 False 的都会使用默认值。而 default_if_none 则只有这个值是等于 None 的时候才会使用默认值。如果 value 是等于 "" 也即空字符串，那么以上会输出空字符串。如果 value 是一个 None 值，才会输出 nothing 。first返回列表/元组/字符串中的第一个元素。如果 value 是等于 ['a','b','c'] ，那么输出将会是alast返回列表/元组/字符串中的最后一个元素。如果 value 是等于 ['a','b','c'] ，那么输出将会是cfloatformat使用四舍五入的方式格式化一个浮点类型。如果这个过滤器没有传递任何参数，那么只会在小数点后保留一个小数。如果小数后面全是0，那么只会保留整数。也可以传递一个参数，标识具体要保留几个小数。# 数据 context = { "num": [34.45678, 18.000, 5.17], } 不传参数: >不传参数:34.5 传参数保留3位: >传参数保留3位:34.457 join类似与 Python 中的 join ，将列表/元组/字符串用指定的字符进行拼接。如果 value 是等于 ['a','b','c'] ，那么以上代码将输出 a/b/c 。length获取一个列表/元组/字符串/字典的长度。如果 value 是等于 ['a','b','c'] ，那么以上代码将输出3 如果 value 为 None ，那么以上将返回0random在被给的列表/字符串/元组中随机的选择一个值。如果 value 是等于 ['a','b','c'] ，那么以上代码会在列表中随机选择一个safe标记一个字符串是安全的。也即会关掉这个字符串的自动转义。如果 value 是一个不包含任何特殊字符的字符串，比如 这种，那么以上代码就会把字符串正常的输入。如果 value 是一串 html 代码，那么以上代码将会把这个 html 代码渲染到浏览器中。# 数据 context = { "html": " 欢迎来到悦来集团! ", } # 只会原封不动的带标签渲染显示出来 {{html}} > 欢迎来到悦来集团! # 会解析标签的作用，然后渲染显示 >欢迎来到悦来集团!slice类似于 Python 中的切片操作 将会给 some_list 从2开始做切片操作stringtags删除字符串中所有的 html 标签 如果 value 是 hello world ，那么以上代码将会输出 hello world 。truncatechars如果给定的字符串长度超过了过滤器指定的长度。那么就会进行切割，并且会拼接三个点来作为省略号。如果 value 是等于 abcdef ，那么输出的结果是 abcd… ，只有四个字母是因为三个点也占了一个字符模版结构include模版有时候一些代码是在许多模版中都用到的。如果每次都重复的去拷贝代码那肯定不符合项目的规范。一般可以把这些重复性的代码抽取出来，就类似于Python中的函数一样，以后想要使用这些代码的时候，就通过 include 包含进来。这个标签就是 include 。# header.html 我是header # footer.html 我是footer # main.html {% include 'header.html' %} 我是main内容 {% include 'footer.html' %}include 标签寻找路径的方式。也是跟 render 渲染模板的函数是一样的。默认 include 标签包含模版，会自动的使用主模版中的上下文，也即可以自动的使用主模版中的变量。模板继承在前端页面开发中。有些代码是需要重复使用的。这种情况可以使用 include 标签来实现，也可以使用另外一个比较强大的方式来实现，那就是模版继承。模版继承类似于 Python 中的类，在父类中可以先定义好一些变量和方法，然后在子类中实现。模版继承也可以在父模版中先定义好一些子模版需要用到的代码，然后子模版直接继承就可以了。并且因为子模版肯定有自己的不同代码，因此可以在父模版中定义一个block接口，然后子模版再去实现。以下是父模版的代码： {% block title %}{% endblock %} - 陌上花 {% block head %}{% endblock %} <hender> 首页 留言 </hender> {% block body %}{% endblock %} Copyright © Blog All Rights Reserved. 2016- 这个模版，取名叫做 base.html ，定义好一个简单的 html 骨架。然后定义好 block 接口，让子模版来根据具体需求来实现。block 接口的定义和模板标签一样，需要有起始标签{% block 自定义名称 %}，就要有结束标签 {% endblock %}hotarticle.html文件的内容 热门文章 文章 文章 文章 文章 {% for article in articles %} {{article}} {% endfor%} 子模板然后通过 extends 标签来实现，示例代码如下：{% extends "cc_base.html" %} {% block title %}首页{% endblock %} {% block head %} {% endblock %} {% block body %} {% include "hotarticle.html"%} {% endblock%}以上代码保存后解析的代码会成这样，框起来的地方就是三个 block 传入的数据具体效果需要注意的是：extends标签必须放在模版的第一行。子模板中的代码必须放在block中，否则将不会被渲染。如果在某个 block 中需要使用父模版的内容，那么可以使用 {{block.super}} 来继承。比如上例，{%block title%} ，如果想要使用父模版的 title ，那么可以在子模版的 title block 中使用 {{ block.super }} 来实现。在定义 block 的时候，除了在 block 开始的地方定义这个 block 的名字，还可以在 block 结束的时候定义名字。比如 {% block title %}{% endblock title %} 。这在大型模版中显得尤其有用，能让你快速的看到 block 包含在哪里。
Django5 入门Django相关的网址Github源代码：https://github.com/django/djangoDjango官网：https://www.djangoproject.com/安装Django通过 pip install django 安装 django ，本文以 Django 5.0.3 版本进行记录。pip install django #如需要指定版本用这个命令 pip install django==5.0.3 初始化 Django 项目创建项目使用命令： django-admin startproject [项目名称] 即可创建。初始化一个新的 Django 项目，例如：django-admin startproject startdjango 创建应用（app）：一个项目类似于是一个架子，但是真正起作用的还是 app 。在终端进入到项目所在的路径，然后执行 python manage.py startapp [app名称] 创建一个app。运行Django项目进入项目，通过命令行的方式： python manage.py runserver这样可以在本地访问项目网站，默认端口号是 8000 ，在浏览器中通过 http://127.0.0.1:8000/ 来访问cd startdjango python manage.py runserver如果想要修改端口号，那么在运行的时候可以指定端口号，python manage.py runserver 9000这样就可以通过9000端口来访问python manage.py runserver 9000项目结构介绍 manage.py：以后和项目交互基本上都是基于这个文件。一般都是在终端输入python manage.py [子命令]。可以输入python manage.py help看下能做什么事情。除非你知道你自己在做什么，一般情况下不应该编辑这个文件。 settings.py：本项目的设置项，以后所有和项目相关的配置都是放在这个里面。 urls.py：这个文件是用来配置URL路由的。比如访问http://127.0.0.1/news/是访问新闻列表页，这些东西就需要在这个文件中完成。 wsgi.py：项目与WSGI工协议兼容的web服务器入口，部署的时候需要用到的，一般情况下也是不需要修改的。 project和app的关系app是django项目的组成部分。一个app代表项目中的一个模块，所有URL请求的响应都是由app来处理。比如豆瓣，里面有图书，电影，音乐，同城等许许多多的模块，如果站在django的角度来看，图书，电影这些模块就是app，图书，电影这些app共同组成豆瓣这个项目。因此这里要有一个概念，django项目由许多 app组成，一个app可以被用到其他项目，django也能拥有不同的app。通过命令：python manage.py startapp bookURL分发器一、视图：视图一般都写在 app 的 views.py 中。并且视图的第一个参数永远都是 request （一个HttpRequest）对象。这个对象存储了请求过来的所有信息，包括携带的参数以及一些头部信息等。在视图中，一般是完成逻辑相关的操作。def book_list(request): return HttpResponse("书籍列表！")视图可以是函数，也可以是类。二、URL映射：视图写完后，要与URL进行映射，即用户在浏览器中输入什么 url 的时候可以请求到这个视图函数。在用户输入了某个 url ，请求到我们的网站的时候， django 会从项目的 urls.py 文件中寻找对应的视图。在 urls.py 文件中有一个 urlpatterns 变量，以后 django 就会从这个变量中读取所有的匹配规则。匹配规则需要使用 django.urls.path 函数进行包裹，这个函数会根据传入的参数返回URLPattern 或者是 URLResolver 的对象。示例代码如下：from django.contrib import admin from django.urls import path from book import views urlpatterns = [ path('admin/', admin.site.urls), path('book/',views.book_list) ]URL中添加参数：有时候， url 中包含了一些参数需要动态调整。比如博客某篇文章的详情页的url，是https://moshanghua.net/details/3276 后面的 3276 就是这篇文章的 id ，那么文章详情页面的url就可以写成 https://moshanghua.net/details/<id> ，其中id就是文章的id。在django 中实现这种需求。可以在 path 函数中，使用尖括号的形式来定义一个参数。比如我现在想要获取一本书籍的详细信息，那么应该在 url 中指定这个参数。示例代码如下：from django.contrib import admin from django.urls import path from book import views urlpatterns = [ path('admin/', admin.site.urls), path('book/',views.book_list), path('book/<book_id>',views.book_detail) ]而 views.py 中的代码如下：def book_detail(request, book_id): return HttpResponse(f"您查询的图书 id 是: {book_id}")在指定参数时，也可以指定参数的类型，比如以上 book_id 为整形，那么在定义 URL 的时候，就可以使用以下语法实现：... path('book/<int:book_id>',views.book_detail) ...除了 int 类型， django 的 path 部分还支持 str 、 slug 、 uuid 、 path 类型。也可以通过查询字符串的方式传递一个参数过去。示例代码如下：urlpatterns = [ path('admin/', admin.site.urls), path('book/',views.book_list), path('book/detail',views.book_detail) ]在 views.py 中的代码如下：def book_detail(request): book_id = request.GET.get("id") name = request.GET.get("name") return HttpResponse(f"您查询的图书 id 是: {book_id}，图书的名称是:《{name}》")在访问的时候就是通过 /book/detail?id=1&name=xx 即可将参数传递过去。path函数详解path 函数的定义为： path(route,view,name=None,kwargs=None) 。route 参数： url 的匹配规则。这个参数中可以指定 url 中需要传递的参数，比如在访问文章详情页的时候，可以传递一个 id 。传递参数是通过 <> 尖括号来进行指定的。并且在传递参数的时候，可以指定这个参数的数据类型，比如文章的 id 都是 int 类型，那么可以这样写 <int:id> ，以后匹配的时候，就只会匹配到 id 为 int 类型的 url，而不会匹配其他的 url ，并且在视图函数中获取这个参数的时候，就已经被转换成一个 1.int 类型了。其中还有几种常用的类型：2.str ：非空的字符串类型。默认的转换器。但是不能包含斜杠。3.int ：匹配任意的零或者正数的整形。到视图函数中就是一个int类型。4.slug ：由英文中的横杠 - 或者下划线 _ 连接英文字符或者数字而成的字符串。5.uuid ：匹配 uuid 字符串。6.path ：匹配非空的英文字符串，可以包含斜杠 /view 参数：可以为一个视图函数或者是 类视图.as_view() 或者是 django.urls.include() 函数的返回值。name 参数：这个参数是给这个 url 取个名字的，在项目比较大， url 比较多的时候用处很大。URL中包含另外一个urls模块（路由模块化）：在项目中，不可能只有一个 app ，如果把所有的 app 的 views 中的视图都放在 urls.py 中进行映射，肯定会让代码显得非常乱。因此 django 给提供了一个方法，可以在 app 内部包含自己的 url 匹配规则，而在项目的 urls.py 中再统一包含这个 app 的 urls 。使用这个技术需要借助 include 函数。示例代码如下：# startdjango/urls.py文件： from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path('book/',include("book.urls")) ]在 urls.py 文件中把所有的和 book 这个 app 相关的 url 都移动到 app/urls.py 中了，然后在startdjango/urls.py 中，通过 include 函数包含 book.urls ，以后在请求 book 相关的url的时候都需要加一个 book 的前缀。# book/urls.py文件： from django.urls import path from . import views urlpatterns = [ path('list/',views.book_list), path('detail/<book_id>/',views.book_detail) ]访问书的列表的 url 的时候，就通过 /book/list/ 来访问，访问书籍详情页面的 url 的时候就通过book/detail/<id> 来访问。为了避免多个模块的 urls.py 中包含同名的 url ，可以指定一个应用命名空间：# book/urls.py文件： from django.urls import path from . import views # 指定应用命名空间 app_name='book' urlpatterns = [ path('list/',views.book_list), path('detail/<book_id>/',views.book_detail) ]url反转（路由反转）一般是通过url来访问视图函数。有时候知道这个视图函数，但是想反转回它的url。这时候就可以通过 reverse 来实现。示例代码如下：print(reverse("list")) > /book/list/如果有应用命名空间或者有实例命名空间，那么应该在反转的时候加上命名空间。示例代码如下：print（reverse('book:list')） > /book/list/如果这个url中需要传递参数，那么可以通过 kwargs 来传递参数。示例代码如下：print(reverse("book:detail",kwargs={"book_id":1})) > /book/detail/1因为 django 中的 reverse 反转 url 的时候不区分 GET 请求和 POST 请求，因此不能在反转的时候添加查询字符串的参数。如果想要添加查询字符串的参数，只能手动的添加。示例代码如下：login_url = reverse('login') + "?next=/" print(login_url)
Excel表格的基本结构一个Excel表格文件，又叫做一个工作簿（Workbook）。一个工作簿中包含一个或多个工作表（Worksheet）。在工作薄页面的左下方可以进行工作表的切换和增删。一个工作表由单元格（Cell）组成。Excel的数据存储在单元格中。我们可以通过列号（Column）和行号（Row）对单元格进行定位。行号默认从数字1开始，并依次递增。列号默认从字母A开始，依次递增。超过字母Z后，以AA，AB的方式继续计数。至此，就是Excel表格的基本结构，总结如图所示。openpyxl 模块要使用Python对Excel表格进行读取，我们需要安装一个用于读取数据的工具 openpyxl 。openpyxl 是一个用于读、写Excel文件的开源模块。Excel表格读取读取工作簿读取指定路径的工作簿需要使用函数：openpyxl.load_workbook()openpyxl.load_workbook()函数读取成功后，会返回一个工作簿对象，本例中将这个对象赋值给了变量wb。# 导入openpyxl模块 import openpyxl #读取工作目录里名为"2019年1月销售订单.xlsx"的工作簿并赋值给变量wb wb = openpyxl.load_workbook("2019年1月销售订单.xlsx") 读取指定工作表如果事先不知道工作簿内有哪些工作表，可以通过访问工作簿的 .sheetnames 属性来获取一个包含所有工作表名称的列表。具体操作为在变量wb之后添加代码 .sheetnames 。import openpyxl wb = openpyxl.load_workbook("2019年1月销售订单.xlsx") # 使用print输出工作簿中所有的工作表名称 print(wb.sheetnames) # ['销售商品', '销售订单数据'] # 通过工作簿对象wb获取名为“销售商品”的工作表对象， orderSheet = wb["销售商品"] 读取指定单元格要获取工作表中指定的单元格对象，我们可以通过在中括号 [ ] 内填入列号和行号的方式去获取。单元格对象除了包含具体的值，还包含相关的函数和属性。要访问单元格里的值，可以在单元格对象后加一个 .valueimport openpyxl wb = openpyxl.load_workbook("sample.xlsx") print(wb.sheetnames) # ['sheet1', 'sheet2'] orderSheet = wb["销售商品"] # 使用print输出 orderSheet 的C5单元格对象 print (orderSheet["C5"]) # < Cell '销售商品'.C5 > # 使用 orderSheet["C5"].value 输出orderSheet的C5单元格的值 print(orderSheet["C5"].value) 若单元格中包含公式，现有方式读取出的值是公式本身。若需要读取公式计算后的值，要在读取工作簿的代码部分，传入一个参数： data_only=True ，便可以得出公式计算后的值了。# 导入openpyxl模块 import openpyxl # 原打开方式，直接读取公式本身 wb = openpyxl.load_workbook("2019年1月销售订单.xlsx") orderSheet = wb["销售订单数据"] # 输出公式本身 print(orderSheet["I3"].value) # 添加data_only=True打开工作簿，获取公式计算后的值 wb2 = openpyxl.load_workbook("2019年1月销售订单.xlsx", data_only=True) orderSheet2 = wb2["销售订单数据"] # 输出公式计算后的值 print(orderSheet2["I3"].value)工作表行数据的遍历要对整个工作表的每一行数据进行浏览查询，可以使用for循环对工作表对象的行属性（rows）进行遍历。具体代码为 for rowData in orderSheet.rows这样程序就会以从上到下的顺序，逐个获取到“销售订单数据”工作表内的每一行数据，读取出的每一行数据是由单元格对象组成的元组。import openpyxl wb = openpyxl.load_workbook("2019年1月销售订单.xlsx", data_only=True) orderSheet = wb["销售订单数据"] # 遍历工作表的所有行数据 for rowData in orderSheet.rows: # 输出行数据 print(rowData) # (<Cell '销售订单数据'.A1>, <Cell '销售订单数据'.B1>, <Cell '销售订单数据'.C1>, <Cell '销售订单数据'.D1>, <Cell '销售订单数据'.E1>, <Cell '销售订单数据'.F1>, <Cell '销售订单数据'.G1>, <Cell '销售订单数据'.H1>, <Cell '销售订单数据'.I1>, <Cell '销售订单数据'.J1>) # 通过索引2获取第3列数据，也就是商品名 productName = rowData[2].value # 输出商品名 print(productName)列号转数字使用函数openpyxl.utils.cell.column_index_from_string()来获取工作表列号对应的数字。遍历行数据时，如果要定位的列数字比较大，比如订单的总价在第 Z 列，列号太大不太容易数的时候就可以使用函数：openpyxl.utils.cell.column_index_from_string()，来获取列号对应的数字.比如传入参数“I”就会获取到数字9，表示“I”列是第9列。这个数字减一即可得到对应的索引。因为索引是从0开始的，所以需要减一import openpyxl wb = openpyxl.load_workbook("./doc/2019年1月销售订单.xlsx", data_only=True) orderSheet = wb["销售订单数据"] for rowData in orderSheet.rows: productName = rowData[2].value # print(productName) priceIndex = openpyxl.utils.cell.column_index_from_string("I") - 1 # print(priceIndex) price = rowData[priceIndex].value print(price) # 总价 # 5 # 20 # 40 # ...Excel表格写入创建工作簿使用openpyxl.Workbook()函数即可创建一个新工作簿。创建成功后，新创建的工作簿对象会被返回。为了方便之后对这个工作簿进行操作，将这个对象赋值给一个变量newWb。可以访问sheetnames字段来获取工作簿内所有的工作表名称，使用openpyxl.Workbook()创建的工作簿里面，都有一张默认的工作表，名称为Sheet。import openpyxl # 创建一个新工作簿并赋值给变量newWb newWb = openpyxl.Workbook() # 输出新工作簿内所有的工作表名称 print(newWb.sheetnames) # ['Sheet'] 修改工作表名称先通过变量newWb使用中括号 + 工作表名称获取这个工作表对象，然后把这个对象赋值给变量aSheet。通过对工作表对象的 .title属性进行赋值，即可修改工作表的名称。import openpyxl newWb = openpyxl.Workbook() # 将名为Sheet的默认工作表赋值给aSheet变量 aSheet = newWb["Sheet"] # 将aSheet工作表名称修改为“A平台” aSheet.title = "A平台" 创建工作表通过工作簿对象使用create_sheet()函数可以创建一个名称为Sheet的工作表。若名为Sheet工作表已经存在，则会在Sheet后依次添加数字，比如Sheet1，Sheet2。在创建时如需要指定工作表名称，可以将需要指定的工作表名称作为参数传入create_sheet()函数。import openpyxl newWb = openpyxl.Workbook() # 不指定名称创建工作表 newWb.create_sheet() # 指定创建的新工作表名称为"陌上花" newWb.create_sheet("陌上花") # 输出所有的工作表名称以检查是否创建成功 print(newWb.sheetnames) # ['Sheet', 'Sheet1', '陌上花']新创建的工作表对象会在函数调用后返回，在这里也可以直接分别赋值给变量bSheet和cSheet，方便之后操作使用# 创建 B平台 的工作表并赋值给变量bSheet bSheet = newWb.create_sheet("B平台") # 创建 C平台 的工作表并赋值给变量cSheet cSheet = newWb.create_sheet("C平台")Excel设置单元格的值每一个工作表都有一个表头，分别是“商品名”、“月份”和“销售额”。本质上，每一个表头也就是一个一个单元格组成的。要修改每个工作表的表头，就需要用到“设置单元格的值”这个知识点。可以通过“工作表对象["列号行号"].value”这种方式来获取指定的单元格的值。而直接把要设置的值赋值给.value属性，就可以设置或修改这个单元格的值了。# 设置aSheet里A1单元格的值为“编号” aSheet["A1"].value = "编号" aSheet["B1"].value = "月份" aSheet["C1"].value = "销售额" # 输出A1单元格的值以检查是否设置成功 print(aSheet["A1"].value) 可以使用for循环对工作簿对象内的worksheets属性进行遍历，以达到逐个访问所有工作表并设置表头的目的# 使用for循环遍历工作簿对象的worksheets属性 for sheet in newWb.worksheets: # 给每一个工作表设置表头 sheet["A1"].value = "商品名" sheet["B1"].value = "月份" sheet["C1"].value = "销售额" 保存工作簿文件通过工作簿对象使用save() 函数，将文件保存路径作为参数，即可将工作簿保存到指定的文件路径。 一般将工作簿存储成后缀名为.xlsx的文件。如果指定路径的文件已经存在，使用save()函数会覆盖原有文件。# 将工作簿保存到指定路径 newWb.save("/Users/chixm/data/汇总.xlsx")Excel添加行数据想要添加一整行数据可以通过工作表对象使用append()函数。append()函数会在现有工作表内数据的最后一行之后再添加一行数据。append()函数只有一个参数，该参数是一个列表或者元组。使用函数后，列表或元组内的数据会按照顺序逐个添加到目标行中。import openpyxl # 读取工作簿和工作表 wb = openpyxl.load_workbook("怪物数值.xlsx") sheet = wb["东胜神州"] # 通过append()函数传入一个元组添加一行数据 sheet.append(("D10002", "白鼠", 600)) # 保存工作簿到原路径 wb.save("怪物数值.xlsx")
pyenv 来管理 Python 版本pyenv 是一个强大 Python 包管理工具，可以灵活地切换各种 Python 版本，使用 pyenv 来管理我们的 Python 版本，优雅高效且不会破坏掉系统自带的 Python 环境：macOS 安装 pyenv➜ brew install pyenv接着为 pyenv 配置 shell 环境，提高工作效率，可自动联想 Tab 补全我们本地安装的 Python 版本：echo 'eval "$(pyenv init -)"' >> ~/.zshrcpyenv 安装 Python# 查看已经安装的Python版本 ➜ pyenv versions # 查看当前的 Python 版本 ➜ pyenv version # 查看可安装的版本 ➜ pyenv install -l # 安装与卸载 pypy3.8-7.3.11 ➜ pyenv install pypy3.8-7.3.11 ➜ pyenv uninstall pypy3.8-7.3.11版本切换确实很方便，所安装的版本都在 ~/.pyenv/versions 目录下：# global 全局设置 一般不建议改变全局设置 ➜ pyenv global <python版本> # shell 会话设置 只影响当前的shell会话 ➜ pyenv shell <python版本> # 取消 shell 会话的设置 ➜ pyenv shell --unset # local 本地设置 只影响所在文件夹 ➜ pyenv local <python版本>pyenv 的 global、local、shell 的优先级关系是：shell > local > globalPython 的 pip 管理工具pipenv 是一个强大的工具，用于简化 Python 项目中的依赖管理和虚拟环境管理。以下是一些常见的 pipenv 用法示例：更多关于 pipenv 的信息，可以查看它的官方文档： pipenv 官方文档 安装 pipenv首先，你需要确保已经安装了 pipenv。你可以通过以下命令安装它：pip install pipenv创建和管理虚拟环境创建一个新项目并初始化 **pipenv** 环境：mkdir my_project cd my_project pipenv install安装一个新的包pipenv 会自动创建一个虚拟环境（如果还没有创建），并将包安装到该虚拟环境中。pipenv install requests安装一个开发依赖包：开发依赖包只在开发环境中需要，比如测试工具。pipenv install --dev pytest卸载一个包：pipenv uninstall requests激活虚拟环境：激活虚拟环境后，你可以在其中运行 Python 命令和脚本。pipenv shell要退出虚拟环境，使用 exit 命令。运行脚本而不激活虚拟环境：如果你不想手动激活虚拟环境，可以使用以下命令直接在虚拟环境中运行脚本。pipenv run python your_script.py管理依赖文件生成 Pipfile.lock： Pipfile.lock 文件记录了所有包的精确版本，保证项目的一致性。pipenv lock安装 Pipfile 中的所有依赖： 如果你克隆了一个包含 Pipfile 的项目，可以使用以下命令安装所有依赖。pipenv install检查包的安全性： pipenv 提供了一个方便的命令来检查已安装的包是否有已知的安全漏洞。pipenv check其他有用的命令查看已安装包列表：pipenv graph更新包：pipenv update requests或更新所有包：pipenv update清理未使用的包：pipenv clean查看虚拟环境路径：pipenv --venv查看 Python 解释器路径：pipenv --py这些命令和用法应该可以帮助你更有效地管理 Python 项目的依赖和虚拟环境。如果你需要更多信息和详细的用法，可以查看 pipenv 的官方文档。例如：# 安装 pipenv pip install pipenv mkdir my_project cd my_project # 初始化 pipenv 环境 pipenv install # 安装模块 openpyxl pipenv install openpyxl # 激活虚拟环境，运行python，使用 exit 命令退出环境 pipenv shell # 直接在虚拟环境中运行脚本 pipenv run python your_script.py
VsCode中写python代码，输出打印有中文时，控制台输出为乱码：解决方法 - 修改json文件“文件”--“首选项”--“设置”--搜索code-runner.executorMap点击“在settings.json中编辑”在"code-runner.executorMap": 下找到python将python冒号后面的 "python -u"改成"set PYTHONIOENCODING=utf8 && python -u" （添加系统全局变量，变量名PYTHONIOENCODING，值设置为UTF8）然后就
Python的模块为日常编程中许多问题提供了标准的解决方案，同时也能让我们更加简洁优雅地管理代码。模块定义： 每个模块是由1个或多个Python文件构成。是相关的类、函数和变量所组成的一个集合。它可以被其它代码引入并直接使用。通常，一个模块中的各个功能是相互关联的。模块中的函数就像是积木，用一块一块的积木搭建成一个完整的图形，搭好的图形就是模块。 了解完模块的基本概念后，先来看看最常接触的第一大类模块：内置模块。内置模块是在安装Python时自带的模块。Python提供了大量丰富且高质量的内置模块来帮助完成一些系统化工作。比如，生成一个随机的数字可以使用random模块，要处理日期和时间则可以通过datetime模块等。为了使用这些模块，首先需要通过关键词import来导入模块。导入模块（I）import random randomNum = random.random() print(randomNum)代码的作用 这三行代码输出了一个随机数。第一行导入了random模块，该模块用于生成随机数； 第二行将生成的随机数赋值给了变量randomNum； 第三行输出了randomNum这个变量的数值。import 关键字import，中文意思是“导入”，表明我们要在这里导入模块。 模块的名称 一个名为random的模块，该模块用于生成一个随机数。 模块内的函数 导入random模块后，就可以通过 random.xxx() 来使用该模块中的所有函数。这里，我们调用了random模块里的random()函数，该函数用于生成一个0到1的随机浮点数。 模块内的函数 random模块中还有其它的函数，可以根据自己的需要来调用。比如，想生成一个在1到7之间的随机整数，可以使用random模块里的randint()函数，代码为：random.randint(1,7)。 代码小结 要导入模块时，就可以使用这样的格式： 使用import导入模块后，除了可以获取到模块内的函数，还可以获取到该模块中的类。通过调用类里面的方法，来实现某一功能。比如，要获取今天的日期，就需要用到datetime模块里的date类，以及该类中的today()方法。import datetime todayDate = datetime.date.today() print(todayDate)导入模块 使用关键字import，中文意思是“导入”，表明我们要在这里导入一个名称为datetime的模块。 模块中的一个类 一个类，表明我们在调用datetime模块里的date类。date类是一个日期类，里面提供了一些关于日期的方法与属性。 date类里面的某一个方法 一个方法，表明我们要调用的today()从属于date类。该方法用于获取当前的本地日期。 代码小结 导入模块后，想获取到该模块中的类里面的某一个方法时，就可以使用这样的格式： 小练习使用import导入random模块。使用该模块下的random()函数，生成一个0到1之间的随机浮点数，并使用print()将结果输出。import random print(random.random())获取今天日期的年份，并判断跟实际今年的年份（2022）是否相等。相等输出True，不相等输出False。import datetime today = datetime.date.today() year = today.year print(year == 2022)不难看出，一个模块是由很多类和函数组成的。有时候只想导入（import）模块里面的一部分内容，可能是一个类或是一个函数。 比如，我们只希望导入datetime模块中的date类。这时候，就可以用到 from...import... 。导入模块（II）from datetime import date todayDate = date.today() print(todayDate)两个关键字 第一个关键字from允许我们从模块中导入一个指定的部分。这两个关键字，表明从datetime模块里导入date类。 模块的名称 一个名为datetime的模块，表示要从该模块中导入某个类。 一个类 一个类，表明我们要调用的date类属于datetime模块。 date类里面的某一个方法 一个方法，表明我们要调用的today()从属于date类。可以看到，使用from...import...这种形式时，调用datetime模块中的类或函数时不需要datetime.前缀。 代码小结 当我们只想导入模块里面的一部分内容时，就可以使用这样的格式： 第三方模块学习了导入模块的两种方式，但是导入的都是内置模块。这些模块是Python自带的，具有较高的通用性。除此之外，我们还会接触到许多的第三方模块。这些非内置的模块由其他的开发者所编写，提供给公众免费使用，功能更加个性化。可以从Python Package Index上找到自己需要的模块。内置模块可以直接导入后使用，而非内置的模块则需要先进行安装，然后才能导入使用。 安装模块为了安装第三方模块，需要一个叫作 pip 的工具。在安装Python环境的时候，pip工具已经随着一起自动安装了，现在可以直接在电脑上使用pip工具来安装第三方模块。安装第三方模块的方式在不同的电脑系统上略微有些不同Windows要使用pip工具安装第三方模块，需要在Windows的命令提示符里进行。可以使用以下两种方式打开命令提示符： 在电脑左下角「开始菜单」旁的搜索栏里输入cmd 同时在键盘上按下快捷键WIN和R，在运行框里输入cmd。 打开一个Windows命令提示窗口，就可以开始安装第三方模块了。只需要在命令提示符的窗口里，使用 pip3 install「ModuleName」命令。这里，「ModuleName」是你所选择的模块的名称。假如我们想制作一个可交互的柱状图，可以通过第三方模块 pyecharts，该模块是一个强大的数据可视化工具。直接在终端中输入：pip3 install pyecharts==1.8.1 ，然后敲击回车键，就能进行安装。这里由于pyecharts的特殊性，在安装时要指定版本1.8.1，而其它大多数模块都可以直接使用模块名安装。如果在自己电脑上安装不上或安装缓慢，可在命令后添加如下配置进行加速：-i https://pypi.tuna.tsinghua.edu.cn/simple/pip3 install pyecharts==1.8.1 -i https://pypi.tuna.tsinghua.edu.cn/simple/点击回车后，会出现很多的安装信息。当看到「Successfully installed...」或显示「Requirement already satisfied」的时候，说明模块已经安装成功。可能会遇到黄色的警告，这是在提示需要升级pip工具。可以选择忽视，也可以按照指示在终端中输入「pip install --upgrade pip」进行升级。安装过程如图所示。 macOS要使用pip工具安装第三方模块，需要在macOS的终端里进行。我们可以点击「启动台」后，在上方的搜索栏里输入终端，然后打开即可。 打开终端窗口，就可以开始安装第三方模块了。只需要在终端窗口里，使用 pip3 install「ModuleName」命令。这里，「ModuleName」是你所选择的模块的名称。 假如我们想制作一个可交互的柱状图，就可以通过第三方模块 pyecharts 来完成。直接在终端中输入：pip3 install pyecharts==1.8.1 ，然后敲击回车键，就能进行安装。这里由于pyecharts的特殊性，在安装时要指定版本1.8.1，而其它大多数模块都可以直接使用模块名安装。如果在自己电脑上安装不上或安装缓慢，可在命令后添加如下配置进行加速：pip3 install pyecharts==1.8.1 -i https://pypi.tuna.tsinghua.edu.cn/simple/点击回车后，会出现很多的安装信息。当看到「Successfully installed...」的时候，说明模块已经安装成功。 安装过程如图所示。 示例安装成功后，就可以关闭当前窗口，回到编辑器里使用该模块来绘制柱状图了。和内置模块一样，我们需要导入模块。 第一行代码： 使用 pyecharts.charts 的方式，访问了pyecharts模块里的子模块charts。 然后，通过from...import...，从pyecharts模块的子模块charts里导入了Bar类。 第二行代码： 使用from...import...，从pyecharts模块中，导入子模块options，并将其简写为了opts。这里，import...as...是用于在导入一个模块的同时，为该模块取一个别名。这是为了之后在代码中使用该模块时能更加方便，不用再通过options调用，可以直接通过opts。 导入完成后，我们就可以通过这些模块，绘制出一个可交互的柱状图啦。from pyecharts.charts import Bar from pyecharts import options as opts bar = Bar() bar.add_xaxis(["衬衫", "毛衣", "领带", "裤子", "风衣", "高跟鞋", "袜子"]) bar.add_yaxis("商家A", [114, 55, 27, 101, 125, 27, 105]) bar.add_yaxis("商家B", [57, 134, 137, 129, 145, 60, 49]) bar.set_global_opts(title_opts=opts.TitleOpts(title="某商场销售情况")) bar.render("bar.html")小练习引入math模块 使用import来导入内置模块：math，该模块提供了大量的数学运算函数。导入模块后，完成以下两个操作： 通过math模块内 sqrt() 函数，输出99的开平方结果； 通过math模块内 fabs() 函数，输出-0.03的绝对值。 import math print(math.sqrt(99)) print(math.fabs(-0.03))计算平均值 statistics是Python中的一个数学统计模块。使用statistics.mean()可以计算出一个列表的平均值，只需要将列表传入到括号中即可。使用import导入statistics模块，并定义一个列表numList = [10, 99, 78, 50]。使用statistics.mean()计算该列表的平均值，并输出。import statistics numList = [10,99,78,50] print(statistics.mean(numList))from...import... 使用from...import...来完成上一道题目定义一个numList = [10, 99, 78, 50]，使用statistics模块下的mean()来计算该列表的平均值，并输出。from statistics import mean numList = [10,99,78,50] print(mean(numList))
在生活中，我们通过特征与功能来描述一个具体对象，转换到代码中就变成了数据与函数。 回顾已经学过的内容，我们学习了用来存储数据的变量与用来存储代码的函数。 现在让我们把变量与函数打包，来学习在程序中创建类与对象。类代表着一类事物，比如人类，鸟类，汽车，电脑。当我们提起这些事物的时候，我们并不特指某一个具体的东西，比如人类是泛指抽象的全人类而对象指的是类的实例，比如人类的对象是某个具体的人，如张三，李四，tony和kevin。类与对象类代表一些拥有相同特性与功能的事物，如鸟类，人类，猫类等。类中的某一个具体实例称为这个类的实例对象，简称为对象。若请你介绍一下自己的手机，你会如何去做？ 你可以通过颜色、型号、容量大小，屏幕尺寸等数据来描述它的特征； 也可以用拍照、安装应用、打电话等操作来描述它的功能。 我们可以把拥有上述特性的设备都归类于手机，即手机就是一个类。手机的特征称为这个类的属性，手机的功能称为这个类的方法。属性与方法定义： 属性用来描述这个类的一些特征，如品牌，颜色，型号是手机的属性。方法用来表现这个类的一些功能，如拍照，打电话等是手机的方法。在Python中通过class关键字来创建一个类。 为了方便理解，接下来在程序中定义一个手机类。 并为手机设定两个方法：打电话，发短信。 类的定义class Phone(): def makeCall(self, who): return f"正在拨打电话给{who}" def sendMsg(self, who, txt): return f"正在发送短信给{who}, 内容为{txt}"代码的作用 用class定义一个类，并命名为Phone。第2～6行，为该类添加了打电话和发短信两个功能。即定义了两个方法makeCall与sendMsg。第2，3行，makeCall方法接收联系人的名字为参数，并将文字格式化输出。第5，6行，sendMsg方法接收联系人的名字与短信内容为参数，并将文字格式化输出。关键字 class，在程序中定义类的关键字。 类名 一串文字，为类定义的名称。 为了区分类与函数，类的名称首字母建议大写。 括号 一对括号，定义类的标准写法。 : 一个冒号，表明接下来缩进的代码是属于这个类的。 四个空格 一个缩进，表示该代码块属于Phone这个类。 方法名 类中的两个特殊函数，称为方法。 方法又被称为成员函数，用来表现这个类的一些功能。成员函数的第一个参数为self。 特殊的参数 self参数，由程序自动传入的参数，指调用该方法的对象。第一个参数为self，是定义实例方法的固定写法。 代码小结 当我们要定义一个类时就需要这几个部分 类是抽象的，我们要使用类，就需要实例化一个对象。对象是以类为模板创建的。这个过程类似于以人类的共同特性为模板，创造一个特定的人。 可以这样说，你就是人类的一个实例对象。 接下来学习一下如何通过类来实例一个具体的对象。 用Phone类来实例化两个对象表示我的手机与你的手机。 实例化对象class Phone(): def makeCall(self, who): return f"正在拨打电话给{who}" def sendMsg(self, who, txt): return f"正在发送短信给{who}, 内容为{txt}" myPhone = Phone() yourPhone = Phone() ret = myPhone.makeCall("Tony") print(ret) ret2 = yourPhone.sendMsg("Jeremy", "中午吃啥？") print(ret2)代码的作用 将刚才定义好的Phone类拿过来，并实例化两个对象myPhone与yourPhone。第9，10行，创建Phone的对象myPhone与yourPhone。第12行，调用myPhone的方法makeCall，把结果存储到ret中。第14行，调用yourPhone的方法sendMsg，把结果存储到ret2。对象名 一个变量名，为对象设定的名称。 类名 定义好的类名。 括号 括号，表示调用Phone类实例化一个对象。 对象 对象名称，用对象名调用指定的方法。 句点 一个句点【.】。用句点连接对象名与对象的方法，称为句点表示法。例如第11行，表示myPhone使用了他的方法(功能)makeCall（打电话）。 方法名 方法名，对象要调用的方法名称。 实参 调用方法时传递的实参。调用对象的方法时，不需要为self参数传递实参。这里，第11行的“Tony”实参传递给makeCall的“who”形参。第13行的“Jeremy”实参传递给sendMsg的“who”形参，“中午吃啥”传递给sendMsg的“txt”形参。 代码小结 当我们要实例化对象时就需要这几个部分 小练习实例化对象 为Cat实例化一个对象mimi，并使用该对象调用talk方法。class Cat(): def talk(self): print("喵喵喵") # 创建一个Cat对象，并存储在mimi中 mimi = Cat() # 调用mimi的方法talk mimi.talk()类的属性与初始化在刚才的代码中，创建了一个包含两个方法的Phone类，并且创建两个不同的实例对象去调用这些方法。现在让我们为类设置属性，并在创建实例化对象时，初始化该属性的值。手机的属性有：颜色，品牌。 class Phone(): def __init__(self, bd, clr): print("创建实例对象时，自动调用此方法") self.brand = bd self.color = clr myPhone = Phone("华为", "白色") yourPhone = Phone("苹果", "黑色") print(f"我有一个{myPhone.color}的{myPhone.brand}手机") print(f"你有一个{yourPhone.color}的{yourPhone.brand}手机")代码的作用 为Phone类添加品牌（brand）与颜色（color）两个属性。第2行，定义初始化方法__init__并设定两个参数bd与clr。第8，9行，创建实例化对象myPhone与yourPhone，并为__init__方法传递参数两组不同的参数。第10，11行，分别格式化输出实例对象的color与brand属性初始化方法 初始化方法__init__，是一个特殊的方法。init 的左右两边各有两个下划线，即整个名称共有四个下划线。初始化类似于出厂设置，表示“开始时做好准备”，会在创建对象时自动被调用。 特殊的参数 self参数，是调用方法时由程序自动传入的参数，指实例化后的对象。 句点 一个句点，用来连接对象名与属性。因为这里还没有创建对象，所有对象名用self参数代替。 属性 对象的两个变量，称为属性。与之前创建的变量不同，brand与color是专属于该类对象的变量，只能被类的对象使用。 参数 初始化函数的两个形参名。接收传递的数据后赋值给对象的两个属性brand与color。 实参 两组数据。在创建对象时，为初始化函数中的brand与color传递的数据。 使用属性 两个对象分别使用它们的属性，并格式化输出内容。 代码小结 当我们初始化属性时需要这几个部分 特殊的self参数通过前面的内容知道，对象的属性与方法需要用句点表示法将对象名与方法名连接在一起。但是在定义类时，我们还不知道要创建哪些对象，所以self的作用就是将实例化的对象名称(引用)传递到方法中。比如在myPhone对象中，self.brand 代表的是myPhone.brand。 初始化过程 在创建一个实例对象时，程序会自动调用init方法。最后总结一下类与对象的注意事项。方法与属性只能被实例对象调用就像append只能被列表使用一样，方法与属性只能用句点表示法被该类的实例使用，否则就会出错。 函数与方法 在Python中有着一切皆对象的说法，我们创建的字符串、列表、元组等本质上都是该类型的一个对象。所以直接调用的print()、range()为函数，用句点表示调用的append()、keys()等为某个对象的方法。 小练习属性的使用 现有一个Cat类，并为该类初始化了两个属性名称（name）与品种（breed）。假设我有一只“橘猫”叫做“大黄”，实例化一个Cat对象存储到myCat中，并传递参数"大黄", "橘猫"。假设你有一只"布偶猫"叫做“土豆”，实例化一个Cat对象存储到yourCat中，并传递参数"土豆", "布偶猫"最后分别按照“有一只xx叫做xxx”的格式输出（需要用到格式化输出）。class Cat(): def __init__(self, name, breed): self.name = name self.breed = breed def talk(self): print("喵喵喵") # 实例化一个Cat对象存储到myCat中，并传递参数"大黄", "橘猫" myCat = Cat("大黄", "橘猫") # 实例化一个Cat对象存储到yourCat中，并传递参数"土豆", "布偶猫" yourCat = Cat("土豆", "布偶猫") # 分别按照格式输出字符串 print(f"有一只{myCat.breed}叫做{myCat.name}") print(f"有一只{yourCat.breed}叫做{yourCat.name}")判断用户是否为会员 现有一个User类，并为该类初始化了两个属性用户名（name）与是否为会员（isVIP）。实例化一个User对象存储到tony中，并传递参数"Tony", True 实例化一个User对象存储到jeremy中，并传递参数"Jeremy", False 最后分别调用tony与jeremy的sayHi方法。class User(): def __init__(self, name, isVIP): self.name = name self.isVip = isVIP def sayHi(self): if self.isVip: print(f'尊贵的会员{self.name},欢迎您!') else: print(f'{self.name},欢迎您!') # 实例化一个User对象存储到tony中，并传递参数"Tony", True tony = User("Tony", True) # 实例化一个User对象存储到jeremy中，并传递参数"Jeremy", False jeremy = User("Jeremy", False) # 分别调用tony与jeremy的sayHi方法 tony.sayHi() jeremy.sayHi()计算学生平均成绩 现有一个MathScore类，并为该类初始化了两个属性班级名称（name）与本学期数学成绩列表（scoreList）。实例化一个MathScore对象存储到class32 中，并传递参数"三年级二班", [78, 99, 88, 87, 67] 最后调用class32的showMsg方法class MathScore(): def __init__(self, className, scoreList): self.className = className self.scoreList = scoreList self.studentNums = len(self.scoreList) def getSum(self): # 计算成绩总和 s = 0 for score in self.scoreList: # 注：s += score 为 s = s + score 的简写 s += score return s def mean(self): # 计算成绩平均数 return self.getSum()/self.studentNums def showMsg(self): print(f"{self.className}共有{self.studentNums}人,数学平均成绩为{self.mean()}") # 实例化一个MathScore对象存储到class32 中，并传递参数"三年级二班", [78, 99, 88, 87, 67] class32 = MathScore("三年级二班", [78, 99, 88, 87, 67]) # 调用class32的showMsg方法 class32.showMsg()
在 Python 中，我们可以使用【def 函数名(参数):】的方式定义函数。如果我们把 def 定义的函数看作“有名字函数”，那么还有一类函数，其不需要显示定义函数名。这就是匿名函数。匿名函数匿名函数是一种不需要为函数命名的函数定义方式，以 lambda 关键字开头。 匿名函数之所以叫匿名函数，是因为它没有函数名称。 本例中，我们是把一个匿名函数赋值给了变量 square，该变量就可以调用函数。 匿名函数的结构square = lambda x:x*x result = square(9) print(result) multiply = lambda x,y:x*y newResult = multiply(9,10) print(newResult)代码的作用 这两段代码创建两个匿名函数，并且使用变量调用，传入参数，输出了结果。lambda 一个关键字 lambda，用来创建匿名函数。 空格 一个空格，固定格式，关键字 lambda 和具体计算式之间的空格。 参数 这个位置表示该匿名函数的参数，为形参。 如果传入多个参数，需要使用“逗号”隔开。 冒号: 一个冒号：，是“匿名函数”的固定格式，冒号后面是具体如何计算冒号前面的输入数值。 表达式 冒号后面是函数的返回值，注意这里不需使用 return 关键字。 变量 将匿名函数赋给一个变量，再由该变量来调用函数。 调用函数 匿名函数同样需要被调用才能执行，调用仍然使用 ( ) 传参的方式实现。 变量 变量，这个变量会“接受”匿名函数返回出来的值。 代码小结 当要定义匿名函数时，可以使用这样的格式 小练习幂 定义一个“匿名函数”，它的功能是计算一个输入值的3次幂，将匿名函数赋值给变量power，然后输入一个数值 5，并输出计算结果。power = lambda number:number*number*number print(power(5))立方体体积 定义一个“匿名函数”，它的功能是计算立方体的体积，其公式为：长宽高，将匿名函数赋值给变量 area。然后传入参数10, 8, 6，并输出计算结果。area = lambda length,width,height:length*width*height print(area(10, 8, 6))匿名函数使用起来比较方便，但是它也有局限性。 lambda 的主体是一个表达式，而不是一个代码块，不适合处理复杂的逻辑情况。 我们在创建函数时，如果需要处理较为复杂的逻辑，建议使用 def 创建函数，如本例所示，计算列表各元素的累加。 在之前的学习中，都是先定义函数以后，在代码的其他地方调用这个函数。 其实，在函数的内部还可以调用自己，这种调用自己函数就是递归函数。 递归一段程序调用自身的过程我们叫做递归，多见于函数调用函数自身。当两面镜子相互之间近似平行时，镜中嵌套的图像是以无限递归的形式出现的。也可以理解为自我复制的过程 语言例子 如果我们用语言的形式表示递归的话，这个通俗的故事最能体现：从前有座山，山里有座庙，庙里有个老和尚，正在给小和尚讲故事呢！故事是什么呢？“从前有座山，山里有座庙，庙里有个老和尚，正在给小和尚讲故事呢！故事是什么呢？‘从前有座山，山里有座庙，庙里有个老和尚，正在给小和尚讲故事呢！故事是什么呢？…… 接下来，就在案例中，学习递归的使用方法和其中的程序运行逻辑。 递归递归概念比较抽象，我们来一起梳理下。假设创建一个递归函数，用于计算数字累加，传入数字 5 ，计算 5 以内的数字累加。 5+4+3+2+1+0 由于 5 大于 0，程序不会执行函数中 if 判断的代码块，而是返回 5 + sum(4)。 这里的 sum(4) 又是一次 sum() 函数的调用，程序就会返回 4 + sum(3)。 程序就一直调用自己，直到 sum(0)，因为 if 语句的存在，它不需要等待 sum(0) 的计算了，而是直接给出结果 0。 然后程序一路返回，回到最初的 sum(5)，并给出最终的答案：5+4+3+2+1+0 = 15 递归函数会终止么？在递归函数中，if 判断就是终止条件，在本例中当 n 小于等于 0，就返回 0 ，递归就终止了。 如果不加这个终止条件会无休止的递归下去，最终造成程序报错。 类似的，我们要算一个数的阶乘，一个正整数的阶乘是所有小于及等于该数的正整数的积，例如 5! = 5×4×3×2×1我们可以用图中的代码，当 n > 0 的时候，函数会调用它本身，直到 n <= 0。 小练习200以内求和 写一个递归函数可以实现 200 以内的整数和。将函数名命名为 sum，传入参数为 n。# 定义名为sum()函数，传入参数n def sum(n): # 如果n小于等于0 if n <= 0: # 返回0 return 0 # 返回n加上sum(n-1) return n + sum(n-1) # 调用sum()传入200并输出 print(sum(200))
必选参数函数的一种参数类型，在调用这个函数的时候必须传入数据的参数。 传递实参时的顺序在传递必选参数时，形参会按照定义的顺序依次接收数据。调用函数时第一个参数传递给name，第二个参数传递给pet。 缺少实参在调用函数时，缺少或超出对必选参数的传递会导致程序错误。也就是说，在函数中定义了多少个必选参数就要传递多少个实参。 关键字传递当我们忘记了传递顺序时，可以利用“形参名=实参名”的方式传递实参。这样以关键字传递实参的形式，简称为关键字实参。 小练习定义一个函数getArea，设定参数width与height分别接收矩形的宽高，计算矩形的面积并返回。调用该函数，用关键字的形式传递参数宽为5、高为3，并按照“矩形的面积为xx”的格式输出结果。def getArea(width, height): return width*height ret = getArea(width=5, height=3) print(f"矩形的面积为{ret}")若定义一个计算圆形面积的函数，设定参数为半径（radius）与圆周率（pi）。多数情况下，圆周率都会近似为3.14。若pi不是必选参数，设其默认为3.14。只在需要修改圆周率时传递数据，函数调用起来会方便很多。 必选参数定义起来虽然简单，在调用函数时经常会因为缺少实参造成程序错误。接下来学习给形参设置默认值。默认值参数def getArea(radius, pi=3.14): ret = radius * radius * pi return ret ret1 = getArea(2) print(ret1) ret2 = getArea(2, 3.14159) print(ret2)代码的作用定义一个函数getArea，根据传递的半径与圆周率，计算圆的面积并输出。在第1行，定义形参radius与pi，并为pi设定默认值为3.14。在第5行，调用函数getArea，并传递数据2。在第7行，调用函数getArea，并传递数据2与3.14159。关键字一个关键字，def是函数定义的关键字，是define的缩写。括号 括号与冒号，这是函数定义的固定格式。逗号 一个逗号，用来分割多个参数。 必选参数 一串字母radius，必选参数。必选参数要定义在默认值参数之前。 默认参数 一串字母pi，默认值参数。默认参数可以有任意个，但必须定义在必选参数之后（若必选参数存在）。 等号 一个等号，赋值符号。默认值 一组数据，为参数pi设置默认值。若在调用函数时，没有为参数pi传递实参，参数pi默认为3.14。传递一个实参 调用函数，只为必选参数传递整数2。因为pi没有接收到参数，所以pi将使用默认值3.14。传递两个实参 调用函数，传递参数2与3.14159。此时pi接收到的实参数据3.14159会覆盖默认值3.14。 代码小结 当我们定义一个默认值参数时就需要这几个部分 目前学习了两种类型的参数，必选参数与默认值参数。这两种参数形式涵盖了80%以上的函数使用。 在定义不同的参数时，需要注意避免一些常见的错误。1.定义参数的顺序在定义函数时，定义形参的顺序是：1，必选参数；2，默认参数。 当有必选参数和默认参数的时候，必选参数必须写在默认参数的前面，否则程序会出错。 2.参数名避免使用无意义的字母在传递实参给函数时，若忘记定义顺序可以使用“形参名=实参”的方式。 但如果定义的形参名是诸如a，abc这样无意义的名字，会减少代码可读性，容易混淆。 所以设定参数名时，尽量使用有意义的名称。 最后，对这两种参数的差异性做一个总结。
初识函数定义 函数是指封装了某一特定功能的代码块。简单的讲，函数就是用来存储代码的“特殊变量”。前面接触过的很多“功能”都是函数。比如在屏幕上输出一些数据的print()，生成一个指定范围整数序列的range()等。函数的功能是如何定义的呢？定义函数def sayWelcome(): print("欢迎光临") print("商品一律九折")代码的作用 这3行代码做的事情是定义了一个叫做“sayWelcome”的函数。这个函数的功能是输出欢迎语内容。def 一个关键字，def是函数定义的关键字，是define的缩写。sayWelcome 一个名称，函数名。 这里的名称其实就是变量名，只不过需要存储的不再是数据，而是代码，我们称为函数名。括号 一对括号，是函数定义的标准格式。冒号 一个冒号，表明接下来缩进的代码是属于这个函数的。缩进 四个空格。和判断、循环一样，函数内部的代码也需要缩进相应的空格。函数体 几行代码组成的代码块。实现该函数功能的代码块，称为函数体。代码小结 当我们要定义函数时就需要这几个部分。现在我们已经将输出欢迎语的代码打包，并为它贴上了sayWelcome的标签。当我们需要展示欢迎语时，只需要“打电话”（call）给电脑，让它在此处执行sayWelcome的代码。在代码中使用我们已经定义好的函数，这个过程称为调用函数（Call Function）。调用函数def sayWelcome(): print("欢迎光临") print("商品一律九折") sayWelcome() sayWelcome()代码的作用 定义一个sayWelcome函数，实现输出欢迎语的功能。第5、6行代码，调用了sayWelcome函数。sayWelcome 一个名称，被调用的函数名。程序通过函数名来定位函数体中的代码。括号 一对括号，调用符号。表示在此处执行该函数中的代码，是调用函数的标准格式。代码小结 当我们要调用函数时就需要这几个部分。 代码执行顺序 函数体中的代码不是立刻执行的，而是等到该函数被调用时才执行。我们可以理解为：函数的调用是一个迂回的路径。 当程序执行到第七行代码时，开始调用setWatermark函数时，并不会继续执行第八行代码，而是跳转到定义函数setWatermark()的内部 从第二行开始执行 直到第2,3,4行代码结束 再跳回到第7行代码，从而继续执行第8行代码 现在我们可以把需要重复使用的代码定义为一个函数，就像刚才的sayWelcome函数。若我们希望修改函数中的内容怎么办呢？ 若定义函数时预留一个位置接收数据。根据不同的情况传递不同的数据，就能更加灵活的解决刚才的问题。这时候我们需要为函数“挖空”，并在调用函数时“填空”，即设置参数。我们把提前挖好的“空”称为形参，把用来填空的数据称为实参。形参与实参定义 形参是形式参数的简称，指定义函数时设置的参数名称。实参是实际参数的简称，指调用函数时实际传递的数据。为函数设置参数def sayWelcome(discount): print("欢迎光临") print(f"商品一律{discount}") sayWelcome("九折") sayWelcome("五折")代码的作用 定义sayWelcome函数，并为它们设置一个参数discount。第1行，定义sayWelcome函数并在括号中设置形参名称discount。第3行，将discount形参放到函数体中使用，使discount中的数据按照指定的格式输出。第5～6行，多次调用sayWelcome函数，并分别为discount形参传递实参数据“九折”、“五折”。形参 定义一个形参，用来接收数据的参数名称。 形参 在代码中使用形参，接收到的数据会被传递到此处使用。 实参 实参，调用函数时传递给形参discount的数据。 代码小结 我们通过下面的代码为函数设置参数。 形参 形参是定义函数时设置的参数名称。相当于我们定义了一个变量，但不需要给该变量赋值。实参 实参是调用函数时传递给形参的数据。相当于为形参变量赋值的数据。 参数可以定义多个，也可以不定义。如果参数不止一个，多个参数之间可以用英文逗号“,”隔开。根据函数的功能不同，我们可以传递不同类型的实参数据。比如，我们可以把店铺名称与产品折扣都设置为参数。小练习计算BMI指数 请定义一个叫做“getBMI()”的函数，该函数包括2个参数height, weight，分别代表身高和体重。这个函数的功能是通过一个人的身高和体重计算BMI指数，并用print输出结果。BMI指数的计算公式为：BMI = 体重 /（身高X身高）然后分两次调用这个函数：第一次传入参数(1.83, 60)。第二次传入参数(1.60, 50)。def getBMI(height, weight): BMI = weight / (height * height) print(BMI) getBMI(1.83, 60) getBMI(1.60, 50)请定义一个叫做“isOdd”的函数，该函数包括1个参数number，代表一个整数。这个函数的功能是通过if语句判断number中的数字是否为奇数，并用print输出结果。若此数为奇数，输出“奇数”，否则输出“偶数”。 然后分两次调用这个函数：第一次传入参数25。第二次传入参数10。# 定义isOdd函数 def isOdd(number): # 判断number是否为奇数 if number % 2 == 1 : print("奇数") else : print("偶数") # 调用isOdd函数 isOdd(25) isOdd(10)