python编程-基础

admin
0
2026-09-04

一、认识python

人生苦短,我用python ----- life is short ,you need python

python的哲学: 明确,优雅,简单

问题: 我都学了shell,为什么还要学python ?

  • python更强大,执行效率比shell高。
  • python可以跨平台,可移植性好,标准统一,在不同平台程序结果一致。但shell在不同平台还可能不一样(比如centos6,centos7)
  • python模块(模块可以通俗的先理解为插件 ) 丰富,应用场景更丰富。
  • 还有就是顺应开发型运维的趋势,更高薪:smiley:。 DEVOPS

但是,所以对于新时代的运维工程师来说,两种技能都要掌握。

python起源

python的创始人为Guido von Rossum(吉多·范·罗苏姆),俗称”龟叔“,荷兰人。1989年圣诞节期间,在阿姆斯特丹,Guido为了打发圣诞节的无趣,决心开发一个新的脚本解释程序,做为ABC 语言的一种继承。之所以选中Python(大蟒蛇的意思)作为该编程语言的名字,是因为他是一个叫Monty Python的喜剧团体的爱好者。

ABC是由Guido参加设计的一种教学语言。是专门为非专业程序员设计的。但是ABC语言并没有成功,究其原因,Guido 认为是其非开放(封闭,不开源)造成的。Guido决心在Python中避免这一错误。同时他还想实现在ABC 中闪现过但未曾实现的东西。就这样,Python在Guido手中诞生了。

python的优缺点

胶水语言

python优点:

  1. ==简单,易学,易懂,开发效率高==:Python容易上手,语法较简单。在linux上和写shell一样,拿着vi都可以写,直接就可以运行。
  2. ==免费、开源==:我们运维用的大部分软件都是开源啊,亲!
  3. ==可移植性,跨平台==:Python已经被移植在许多不同的平台上,Python程序无需修改就可以在Linux,Windows,mac等平台上运行。
  4. ==可扩展性==:如果你需要你的一段关键代码运行得更快或者希望某些算法不公开,你可以把你的部分程序用C或C++编写,然后在你的Python程序中使用它们(讲完编译型语言和解释型语言区别就容易理解了)。
  5. ==丰富的库==: 想产生个随机数? 调库啊。想操作os? 调库啊。想操作mysql? 调库啊调库君。。。。。。Python的库太丰富宠大了,它可以帮助你处理及应对各种场景应用。
  6. ==规范的代码==:Python采用强制缩进的方式使得代码具有极佳的可读性。

python缺点:

  1. ==执行效率较慢== : 这是解释型语言(下面的解释器会讲解说明)所通有的,同时这个缺点也被计算机越来越强性能所弥补。有些场景慢个几微秒几毫秒,一般也感觉不到。

Python应用场景

  1. 操作系统管理、服务器运维的自动化脚本

一般说来,Python编写的系统管理脚本在可读性、性能、代码重用度、扩展性几方面都优于普通的shell脚本。

  1. Web开发

Python经常被用于Web开发。比如,通过mod_wsgi模块,Apache可以运行用Python编写的Web程序。Python定义了WSGI标准应用接口来协调Http服务器与基于Python的Web程序之间的通信。一些Web框架,如Django,TurboGears,web2py,Zope等,可以让程序员轻松地开发和管理复杂的Web程序。

  1. 服务器软件(网络软件)

Python对于各种网络协议的支持很完善,因此经常被用于编写服务器软件、网络爬虫。第三方库Twisted支持异步网络编程和多数标准的网络协议(包含客户端和服务器),并且提供了多种工具,被广泛用于编写高性能的服务器软件。

  1. 游戏

很多游戏使用C++编写图形显示等高性能模块,而使用Python或者Lua编写游戏的逻辑、服务器。相较于Python,Lua的功能更简单、体积更小;而Python则支持更多的特性和数据类型。

  1. 科学计算

NumPy,SciPy,Matplotlib可以让Python程序员编写科学计算程序。

  1. 其它领域

无人驾驶,人工智能等。

解释型语言与编译型语言

计算机只能识别机器语言(如:01010101001这种), 程序员不能直接去写01这种代码,所以要程序员所编写的程序语言翻译成机器语言。将其他语言翻译成机器语言的工具,称之为**==编译器或解释器==**。

如:中国人 ---(翻译)----外国人

编译器翻译的方式有两种,一种是编译,一种是解释。区别如下:

编译型语言
源代码
编译器
最终可执行文件
操作系统
Windows / Linux / Mac
解释型语言
源代码
解释器
逐行解释每一句
源代码
CPU

正因为这样的区别,所以解释型语言开发效率高,但执行慢。

python版本

在centos7上默认自带的python版本为2.7.X

# python --version
Python 2.7.5

python2.x 2020年终止维护

python3.x 目前主流版本

python官网下载地址:

https://www.python.org/getit/

第一个python程序

  1. 使用vi或vim直接写
# vim 1.py						

#!/usr/bin/python				# 声明类型,指明解释器命令路径
#-*- coding: utf-8 -*-			# 指定字符格式为utf-8(可以打印中文),python3不用再指定了

print "hellow world"			# python2的写法,python3执行会报错
print("hello world")			# python3的写法,python2也可以执行
print("哈哈")				   	   # python2指定了utf-8字符,那么这里就可以使用中文

执行方法一:
# python 1.py

执行方法二:
# chmod 755 1.py
# ./1.py						# 需要有执行权限和声明类型才能这样执行
  1. 使用python命令(默认版本)交互写
# python

>>> print ("hello world")
hello world
>>> exit()					--使用exit()或quit()或ctrl+d键来退出

二、python相关软件安装与使用

python3.x安装

在linux上(如果是虚拟机上安装,请把内存调大,建议内存调整为3G或以上)安装python3.x(我这里为3.6.6版本,2019年6月)

第1步: 安装编译需要的依赖包

cenots7系统如果gnome图形界面和开发工具都安装了,那么就还需要安装zlib-devel,openssl,openssl-devel这几个依赖包
# yum install zlib-devel openssl openssl-devel

第2步: 将下载的安装包拷贝到centos7系统上(此步骤请自行完成),然后解压安装

# tar xf Python-3.6.6.tar.xz -C /usr/src/
# cd /usr/src/Python-3.6.6/

第3步: 编译安装

# ./configure  --enable-optimizations
关于--enable-optimizations参数的说明:可能因不同的同学电脑的兼容问题,有些同学会在make步骤卡住,可以尝试去掉此参数重新编译
# make					
这一步时间较长(20-30分钟,视机器速度而定)
# make install
编译第三步几乎不会报错,除非你的安装路径空间不够了

第4步: 确认安装后的命令

# ls /usr/local/bin/python3.6
确认此命令,此为python的主命令(也就是解释器),并且要与默认的python2区分开
# ls /usr/local/bin/pip3.6			
确认此命令,pip为python安装模块的命令,后面课程会用得到

扩展: 如果觉得源码编译安装太费时间的话,可以使用epel源安装python3.6的rpm版.(需要centos7默认的外网源,能上外网)

# yum install epel-release -y
# yum install python36

pycharm安装

PyCharm是一种Python ==IDE==(Integrated Development Environment, 集成开发环境)。它带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具,比如调试、语法高亮、Project管理、代码跳转、智能提示、自动完成、单元测试、版本控制。

pycharm官网下载地址:

http://www.jetbrains.com/pycharm/download/#section=linux

专业版: 功能全,需要收费,但可以试用30天

社区版: 免费版,学习基础够用了

linux下安装pycharm

将下载的pycharm安装包拷贝到centos系统(过程省略,请自行完成),然后解压,直接启动安装程序

==注意==: 安装专业版前一定记得要时间同步)

# tar xf pycharm-professional-2018.2.4.tar.gz -C /usr/local/
# sh /usr/local/pycharm-2018.2.4/bin/pycharm.sh &

按照图形介绍提示一步步安装

1555860013040

1555860112743

1555860172431

1555860274894

1555860893237

1555861061549

1555861643974

1555862757835

1540718441179

1540718853109

练习: 请各位同学在自己的windows或mac电脑上也安装pycharm,记得要先安装对应版本的python(解释器), 再安装pycharm(选择windows的python解释器)

小结:

  • 实际环境中,程序员一般在个人电脑上(windows或MAC等)安装类似pycharm这种IDE工具,然后在IDE工具上进行开发。开发的代码会通过特定的方法上传到服务器整合(以后会学到)。
  • 安装过程主要两个部分:1,先安装python解释器 2,安装pycharm这种IDE工具,并且要指定项目的python解释器
  • pycharm程序的启动没有服务脚本,是使用 sh /usr/local/pycharm-2018.2.4/bin/pycharm.sh &命令来启动

pyenv安装(拓展)

pyenv是一个**==python多版本管理工具==**,当服务器上存在不同版本的python项目时,使用pyenv可以做到多版本的隔离使用(类似虚拟化),每个项目使用不同版本互不影响。

pyenv文档及安装地址:

https://github.com/pyenv/pyenv

1,使用git clone下载安装到家目录的.pyenv目录
# git clone https://github.com/pyenv/pyenv.git ~/.pyenv

2,设置环境变量,并使之生效,这样才能直接使用pyenv命令
# echo 'export PYENV_ROOT="$HOME/.pyenv"' >> /etc/profile
# echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> /etc/profile
# source ~/.bash_profile

# pyenv help
# pyenv install -l		--或者使用pyenv install --list列出所有的python当前可用版本

3,先解决常见依赖包的问题,否则下一步安装会报错
# yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel libpcap-devel xz-devel -y

4,安装3.6.6版本,需要下载并安装,速度较慢。它会安装到~/.pyenv/versions/下对应的版本号
# pyenv install 3.6.6

5,查看当前安装的版本,前面带*号的是默认使用的版本
# pyenv versions		
* system (set by /root/.pyenv/version)
  3.6.6

pyenv-virtualenv是pyenv的插件,为pyenv设置的python版本提供隔离的虚拟环境。不同版本的python在不同的虚拟环境里使用互不影响。

pyenv-virtualenv文档及安装地址:

https://github.com/pyenv/pyenv-virtualenv

1,将pyenv-virtualenv这个plugin下载安装到pyenv根目录的plugins/下叫pyenv-virtualenv
# git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv

2,把安装的3.6.6版本做一个隔离的虚拟化环境,取名为python3.6.6(这个取名是自定义的)
# pyenv virtualenv 3.6.6  python3.6.6

3,active激活使用,但报错
# pyenv activate python3.6.6		
Failed to activate virtualenv.

Perhaps pyenv-virtualenv has not been loaded into your shell properly.
Please restart current shell and try again.
解决方法:
# echo 'eval "$(pyenv init -)"' >> /etc/profile
# echo 'eval "$(pyenv virtualenv-init -)"' >> /etc/profile
# source /etc/profile

4,再次激活,成功
# pyenv activate python3.6.6
pyenv-virtualenv: prompt changing will be removed from future release. configure `export PYENV_VIRTUALENV_DISABLE_PROMPT=1' to simulate the behavior.
(python3.6.6) [root@daniel ~]# pip install ipython		--安装一个ipython测试

5,使用ipython测试完后退出虚拟环境
(python3.6.6) [root@daniel ~]# ipython
In [1]: print ("hello word")                                                    
hello word

In [2]: exit          		                                                          
(python3.6.6) [root@daniel ~]# pyenv deactivate	 --这里exit就退出终端了,用此命令退出虚拟环境
[root@daniel ~]# 

这样的话,你可以在linux安装多个版本的python,使用不同的隔离环境来开发不同版本的python程序.

删除隔离环境的方法:
# pyenv uninstall python3.6.6

三、print打印(重点)

基本的打印规则

Python程序由多个逻辑行构成,一个逻辑行不一定为一个物理行(人眼看到的行)

显示行连接:
​ 在物理行后跟反斜杠, 代表此行连接下一行代码

隐式行连接: () [] {}
在括号里换行会自动行连接

字符串需要用引号引起来,单引双引三引都可以。

示例: 换行打印

help(print)			# 帮助方法

print("hello world") 			
print("python")		# 这是两句分开的打印,会打印两行

print("hello world\npython")	# 打印的结果会换行

print('''hello world
       python''')  	# 打印的结果会换行
      
print("hello world
       python")   	# 错误写法

示例: 不换行打印

print('hello world', end="") 	# python3里加上end=" ",可以实现不换行打印.类似shell里的echo -n
print("python")

print("hello world \
python")			  # 使用\符号连接行,物理上换了行,逻辑上并没有换行。不建议用\符号来连接行

print("hello world" 
      "python")   # (),[],{}里的多行内容不用\连接,但需要每行引起来;打印出来的结果不换行

示例: 使用VT100控制码(用来在终端扩展显示的代码)实现有颜色的打印

print("\033[31;1;31m hello world\033[0m")
print("\033[31;1;32m hello world\033[0m")
print("\033[31;1;33m hello world\033[0m")
print("\033[31;1;34m hello world\033[0m")
print("\033[31;1;35m hello world\033[0m")
print("\033[31;1;36m hello world\033[0m")
结果如下:

1540994215336

打印时的常见异常

  1. 打错单词

1540733911128

  1. 缩进错误

1540734040998

  1. 一行不能打印多次

1540735710279

常见的Python错误:

  • SyntaxError当存在无效的 Python 代码时,就会发生这种情况。
  • NameError:当你试图使用一个未事先声明的变量时,就会发生这种情况。
  • TypeError:当您使用的数据类型不适合您想要执行的操作时,就会发生这种情况。

语法错误

最常见的错误之一是SyntaxError,当您尝试运行无效的 Python 代码时就会发生这种情况,例如拼写错误的关键字、缺少冒号:或缺少右括号。
例如:

print(Hello, World!

# SyntaxError: invalid syntax

上面的代码片段SyntaxError运行时会抛出异常,因为该print()函数需要一个右括号。此外,“Hello, World!”应该用引号括起来。
完整的错误信息可能如下所示:

File "main.py", line 1
    print(Hello, World!
                      ^
SyntaxError: invalid syntax

• 它File "main.py", line 1描述了文件名和行号。
• 小箭头^指向检测到错误的位置。
注意:箭头^有时可能会误导人,因为那是程序认为错误发生的位置;但有时错误发生在箭头所指位置之前!

名称错误

你经常会遇到的另一个错误是NameError,当你试图引用一个尚未创建的变量时就会发生这种情况——这可能是因为你拼错了变量名或者忘记定义变量了!
例如:

print(greetings)

# NameError: name 'greetings' is not defined

上面的代码片段抛出了一个异常,NameError因为我们没有定义greetings变量。我们可以通过预先定义变量来解决这个问题:

greetings = 'Howdy 🤠'
print(greetings)

# Output: Howdy 🤠

TypeError

我们还要了解的另一个常见错误是TypeError。当处理各种数据类型(例如,数字、字符串和布尔值)的变量时,您很可能会遇到此错误。
例如:

message = 'The air quality is '
print(message + 28)

# TypeError: can only concatenate str (not "int") to str

该变量的数据类型为字符串。如果我们尝试向其中message添加一个整数,将会抛出异常。这可以通过类似内置函数的方式解决,或者将数字用引号括起来:

28TypeErrorstr()
message = 'The air quality is '
print(message + str(28))

# Output: The air quality is 28

四、注释

注释(comment)的作用与方法

注释的作用:在程序中对某些代码进行标注说明 ,增强程序的可读性。

注释反面教材:

1541146871585

1.单行注释: # 被注释内容

在# 后面建议添加一个空格 ,然后在写注释的内容

1540885321182

在代码的后面添加注释 :注释和代码之间要至少有两个空格

1540885700072

2.多行注释 : 三引号(三个双引或三个单引)里包含注释内容

1541148380640

小技巧:在pycharm里可以用**==ctrl+/==**来给多行加#注释或去掉注释。

代码规范PEP

Python 官方提供有一系列 PEP(Python Enhancement Proposals) 文档

其中第 8 篇文档专门针对 Python 的代码格式 给出了建议,也就是俗称的 PEP 8

文档地址:https://www.python.org/dev/peps/pep-0008/

谷歌有对应的中文文档:http://zh-google-styleguide.readthedocs.io/en/latest/google-python-styleguide/python_style_rules/

建议: 开发新手请尽量遵守代码规范,pycharm这样的IDE工具会对不规范的代码进行提示。

五、变量 (重点)

什么是变量

一栋楼房,用来容纳人和物。我们可以说去202房间找某人或去303房间找某物。

在这里你可以把楼房理解成内存,202房间或303房间理解为变量名,某人或某物理解成变量的值。

1546853446228

变量:在内存中开辟一块空间,临时保存数据。通俗的说变量名就是存储空间的名字,通过这个名字来访问和存储空间中的数据。

变量的特点

  • 可以反复存储数据

  • 可以反复取出数据

  • 可以反复更改数据

变量的命名规则

  • 变量名只能是字母数字下划线的任意组合

  • 变量名的第一个字符不能是数字

  • 变量名要有见名知义的效果, 如UserName,user_name

  • 变量名区分大小写

  • 以下关键字不能声明为变量名(关键字是python内部使用或有特殊含义的字符)
    ['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

import keyword			# 导入keyword模块
print(keyword.kwlist)  	# 打印上面的关键字列表

变量的创建(定义)

在python中,每一个变量在使用前都必须赋值,变量赋值后,变量就创建成功了。

==变量名 = 值==

示例:

num = 100     			# num第一次出现是表示创建(定义)这个变量    
num = num-10		
print(num)

示例:

name1 = "daniel"
print(id(name1))
name2 = "daniel"
print(id(name2))   # id()函数用于获取对象内存地址编号;name1和name2得到的id相同,说明指向同一个内存空间

示例:

a = 1
print(id(a))
b = 2
a = 3
print(id(a))
c = 1
print(id(c))

1413311520
1413311584
1413311520
第1次打印和第2次打印的id结果不一样,说明a=3是重新开辟了一个内存空间存放3这个值
第1次打印和第3次打印的id结果一样,说明c=1相当于是把存放1这个值的内存空间名由a换成了c

示例:

a = 1
b = 2
c = 1

print(id(a))
print(id(b))
print(id(c))
结果: id(a)与id(c)得到的结果一样,因为它们的值一样。

示例:

a = 1
b = 2
c = 1
a = 2

print(id(a))
print(id(b))
print(id(c))
结果: id(a)与id(b)得到的结果一样,因为它们的值一样。

小结: 变量名可以不一样,只要值一样,通过id()函数得到的内存地址编号就一样。(目前仅限讨论**==数字这种不可变数据类型==**)

这里引出两个概念:可变数据类型不可变数据类型(有个印象先,讲数据类型时再细讲)

两个变量值的交换

其它语言中可以借助于第三个变量来交换变量 a 和b 的值

python中可以直接交换,两个变量的值

示例:

a, b = 1, 2				# 可以像这样一次定义多个变量
print(a, b)

a, b = b, a
print(a, b)

变量的类型

在程序中,为了更好的区分变量的功能和更有效的管理内存,变量也分为不同的类型。

Python是**==强类型====动态==**解释型语言。

强类型: 不允许不同类型相加。如整型+字符串会报错。

动态:不用显示声明数据类型,确定一个变量的类型是在第一次给它赋值的时候,也就是说: ==变量的数据类型是由值决定的==

示例:

name = "zhangsan"		# str类型
age = 25				# 25没有加引号,则为int类型;加了引号,则为str类型;
height = 1.8			# float类型
marry = True			# bool类型

print(type(name))			# 通过type()内置函数得知变量的类型
print(type(age))
print(type(height))
print(type(marry))

Python基本数据类型分类

  1. ==数字==
    • int 整型(1, 2, -1, -2)
    • float 浮点型(34.678)
    • bool 布尔型(True/False)
    • complex 复数(4+3J, 不应用于常规编程,这种仅了解一下就好
  2. ==字符串==
    • str 单引号,双引号和三引号内表示的内容为字符串 “hello world" "12345"
  3. ==列表==
    • list 使用中括号表示 [1, 2, 3, 4]
  4. ==元组==
    • tuple 使用小括号表示 (1, 2, 3, 4)
  5. ==字典==
    • dict 使用大括号表示,存放key-value键值对 {"a":1, "b":2, "c":3}
  6. ==集合==
    • set 也使用大括号表示,但与字典有所不同 {1, 2, 3, 4}

类型的转换

转换函数说明
int(xxx)将xxx转换为整数
float(xxx)将xxx转换为浮点型
str(xxx)将xxx转换为字符串
list(xxx)将xxx转换为列表
tuple(xxx)将xxx转换为元组
dict(xxx)将xxx转换为字典
set(xxx)将xxx转换为集合
chr(xxx)把整数[0-255]转成对应的ASCII码
ord(xxx)把ASCII码转成对应的整数[0-255]

示例:

age = 25					
print(type(age))	# int类型
age = str(25)
print(type(age))	# str类型

示例:

name = "zhangsan"
age = 25				

print(name, "你" + age + "岁了")    # str+int,字符串拼接报错;age=str(25),这一句就可以成功。

六、输入输出(重点)

输入

还记得shell里的read吗?

用python3中可以使用input()函数等待用户的输入(python2中为raw_input()函数)

示例:

name = input("what is your name: ")
age = input("what is your age: ")		# input输入的直接就为str类型,不需要再str()转换了

print(name, "你" + age + "岁了")

小结: 用单引号,双引号,三引号和input()函数输入的都为字符串类型。

输出

普通输出

输出用print()

示例:

print("="*10)				 # 表示连续打印10个=符号
print("1-系统")
print("2-数据库")
print("3-quit")
print("="*10)
或者
print("="*10)
print('''1-系统				# 使用'''  '''符号来换行
2-数据库
3-quit''')
print("="*10)
结果一样,如下:

1541051758585

格式化输出

还记得awk里的printf吗? (学过C基础的也肯定知道printf)

python里不用printf,但也可以用 % 表示格式化操作符

操作符说明
%s字符串
%d整数
%f浮点数
%%输出 %

示例:

name = "daniel"
age = str(20)

# 字符串拼接的写法
print(name+",你有"+age+"岁了")

# 两种格式化输出的写法
print("%s,你有%s岁了" % (name, age))
print("{},你有{}岁了".format(name, age))

小结:

  • %s或%d相当于是一个占位符,按顺序一一对应后面()里的变量(需要类型对应)
  • {}也相当于是一个占位符,按顺序--对应后面format()里的变量。这种写法的好处是不用对应类型

综合练习

请用前面所学过的知识,写python代码实现下面的结果(颜色可以不做要求:smiley:):

1541054703297

变量的类型

在程序中,为了更好的区分变量的功能和更有效的管理内存,变量也分为不同的类型。

Python是**==强类型====动态==**解释型语言。

强类型: 不允许不同类型相加。如整型+字符串会报错。

动态:不用显式声明数据类型,确定一个变量的类型是在第一次给它赋值的时候,也就是说: ==变量的数据类型是由值决定的==

示例:

name = "zhangsan"		# str类型
age = 25				# 25没有加引号,则为int类型;加了引号,则为str类型;
height = 1.8			# float类型
marry = True			# bool类型

print(type(name))			# 通过type()内置函数得知变量的类型
print(type(age))
print(type(height))
print(type(marry))

Python基本数据类型分类

  1. ==数字==
    • int 整型(1, 2, -1, -2)
    • float 浮点型(34.678)
    • bool 布尔型(True/False)
    • complex 复数(4+3J, 不应用于常规编程,这种仅了解一下就好
  2. ==字符串==
    • str 按目前所学单引号双引号三引号内表示的内容为字符串 “hello world" "12345"
  3. ==列表==
    • list 使用中括号表示 [1, 2, 3, 4]
  4. ==元组==
    • tuple 使用小括号表示 (1, 2, 3, 4)
  5. ==字典==
    • dict 使用大括号表示,存放key-value键值对 {"a":1, "b":2, "c":3}
  6. ==集合==
    • set 也使用大括号表示,但与字典有所不同 {1, 2, 3, 4}

类型的转换

转换函数说明
int(xxx)将xxx转换为整数
float(xxx)将xxx转换为浮点型
str(xxx)将xxx转换为字符串
list(xxx)将xxx转换为列表
tuple(xxx)将xxx转换为元组
dict(xxx)将xxx转换为字典
set(xxx)将xxx转换为集合
chr(xxx)把整数[0-255]转成对应的ASCII码
ord(xxx)把ASCII码转成对应的整数[0-255]

示例:

age = 25					
print(type(age))	# int类型
age = str(25)
print(type(age))	# str类型

示例:

name = "zhangsan"
age = 25				

print(name, "你" + age + "岁了")    # str+int,字符串拼接报错;age=str(25),这一句就可以成功。

小结:

变量的定义

两个变量值的交换

类型 强类型,动态

数字,字符串,列表,元组,字典,集合

六、输入输出(重点)

输入

还记得shell里的read吗?

用python3中可以使用input()函数等待用户的输入(python2中为raw_input()函数)

示例:

name = input("what is your name: ")
age = input("what is your age: ")		# input输入的直接就为str类型,不需要再str()转换了

print(name, "你" + age + "岁了")
name = input("请输入你的名字:")
age = int(input("请输入你的年龄:"))

print(name+",你5年后为"+str(age+5)+"岁了")

小结: 用单引号,双引号,三引号, str()函数转换的和input()函数输入的都为字符串类型。

输出

普通输出

输出用print()

示例:

print("="*10)				 # 表示连续打印10个=符号
print("1-系统")
print("2-数据库")
print("3-quit")
print("="*10)
或者
print("="*10)
print('''1-系统				# 使用'''  '''符号来换行
2-数据库
3-quit''')
print("="*10)
结果一样,如下:

1541051758585

格式化输出(难点)

很多语言里使用printf来进行格式化打印

python里不用printf,但也可以用 % 表示格式化操作符

操作符说明
%s字符串
%d整数
%f浮点数
%%输出 %

示例:

name = "daniel"
age = str(20)

# 字符串拼接的写法
print(name+",你有"+age+"岁了")

# 两种格式化输出的写法
print("%s,你有%s岁了" % (name, age))
print("{},你有{}岁了".format(name, age))
name = input("请输入你的名字:")
age = int(input("请输入你的年龄:"))

print(name+",你5年后为"+str(age+5)+"岁了")
print("%s,你5年后为%d岁了" % (name, age+5))
print("{},你5年后为{}岁了".format(name, age+5))

小结:

  • %s或%d相当于是一个占位符,按顺序一一对应后面()里的变量(需要类型对应)
  • {}也相当于是一个占位符,按顺序一一对应后面format()里的变量。这种写法的好处是不用对应类型

综合练习

请用前面所学过的知识,写python代码实现下面的结果(颜色可以不做要求:smiley:):

1541054703297

参考答案1:

name = input("输入你的名字:")
sex = input("输入你的性别:")
job = input("输入你的职业:")
num = input("输入你的手机号:")

print("-"*10+"information of "+name+"-"*10)
print("name: {}".format(name))
print("sex: {}".format(sex))
print("job: {}".format(job))
print("phonenum: {}".format(num))

参考答案2:

name = input("输入你的名字:")
sex = input("输入你的性别:")
job = input("输入你的职业:")
num = input("输入你的手机号:")

print("-"*10+"information of "+name+"-"*10)
print('''name: {}
sex: {}
job: {}
phonenum: {}
'''.format(name, sex, job, num))

参考答案3:

name = input("输入你的名字:")
sex = input("输入你的性别:")
job = input("输入你的职业:")
num = input("输入你的手机号:")

print("-"*10+"information of "+name+"-"*10)

print("name: {}\nsex: {}\njob: {}\nphonenum: {}".format(name, sex, job, num))

七、运算符

算术运算符(常用)

算术运算符描述实例
+加法1+2=3
-减法5-1=4
*乘法3*5=15
/除法10/2=5
//整除10//3=3 不能整除的只保留整数部分
**求幂(次方)2**3=8
%取余(取模)10%3=1 得到除法的余数

开方

运算代码结果
25math.sqrt(25)5.0
32727 ** (1/3)3.0
416pow(16,1/4)2.0

math.sqrt不支持负数

赋值运算符(常用)

赋值运算符描述实例
=简单的赋值运算符,下面的全部为复合运算符c =a + b 将a + b的运算结果赋值给c
+=加法赋值运算符a += b 等同于 a = a + b
-=减法赋值运算符a -= b 等同于 a = a - b
*=乘法赋值运算符a *= b 等同于 a = a * b
/=除法赋值运算符a /= b 等同于 a = a / b
//=整除赋值运算符a //= b 等同于 a = a // b
**=求幂赋值运算符a ** = b 等同于 a = a ** b
%=取余(取模)赋值运算符a %= b 等同于 a = a % b

比较运算符(常用)

比较运算符描述实例
==等于(注意与=赋值运算符区分开),类似shell里的-eqprint(1==1) 返回True
!=不等于,类似shell里的-neprint(2!=1) 返回True
<>不等于(同 != )print(2<>1) 返回True
>大于, 类似shell里的-gtprint(2>1) 返回True
<小于, 类似shell里的-ltprint(2<1) 返回False
>=大于等于 类似shell里的-geprint(2>=1) 返回True
<=小于等于 类似shell里的-leprint(2<=1) 返回False
print(type(2<=1)) 		# 结果为bool类型,所以返回值要么为True,要么为False.

逻辑运算符(常用)

逻辑运算符逻辑表达式描述
andx and yx与y都为True,则返回True;x与y任一个或两个都为False,则返回False
orx or yx与y任一个条件为True,则返回True
notnot xx为True,返回False; x为False,返回True

成员运算符(比较常用)

在后面讲解和使用序列(str,list,tuple) 时,还会用到以下的运算符。

成员运算符描述
inx 在 y 序列中 , 如果 x 在 y 序列中返回 True; 反之,返回False
not inx 不在 y 序列中 , 如果 x 不在 y 序列中返回 True; 反之,返回False
在SQL语句里也有in和not in运算符;如(没有学习mysql的话,后面会学习了就知道了)
mysql > select * from xxx where name in ('tom','john');

身份运算符(拓展)

身份运算符描述实例
isis 是判断两个标识符是不是引用自一个对象x is y, 类似 id(x) == id(y) , 如果是同一个对象则返回 True,否则返回 False
is notis not 是判断两个标识符是不是引用自不同对象x is not y ,类似 id(a) != id(b)。如果不是同一个对象则返回结果 True,否则返回 False。

is 与 == 区别

is 用于判断两个变量引用对象是否为同一个(同一个内存空间), == 用于判断引用变量的值是否相等。

a = [1,2,3]			# 后面会学到,这是列表
b = a[:]			# 后面会学到,这是列表的切片
c = a
print(b is a)		# False
print(b == a)		# True

print(c is a)		# True
print(c == a)		# True

位运算符 (拓展)

大家还记得IP地址与子网掩码的二进制算法吗?

这里的python位运算符也是用于操作二进制的。

位运算符说明
&对应二进制位两个都为1,结果为1
|对应二进制位两个有一个1, 结果为1, 两个都为0才为0
^对应二进制位两个不一样才为1,否则为0
>>去除二进制位最右边的位,正数上面补0, 负数上面补1
<<去除二进制位最左边的位,右边补0
~二进制位,原为1的变成0, 原为0变成1

运算符的优先级

常用的运算符中: 算术 > 比较 > 逻辑 > 赋值

示例: 请问下面的结果是什么?

result = 3-4 >= 0 and 4 * (6 - 2) > 15
print(result)

result = -1 >= 0 and 16 > 15     # 算术运算后
result = False and True			 # 比较运算后
result = False  				 # 逻辑运算后

八、判断语句(重点)

生活中的判断

1541075593993

shell里的判断语句格式

shell单分支判断语句:

if 条件;then
	执行动作一
fi

shell双分支判断语句:

if 条件;then
	执行动作一
else
	执行动作二
fi

shell多分支判断语句:

if 条件一;then
	执行动作一
elif 条件二;then
	执行动作二
elif 条件三;then
	执行动作三
else
	执行动作四
fi

shell里的case语句

case "变量" in 
	值1 )
		  执行动作一
		  ;;
	值2 )
		 执行动作二
		  ;;
	值3 )
		 执行动作三
		  ;;
	* )
		 执行动作四
esac

python里的判断语句格式

python单分支判断语句:

if 条件:					# 条件结束要加:号(不是;号)
	执行动作一			  # 这里一定要缩进(tab键或四个空格),否则报错
    					 # 没有fi结束符了,就是看缩进

python双分支判断语句:

if 条件:
	执行动作一			
else:					# else后面也要加:
	执行动作二

python多分支判断语句:

if 条件一:
	执行动作一
elif 条件二:			  # elif 条件后面都要记得加:
	执行动作二
elif 条件三:
	执行动作三
else:
	执行动作四

shell里有个case语句, 也可以实现多分支判断。但是python里没有case语句.


实例

示例: 基本格式练习

# 单分支判断
if True:
    print("真")				# 前面一定要缩进(tab键或4个空格)

# 双分支判断
if True:
    print("真")				# 前面一定要缩进(tab键或4个空格)
else:
    print("假")				# 前面一定要缩进(tab键或4个空格)

# 多分支判断
num = 34
gnum = int(input("你猜:"))
if gnum > num:
    print("大了")				# 前面一定要缩进(tab键或4个空格)
elif gnum < num:
    print("小了")				# 前面一定要缩进(tab键或4个空格)
else:
    print("对了")				# 前面一定要缩进(tab键或4个空格)

示例:看看下面语句有什么错误:

if 1 > 0:
    print("yes")
else:
    print("no")
print("haha")
    print("hehe")

示例:通过年龄是否成年与性别来判断对一个人的称呼

男的大于等于18 叫 sir

男的小于18 叫boy

女的大于等于18 叫lady

女的小于18 叫girl

name = input("输入你的名字:")
sex = input("输入你的性别:")
age = int(input("输入你的年龄:"))

if sex == "男" and age >= 18:
    print("{},sir".format(name))
elif sex == "男" and age <18:
    print("{},boy".format(name))
elif sex == "女" and age >= 18:
    print("{},lady".format(name))
elif sex == "女" and age < 18:
    print("{},girl".format(name))
else:
    print("错误")

练习: input输入一个年份,判断是否为闰年(能被4整除但不能被100整除的是闰年,或者能被400整除的也是闰年)

year = int(input("输入一个年份:"))

if year % 4 == 0 and year % 100 != 0:
    print("{}是闰年".format(year))
elif year % 400 == 0:
    print("{}是闰年".format(year))
else:
    print("{}是平年".format(year))

if嵌套

if嵌套也就是if里还有if,你可以无限嵌套下去,但层次不宜过多(嵌套层次过多的话程序逻辑很难读,也说明你的程序思路不太好,应该有很好的流程思路来实现)

比如下面的格式:

if 条件一:
    if 条件二:
		执行动作一		# 条件一,二都为True,则执行动作一
    else:
        执行动作二		# 条件一True,条件二False,则执行动作二
    执行动作三			# 条件一True,条件二无所谓,则执行动作三
else:
    if 条件三:
        执行动作四		# 条件一False,条件三True,则执行动作四
    else:
        执行动作五		# 条件一False,条件三False,则执行动作五
	执行动作六			# 条件一False,条件二,三无所谓,则执行动作六
执行动作七				# 与if里的条件无关,执行动作七

示例:

name = input("输入你的名字:")
sex = input("输入你的性别:")
age = int(input("输入你的年龄:"))

if sex == "男":
    if age >= 18:
        print("{},sir".format(name))
    else:
        print("{},boy".format(name))
elif sex == "女":
    if age >= 18:
        print("{},lady".format(name))
    else:
        print("{},girl".format(name))
else:
    print("性别有误")
year = int(input("输入一个年份:"))

if year % 4 == 0:
    if year % 100 != 0:
#    and year % 100 != 0:
        print("{}是闰年".format(year))
    if year % 400 == 0:
        print("{}是闰年".format(year))
else:
    print("{}是平年".format(year))

九、循环语句(重点)

生活中的循环

1541074178192

1541074846394

软件开发中循环

新手村村长:print("啊,今天天气真好啊")
新手村村长:print("啊,今天天气真好啊")
新手村村长:print("啊,今天天气真好啊")
......
新手村村长:print("看在你陪我说话100次的份上,小伙子不错,给你一把屠龙刀吧!")

一般情况下,需要多次重复执行的代码,都可以用循环的方式来完成

while循环

只要满足while指定的条件,就循环

while 循环的基本格式

while 条件:
      条件满足时候:执行动作一
	  条件满足时候:执行动作二
      ......

注意: 没有像shell里的do..done来界定循环体,所以要看缩进。

示例: 打印1-10

i = 1
while i < 11:
   print(i, end=" ")
   i += 1

示例:打印1-100的奇数

i = 1
while i < 101:
    if i % 2 == 1:
        print(i, end=" ")
    i += 1

跳出循环语句

continue		跳出本次循环,直接执行下一次循环    
break			退出循环,执行循环外的代码 
exit()			退出python程序,可以指定返回值

示例: 猜数字小游戏

import random				# 导入随机数模块(后面会专门讲模块的使用,这里先拿来用用)

num = random.randint(1, 100)	# 取1-100的随机数(包括1和100)

while True:
    gnum = int(input("你猜:"))
    if gnum > num:
        print("猜大了")
    elif gnum < num:
        print("猜小了")
    else:
        print("猜对了")
        break
        
print("领奖")

练习: 用while循环实现1-100中的所有偶数之和

i = 2
sum = 0

# 方法一
while i <= 100:
    sum += i
    i += 2
print(sum)

# 方法二
while i <= 100:
    if i % 2 == 0:
        sum += i
    i += 1
print(sum)

# 方法三(了解)
while i <= 100:
    if i % 2 == 1:
        i += 1
        continue
    else:
        sum += i
        i += 1
print(sum)

for循环

for循环遍历一个对象(比如数据序列,字符串,列表,元组等),根据遍历的个数来确定循环次数。

for循环可以看作为定循环,while循环可以看作为不定循环

如:

6点-18点,每个小时整点循环(定了次数,每天都会有6点-18点)

当有太阳,每个小时整点循环(不定次数,天气和季节都会影响是否有太阳)

for循环的基本格式

for 变量  in  数据:
    重复执行的代码

示例:

for i in 1, 2, 3, 4, 5:
    print(i, end=" ")
print()

for i in range(1, 6):	# range()函数,这里是表示1,2,3,4,5(不包括6)
    print(i)
    
for i in range(6):		# range()函数,这里是表示0,1,2,3,4,5(不包括6,默认从0开始)
    print(i)    

for i in range(1, 100, 2):
    print(i, end=" ")
print()

for i in range(100, 1, -2):
    print(i, end=" ")

练习: 用for循环来实现 1-100之间能被5整除,同时为奇数的和

sum = 0
for i in range(1, 101):
    if i % 5 == 0 and i % 2 == 1:
        sum += i
print(sum)

循环嵌套(了解)

前面在讲if时解释过嵌套是什么,这里我们再来做一个总结: if,while,for都可以互相嵌套

示例: 打印九九乘法表

for i in range(1, 10):
    for j in range(1, i+1):
        print("{}*{}={}".format(j, i, i*j), end=" ")
    print()

扩展语法:

for也可以结合else使用,如下面判断质数(只能被1和自己整除的数)的例子

num = int(input("输入一个大于2的整数"))

for i in range(2, num):
    if num % i == 0:
        print("不是质数")
        break
else:						# 这里的else是与for在同一列上,不与if在同一列。
   	 print("是质数")
name = input("输入你的名字:")
age = int(input("输入你的年龄:"))

#print(name, "你", age, "岁了")
print(name+",你5年后"+str(age+5)+"岁了")
print("%s,你5年后%d岁了" % (name, age+5))
print("{},你5年后{}岁了".format(name, age+5))

九、循环语句(重点)

生活中的循环

1541074178192

1541074846394

软件开发中循环

新手村村长:print("啊,今天天气真好啊")
新手村村长:print("啊,今天天气真好啊")
新手村村长:print("啊,今天天气真好啊")
......
新手村村长:print("看在你陪我说话100次的份上,小伙子不错,给你一把屠龙刀吧!")

一般情况下,需要多次重复执行的代码,都可以用循环的方式来完成

while循环

只要满足while指定的条件,就循环

while 循环的基本格式

while 条件:
      条件满足时候:执行动作一
	  条件满足时候:执行动作二
      ......

注意: 没有像shell里的do..done来界定循环体,所以要看缩进。

示例: 打印1-10

i = 1
while i < 11:
   print(i, end=" ")
   i += 1

示例:打印1-100的奇数

i = 1
while i < 101:
    if i % 2 == 1:
        print(i, end=" ")
    i += 1

跳出循环语句

continue		跳出本次循环,直接执行下一次循环    
break			退出循环,执行循环外的代码 
exit()			退出python程序,可以指定返回值

示例: 猜数字小游戏

import random				# 导入随机数模块(后面会专门讲模块的使用,这里先拿来用用)

num = random.randint(1, 100)	# 取1-100的随机数(包括1和100)

while True:
    gnum = int(input("你猜:"))
    if gnum > num:
        print("猜大了")
    elif gnum < num:
        print("猜小了")
    else:
        print("猜对了")
        break
        
print("领奖")

练习: 用while循环实现1-100中的所有偶数之和

i = 2
sum = 0

# 方法一
while i <= 100:
    sum += i
    i += 2
print(sum)

# 方法二
while i <= 100:
    if i % 2 == 0:
        sum += i
    i += 1
print(sum)

# 方法三(了解)
while i <= 100:
    if i % 2 == 1:
        i += 1
        continue
    else:
        sum += i
        i += 1
print(sum)

for循环

for循环遍历一个对象(比如数据序列,字符串,列表,元组等),根据遍历的个数来确定循环次数。

for循环可以看作为定循环,while循环可以看作为不定循环

如:

6点-18点,每个小时整点循环(定了次数,每天都会有6点-18点)

当有太阳,每个小时整点循环(不定次数,天气和季节都会影响是否有太阳)

for循环的基本格式

for 变量  in  数据:
    重复执行的代码

示例:

for i in 1, 2, 3, 4, 5:
    print(i, end=" ")
print()

for i in range(1, 6):	# range()函数,这里是表示1,2,3,4,5(不包括6)
    print(i)
    
for i in range(6):		# range()函数,这里是表示0,1,2,3,4,5(不包括6,默认从0开始)
    print(i)    

for i in range(1, 100, 2):	# 循环1-100的奇数
    print(i, end=" ")
print()

for i in range(100, 1, -2):
    print(i, end=" ")

练习: 用for循环来实现1-100之间能被5整除,同时为奇数的和

sum = 0
for i in range(1, 101):
    if i % 5 == 0 and i % 2 == 1:
        sum += i
print(sum)

循环嵌套(了解)

前面在讲if时解释过嵌套是什么,这里我们再来做一个总结: if,while,for都可以互相嵌套

示例: 打印九九乘法表

1*1=1 
1*2=2 2*2=4 
1*3=3 2*3=6 3*3=9 
1*4=4 2*4=8 3*4=12 4*4=16 
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25 
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36 
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49 
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64 
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81 

思路: 先简单化成下面的图形

* 
* * 
* * * 
* * * * 
* * * * * 
* * * * * * 
* * * * * * * 
* * * * * * * * 
* * * * * * * * * 

再简单化成下面的图形

* 
* * 
* * * 

打印1:

for line in range(1, 4):
    for field in range(1, 4):
        print("*", end=" ")
    print()
    
* * * 
* * * 
* * * 

打印2:

for line in range(1, 4):
    for field in range(1, line+1):
        print("*", end=" ")
    print()
    
* 
* * 
* * * 

打印3:

for line in range(1, 10):
    for field in range(1, line+1):
        print("*", end=" ")
    print()
* 
* * 
* * * 
* * * * 
* * * * * 
* * * * * * 
* * * * * * * 
* * * * * * * * 
* * * * * * * * * 

打印4:

for line in range(1, 10):
    for field in range(1, line+1):
        print("{}*{}={}".format(field, line, field*line), end="\t")
    print()
1*1=1	
1*2=2	2*2=4	
1*3=3	2*3=6	3*3=9	
1*4=4	2*4=8	3*4=12	4*4=16	
1*5=5	2*5=10	3*5=15	4*5=20	5*5=25	
1*6=6	2*6=12	3*6=18	4*6=24	5*6=30	6*6=36	
1*7=7	2*7=14	3*7=21	4*7=28	5*7=35	6*7=42	7*7=49	
1*8=8	2*8=16	3*8=24	4*8=32	5*8=40	6*8=48	7*8=56	8*8=64	
1*9=9	2*9=18	3*9=27	4*9=36	5*9=45	6*9=54	7*9=63	8*9=72	9*9=81	

扩展语法:

for也可以结合else使用,如下面判断质数(只能被1和自己整除的数)的例子

num = int(input("输入一个大于2的整数"))

for i in range(2, num):
    if num % i == 0:
        print("不是质数")
        break
else:						# 这里的else是与for在同一列上,不与if在同一列。
   	 print("是质数")

十、字符串-str(重点)

字符串的定义与输入

在python中,用引号引起来的都是字符串。还有input函数输入的, str()函数转换的等。

string1 = "hello"
string2 = 'hello'
string3 = """hello
python"""
string4 = '''hello
world'''
string5 = input("input anything: ")
string6 = str(18)

print(isinstance(string3,str))	# isinstance函数可以用来判断数据是否为某一个数据类型,返回值为True或False

字符串的拼接与格式化输出

name = "daniel"

str1 = "===" + name + "==="
str2 = "===%s===" % (name)
str3 = "==={}===".format(name)

print(str1)
print(str2)
print(str3)				# 三种方法结果一样
name = "张三"

print("你好,", name)		# 这种打印的结果与后三种稍有不同
print("你好," + name)
print("你好,%s" % (name))
print("你好,{}".format(name))

小结: 变量在引号里得不到值,只能得到变量名,要得到变量的**==值==**,就格式化输出(使用上面三种方法之一即可)

字符串的下标(重点)

字符串,列表,元组都属于==序列==(sequence),所以都会有下标。

什么是下标(index)?

1541171710101

示例: 将字符串遍历打印

str1 = "hello,python"

for i in str1:					# 直接用for循环遍历字符串
    print(i, end=" ")

示例: 将字符串遍历打印,并对应打印出下标

str1 = "hello,python"

for i, j in enumerate(str1):	# 枚举
    print(i, j)

示例: 将字符串遍历打印,并对应打印出顺序号(从1开始,不是像下标那样从0开始)

str1 = "hello,python"

# 方法一
for i, j in enumerate(str1):	
    print(i+1, j)
# 方法二
num = 1
for i in str1:
    print(num, i)
    num += 1

字符串的切片,倒序

问题: 打印字符串的第3-5个字节

shell里的方法:
# echo abcdefg  | cut -c3-5
cde

# echo abcdefg  | awk '{print substr($0,3,3)}'		# substr()是awk里的截取函数
cde

# echo abcdefg  | sed -r 's/(..)(...)(.*)/\2/'		# sed的分域操作
cde
python里循环的方法(但不建议):
str1 = "abcdefg"

for index, i in enumerate(str1):
    if 5 > index > 1:
        print(i, end="")

上面的方法仅作拓宽思路用,python里实现字符串的截取操作首先就应该想到**==切片==**的方法。

字符串,列表,元组都属于序列,所以都可以**==切片==(也就是我们shell里所说的==截取==**)。

a = "abcdefg"
print(a[0:3])		# 取第1个到第3个字符(注意,不包含第4个)
print(a[2:5])		# 取第3个到第5个字符(注意,不包含第6个)

print(a[0:-1])		# 取第1个到倒数第2个(注意:不包含最后一个)
print(a[1:])		# 取第2个到最后一个
print(a[:])			# 全取
print(a[0:5:2])		# 取第1个到第5个,但步长为2(结果为ace)
print(a[::-1])		# 字符串的倒序(类似shell里的rev命令)

扩展比较难理解的切片方法(仅作了解):

str1 = "abcdefghijk"

print(str1[2:0:-1])
print(str1[:3:-1])

字符串的常见操作

abc = "hello,nice to meet you"

print(len(abc))					# 调用len()函数来算长度						      (常用)
print(abc.__len__())			# 使用字符串的__len__()方法来算字符串的长度

print(abc.capitalize())			# 整个字符串的首字母大写
print(abc.title())			    # 每个单词的首字母大写
print(abc.upper())			    # 全大写
print(abc.lower())			    # 全小写
print("HAHAhehe".swapcase())	# 字符串里大小写互换

print(abc.center(50,"*"))		# 一共50个字符,字符串放中间,不够的两边补*
print(abc.ljust(50,"*"))		# 一共50个字符,字符串放左边,不够的右边补*	       (常用)
print(abc.rjust(50,"*"))		# 一共50个字符,字符串放右边,不够的左边补*

print(" haha\n".strip())		# 删除字符串左边和右边的空格或换行	(常用,处理文件的换行符很有用)
print(" haha\n".lstrip())		# 删除字符串左边的空格或换行
print(" haha\n".rstrip())		# 删除字符串右边的空格或换行

print(abc.endswith("you"))		# 判断字符串是否以you结尾	    类似于正则里的$		(常用)
print(abc.startswith("hello"))	# 判断字符串是否以hello开始	类似于正则里的^		(常用)

print(abc.count("e"))			# 统计字符串里e出现了多少次						   (常用)

print(abc.find("nice"))		# 找出nice在字符串的第1个下标,找不到会返回-1
print(abc.rfind("e"))		# 找出最后一个e字符在字符串的下标,找不到会返回-1
print(abc.index("nice"))	# 与find类似,区别是找不到会有异常(报错)
print(abc.rindex("e"))		# 与rfind类似,区别是找不到会有异常(报错)

print(abc.isalnum())		# 判断是否为数字字母混合(可以有大写字母,小写字母,数字任意混合)
print(abc.isalpha())		# 判断是否全为字母(分为纯大写,纯小写,大小写混合三种情况)
print(abc.isdigit())		# 判断是否为纯数字
print(abc.islower())		# 判断是否为纯小写字母
print(abc.isspace())		# 判断是否为全空格

print(abc.upper().isupper())	# 先把abc字符串全转为大写,再判断是否为全大写字母,结果为True

小建议: 字符串的方法非常多,新手第一次容易晕,但请不要一个一个去记忆,在我们的基础课程里主要会用到后面几个标为常用的方法,可以先记住这几个就好。其它的要用的话再查。

示例: 使用input输入字符,判断输入是数字,纯大写字母,纯小写字母,大小写混合字母,还是其它

char = input("输入: ")

if char.isdigit():
    print("输入的是数字")
elif char.isalpha():
    if char.isupper():
        print("输入的是纯大写字母")
    elif char.islower():
        print("输入的是纯小写字母")
    else:
        print("输入是大小写混合字母")
else:
    print("输入的是其它")

字符串的其它操作(了解)

数字,字符串,元组是==不可变数据类型==改变值的话是在内存里开辟新的空间来存放新值,原内存地址里的值不变).下面的操作可以替换字符串的值,但原字符串没有改变。

列表,字典,集合是**==可变数据类型==**(在内存地址不变的基础上可以改变值)

aaa = "hello world,itcast"
bbb = aaa.replace('l','L',2)	# 从左到右,把小写l替换成大写L,并且最多只替换2个
print(aaa)			# 原值不变
print(bbb)			# 改变的值赋值给了bbb变量,所以这里看到的是替换后的值
print("root:x:0:0".split(":"))			# 以:为分隔号,分隔成列表
print("root:x\n:0:0".splitlines())		# 以\n为分隔号,分隔成列表

字符串的join操作

print(" ".join(['df', '-h']))	# 把列表里的元素以前面引号里的分隔符合成字符串

小结:

  • 引号引起来的,input()函数输入的,str()转换的都为字符串类型

  • 多个字符串可以做拼接和格式化输出

  • 字符串属于**==序列==,属于序列的数据类型都有下标**,可以循环遍历可以切片可以拼接

  • 字符串属于**==不可变数据类型==**,不可变数据类型没有增,删,改这种操作

十一、列表-list(重点)

列表是一种基本的**==序列==**数据结构(字符串和元组也属于序列)

列表是一种**==可变数据类型==**(再次强调数字,字符串,元组是不可变类型)

列表的创建

使用**==中括号==括起来,里面的数据称为==元素==**。可以放同类型数据,也可以放不同类型数据,但通常是同类型。

os_list = ["rhel", "centos", "suse", "ubuntu"]

print(os_list)

列表的下标

和字符串一样,见字符串的下标章节

示例:

os_list = ["rhel", "centos", "suse", "ubuntu"]

for i, j in enumerate(os_list):
    print(i, j)

列表的切片,倒序

和字符串一样,见字符串的切片,倒序章节

示例:

os_list = ["rhel", "centos", "suse", "ubuntu"]

print(os_list[1:3])
print(os_list[1:-1])		
print(os_list[::2])			# 打印第1个和第3个元素
print(os_list[::-1])		# 通过切片来倒序

示例: 验证列表为可变数据类型

os_list = ["rhel", "centos", "suse", "ubuntu"]

print(id(os_list))
os_list.reverse()		# 通过reverse操作来倒序,并且是直接改变原数据
print(os_list)			# 列表的元素倒序了
print(id(os_list))		# 在倒序前后id()函数得到的值一样,说明内存地址不变,但值变了(可变数据类型)

列表的常见操作

os_list = ["rhel", "centos", "suse"]
# 增
os_list.append("ubuntu")			# 在列表最后增加一个元素
print(os_list)
os_list.insert(2, "windowsxp")	# 插入到列表,变为第三个
print(os_list)
# 改
os_list[2] = "windows10"			# 修改第三个
print(os_list)
# 删
os_list.remove("windows10") 		# 删除操作,还可以使用del os_list[2]和os_list.pop[2];它们的区别del os_list是删除整个列表,os_list.pop()是默认删除列表最后一个元素;如果都用下标的话,则一样
print(os_list)
# 查
print(os_list[0])				# 通过下标就可以
# 其它操作
print(os_list.count("centos"))	# 统计元素出现的次数
print(os_list.index("centos"))	# 找出centos在os列表里的位置
os_list.reverse()				# 反转列表
print(os_list)
os_list.sort()					# 排序列表,按ASCII编码来排序
print(os_list)
os_list.clear()					# 清除列表所有元素,成为空列表,不是删除列表
print(os_list)

小建议: 重点记住列表的增,删,改,查这几种操作.

列表合并,拼接

list1 = ["haha", "hehe", "heihei"]
list2 = ["xixi", "hoho"]

list1.extend(list2)    		# list1 += list2也可以,类似字符串拼接
print(list1)

练习: 下面是四个选修课报名的列表,请问张三报名了几门选修课?

math = ["张三", "田七", "李四", "马六"]
english = ["李四", "王五", "田七", "陈八"]
art = ["陈八", "张三", "田七", "赵九"]
music = ["李四", "田七", "马六", "赵九"]

list1 = math + english + art + music			
print(list1.count("张三"))

双列表(拓展)

name_list = ["zhangsan", "lisi", "wangwu", "maliu"]
salary = [18000, 16000, 20000, 15000]

for i in range(len(name_list)):
    print("{}的月收入为{}元".format(name_list[i].ljust(10," "),salary[i]))
    
for index, name in enumerate(name_list):
    print("{}的月薪为{}元".format(name,salary[index]))
问题:找出工资最高的人叫啥?
print(name_list[salary.index(max(salary))])

列表嵌套(拓展)

列表里可以嵌套列表,也可以嵌套其它数据类型

emp = [["zhangsan", 18000], ["lisi", 16000], ["wangwu", 20000], ["maliu", 15000]]


for i in range(len(emp)):
    print("{}的月收入为{}元".format(emp[i][0].ljust(10," "),emp[i][1]))
    
for index, i in enumerate(emp):
    print("%s的月薪为%d元" % (i[0],i[1]))    
问题:找出最高工资的人叫啥?
emp = [["zhangsan", 18000], ["lisi", 16000], ["wangwu", 20000], ["maliu", 15000]]

emp2 = []
for i in emp:
    emp2.append(i[1])

print(emp[emp2.index((max(emp2)))][0])

十二、元组-tuple

元组就相当于是**==只读的列表==**;因为只读,所以没有append,remove,修改等操作方法.

它只有两个操作方法:count,index

元组,字符串,列表都属于序列.所以元组也可以切片,也可以使用for来遍历.

元组的创建与操作

列表使用中括号,元组使用小括号。

示例:

tuple1 = (1, 2, 3, 4, 5, 1, 7)

print(type(tuple1))

print(tuple1.index(3))		# 打印3这个元素在元组里的下标	
print(tuple1.count(1))		# 统计1这个元素在元组里共出现几次
print(tuple1[2:5])			# 切片

tuple1[5] = 6					# 修改元组会报错

元组是只读的,不代表元组里任何数据不可变。如果元组里有列表,那么列表里是可变的。

emp2 = (["zhangsan", 18000], ["lisi", 16000], ["wangwu", 20000], ["maliu", 15000])

emp2[0].append("haha")	# 元组里面的列表可以修改

print(emp2)

课后练习

示例:使用getpass模块使用密码隐藏输入(拓展)

隐藏输入密码(类似shell里的read -s ),但在pycharm执行会有小bug,会卡住 (卡住后,用ps -ef |grep pycharm,然后kill -9 杀掉所有pycharm相关进程);在bash下用python命令执行就没问题

import getpass					# 这是一个用于隐藏密码输入的模块
			
username = input("username:")
password = getpass.getpass("password:")

if username == "daniel" and password == "123":
    print("login success")		
else:
    print("login failed")

bash下执行方法

# /usr/local/bin/python3.6 /项目路径/xxx.py

练习: 一个袋子里有3个红球,3个绿球,6个黄球,一次从袋子里取6个球,列出所有可能组合

练习: 改写猜数字游戏,最多只能猜5次,5次到了没猜对就退出

练习: 打印1-1000的质数(只能被1和自己整除的数)

练习:(有难度,想挑战的可以尝试)

使用input输入一个字符串,判断是否为强密码: 长度至少8位,包含大写字母,小写字母,数字和下划线这四类字符则为强密码

提示:因为没有学python的正则,你可以使用这样来判断  if 字符 in "abcdefghijklmnopqrstuvwxyz":

答:

练习:(有难度,想挑战的可以尝试):

tvlist = [
    "戏说西游记:讲述了西游路上的三角恋.",[
        "孙悟空:悟空爱上了白骨精......",
        "唐三藏:唐僧只想取经......",
        "白骨精:她爱上了唐僧......",
        ],
    "穿越三国:王二狗打怪升级修仙史",[
        "王二狗:开局一把刀,一条狗......",
        "吕布:看我方天画鸡......",
        "貂蝉:油腻的师姐,充值998就送!",
        ],
    "金瓶梅:你懂的",[
        "西门大官人:你懂的......",
        "潘金莲:你懂的......",
        "武大郎:你懂的......",
        "武松:你懂的......",
        ],
    "大明湖畔:我编不下去了......",[
        "夏雨荷:xxxxxx",
        "乾隆:xxxxxx",
        "容么么:xxxxxx",
    ],
]

请写python程序实现类似下面的结果:

1541220544911

提示部分代码
import random							# 导入random模块(后面会具体讲模块)
    
tv_name_num = random.randrange(0,len(tvlist),2)   # len(tvlist)长度为8,这是0,2,4,6四个数的随机
tv_role_num = tv_name_num + 1
print("今日的通告: ")
print(tvlist[tv_name_num])
print("可接的角色有: ")

练习:(有难度,想挑战的可以尝试)

小购物车程序
1, 双十一来了,你的卡里有一定金额(自定义)
2, 买东西,会出现一个商品列表(商品名,价格)
3, 选择你要买的商品,卡里的钱够就扣钱成功,并加入到购物车;卡里钱不够则报余额不足
(或者做成把要买的商品都先加入到购物车,最后可以查看购物车,并可以删除购物车里的商品;确定后,一次性付款)
4, 买完后退出,会最后显示你一共买了哪些商品和显示你的余额

提示部分代码:

money=20000

goods_list=[
    ["iphoneX",8000],
    ["laptop",5000],
    ["book",30],
    ["earphone",100],
    ["share_girlfriend",2000],
]

cart_list=[]

十三、字典-dict(重点)

字典:是一种key:value(键值对)类型的数据,它是**==无序的==(没有像列表那样的索引,下标)**.

  • (备:现在也有特殊方法实现的有序字典,有兴趣课后可以搜索了解一下)

它是通过key来找value,查找速度快;

如果key相等, 会**==自动去重==(去掉重复值), 也就是说dict中==没有重复的key==。但是==值是可以相等的==**。

==字符串,列表,元组属于序列,所以有下标,可以切片. 字典和集合是无序的,没有下标,不能切片==

字典的创建和删除

创建字典

方式1:花括号 {} 最常用

# 空字典
d1 = {}

# 键值对,key: value
d2 = {"name":"张三", "age":20, "city":"北京"}
#或
dict1 = {
    'stu01': "zhangsan",
    'stu02': "lisi",
}
print(d2)

方式2:dict() 构造函数

d3 = dict(name="李四", age=25)
print(d3)

# 从列表元组创建
d4 = dict([("a",1), ("b",2)])
print(d4)

方式3:字典推导式

d5 = {i:i*2 for i in range(3)}
print(d5)   # {0: 0, 1: 2, 2: 4}

删除字典

d = {"a":10, "b":20, "c":30, "d":40}

1. del 关键字:删除指定键,删除整个字典

# 删除单个键值对
del d["a"]
print(d)  # {'b': 20, 'c': 30, 'd': 40}
# 删除整个字典对象(变量直接消失)
del d
# print(d)  # 报错 NameError

注意:del d["不存在的键"] → 报 KeyError

2. pop() 删除指定key,并返回被删除的值

d = {"a":10, "b":20, "c":30}
val = d.pop("b")
print(val)  # 20
print(d)    # {'a': 10, 'c': 30}

# 可以设置默认值,键不存在不会报错
res = d.pop("x", None)
print(res) # None

3. popitem() 删除最后插入的一项

(Python3.7+字典有序)

d = {"a":1, "b":2}
item = d.popitem()
print(item) # ('b', 2)
print(d)    # {'a': 1}

4. clear() 清空字典

清空字典所有元素,字典对象保留(变成空字典)

d = {"a":10, "b":20}
d.clear()
print(d) # {}

字典的增删改查

字典是**==可变数据类型==**,所以可以做增删改操作

# 增
dict1["stu05"] = "tianqi"		# 类似修改,如果key值不存在,则就增加
print(dict1)

# 改
dict1["stu04"] = "马六"		   # 类似增加,如果key值存在,则就修改
print(dict1)
# 字典的增加与修改的写法是一样的,区别就在于key是否已经存在

# 查
print(dict1["stu01"])   	# 如果key值不存在,会返回keyerror错误
print(dict1.get("stu01"))  	# 这种取值方法如果key值不存在,会返回none,不会返回错误

# 删
dict1.pop("stu05")  		# 删除这条;也可以del dict1["stu05"]来删除
dict1.popitem()  			# 删除显示的最后一条
dict1.clear()  				# 清空字典
print(dict1)

字典的循环遍历

前面的学习中我们知道可以使用for来遍历字符串,列表,元组.字典虽然不属于序列,但也可以使用for来遍历

print(dict1.keys())   		# 打印所有的键:keys
print(dict1.values()) 		# 打印所有的值:values
print(dict1.items())  		# 把所有键值对一起拿出来,也就转成列表套元组了

# 上面这三种可以使用for来循环遍历

for key in dict1.keys():
    print(key)

for value in dict1.values():
    print(value)

for line in dict1.items():
    print(line)

**练习:**打印出所有value为2的key

dict1 = {
    '张三': 2,
    '田七': 4,
    '李四': 3,
    '马六': 2,
    '王五': 1,
    '陈八': 2,
    '赵九': 2,
}
答:
for i in dict1.items():
    if i[1] == 2:
        print(i[0])

字典练习:

city = {
    "北京": {
        "东城": "景点",
        "朝阳": "娱乐",
        "海淀": "大学",
    },
    "深圳": {
        "罗湖": "老城区",
        "南山": "IT男聚集",
        "福田": "华强北",
    },
    "上海": {
        "黄埔": "xxxx",
        "徐汇": "xxxx",
        "静安": "xxxx",
    },
}
  1. 打印北京东城区的说明(也就是打印出"景点")
  2. 修改北京东城区的说明,改为"故宫在这"
  3. 增加北京昌平区及其说明
  4. 修改北京海淀区的说明,将"大学"改为"清华","北大","北邮"三个学校的列表
  5. 在大学列表里再加一个"北影"
  6. 循环打印出北京的区名,并在前面显示序号(以1开始)
  7. 循环打印出北京海淀区的大学,并在前面显示序号(以1开始)
print(city["北京"]["东城"])
city["北京"]["东城"]="故宫在这"
print(city["北京"]["东城"])
city["北京"]["昌平"]="我们在这"
print(city)
city["北京"]["海淀"]=["清华","北大","北邮"]
print(city["北京"]["海淀"])
city["北京"]["海淀"].append("北影")
print(city["北京"]["海淀"])

for index, i in enumerate(city["北京"].keys()):
    print(index+1, i)

for index, i in enumerate(city["北京"]["海淀"]):
    print(index+1, i)

小结:

字典是否属于序列? 不属于

字典能否切片? 不能切

"我要打印字典的第2个到第5个键值对",这种说法是否正确? 不对

字典是属于可变数据类型还是不可变数据类型? 可变

"字典里面可以嵌套字典,也可以嵌套列表或元组等其它数据类型",这种说法是否正确?

十四、集合-set(了解)

集合和字典一样都是使用**==大括号==**。但集合没有value,相当于只有字典的key。

字符串,列表和元组属于序列,是有序的,但集合是无序的,所以不能通过下标来查询和修改元素。

再总结一下:

整数,字符串,元组是**==不可变==**数据类型(整数和字符串改变值的话是在内存里开辟新的空间来存放新值,原内存地址里的值不变)

列表,字典,集合是**==可变==**数据类型(在内存地址不变的基础上可以改变值)

当然还有一种不可变集合我们这里不做讨论

集合主要特点:

  1. 天生去重(去掉重复值)
  2. 可以增,删(准确来说,集合可以增加删除元素,但不能修改元素的值)
  3. 可以方便的求交集,并集,补集

集合的创建

示例:

set1 = {1, 2, 3, 4, 5, 1, 2}
set2 = {2, 3, 6, 8, 8}

print(type(set1))
print(set1)
print(set2)				# 打印的结果,没有重复值

集合的常见操作(了解)

set1 = {1, 4, 7, 5, 9, 6}
set2 = set([2, 4, 5, 9, 8])

# 交集
print(set1.intersection(set2))
print(set1 & set2)

print(set1.isdisjoint(set2))  			# 判断两个集合是否有交集,类型为bool(有交集为False,没交集为True)
# 并集
print(set1.union(set2))
print(set1 | set2)
# 差集(补集)
print(set1.difference(set2)) 			# set1里有,set2里没有
print(set1-set2)
print(set2.difference(set1)) 			# set2里有,set1里没有
print(set2-set1)
# 对称差集
print(set1.symmetric_difference(set2))  # 我有你没有的  加上 你有我没有的
print(set1^set2)
# 子集
set3=set([4, 5])
print(set3.issubset(set1))              # 判断set3是否为set1的子集
print(set1.issuperset(set3))            # 判断set1是否包含set3

# 集合的增加操作
set1.add(88)
print(set1)
set1.update([168, 998])                  # 添加多个
print(set1)

# 集合的删除操作
set1.remove(88)                         # 删除一个不存在的元素会报错
print(set1)
set1.discard(666)                       # 删除一个不存在的元素不会报错,存在则删除
print(set1)

小建议: 集合在运维开发中应用不多,我们主要记一下集合的天生去重特性求交并补集方便这主要的两点就好。

练习: 有以下4个选修课名单

math = ["张三", "田七", "李四", "马六"]
english = ["李四", "王五", "田七", "陈八"]
art = ["陈八", "张三", "田七", "赵九"]
music = ["李四", "田七", "马六", "赵九"]
  1. 求同时选修了math和music的人
  2. 求同时选修了math,enlish和music的人
  3. 求同时选修了4种课程的人
print(set(math).intersection(set(english),set(music),set(art)))
# 或
print(set(math).intersection(set(english).intersection(set(music))).intersection(set(art)))

python数据类型总结:

1, 数字(int,float,bool,complex); 字符串, 列表,元组,字典,集合

2, 字符串,列表,元组属于序列,它们都有下标。字典,集合没有下标

3, 数字,字符串,元组是不可变类型; 列表,字典,集合是可变类型(不可变集合不讨论)

4, 可以做增,删操作的有列表,字典,集合。

5, 列表,字典可以修改里面的元素, 但集合不可以修改里面的元素。

python里括号使用总结:

小括号(): 用于定义元组; 方法调用; print打印(其实print()也是一个函数); 函数,如len(),id(),type().

中括号(): 用于定义列表; 字符串,列表,元组取下标; 字典取key

大括号(): 用于定义字典,集合; format格式化输出用于取代%s这种的占位符也是大括号

问题:

属于序列的数据类型有哪几种?序列类型有哪些共性?

字符串,列表,元组     有下标,能切片,能拼接,for遍历

属于可变数据类型的有哪几种? 可变数据类型有哪些共性?

列表,集合,字典        可以增,删,改(集合有点特殊)

天生去重的数据类型有哪几种?

集合,字典里的key

可以用for循环遍历打印的数据类型有几种?

字符串,列表,元组,字典, 集合

可以做四则运算的数据类型

数字

十五、python文件IO操作

io(input and output): 磁盘读写

回顾下shell里的文件操作

shell里主要就是调用awk,sed命令来处理文件,特别是sed命令可以使用sed -i命令直接操作文件的增,删,改。

python文件操作的步骤

python文件的操作就三个步骤:

  1. 先**==open打开==**一个要操作的文件
  2. **==操作==**此文件(读,写,追加等)
  3. **==close关闭==**此文件

python文件的打开与关闭

f = open("文件路径","文件访问模式")		# 打开文件简单格式,需要赋值给一个变量


f.close()							   # 关闭的方法
with open("文件路径", '文件访问模式') as f:	# 此方法打开文件不用后面再使用close关闭了	

python文件访问模式

访问模式说明
==r== (read)只读模式,不能写(文件必须存在,不存在会报错)
==w== (write)只写模式,不能读(文件存在则会被覆盖内容(要千万注意),文件不存在则创建)
==a== (append)追加模式,不能读
r+读写模式
w+写读模式
a+追加读模式
rb二进制读模式
wb二进制写模式
ab二进制追加模式
rb+二进制读写模式
wb+二进制写读模式
ab+二进制追加读模式

python主要的访问模式示例

只读模式(r)

**示例: **

先在linux操作系统上使用head -5 /etc/1.txt > /tmp/1.txt准备一个文件

f = open('/tmp/1.txt", encoding="utf-8")		# 默认就是只读模式
# 如果不同平台,可能会字符集编码不一致,不一致的需要指定;一致的不用指定。

data1 = f.read()
data2 = f.read()				# 读第二遍

f.close()

print(data1)
print("="*50)
print(data2)	# 发现读第二遍没有结果;类似从上往下读了一遍,第二次读从最后开始了,所以就没结果了

tell与seek的理解

f = open("/tmp/1.txt", "r")
print(f.tell())			# 结果为0 (告诉你光标在哪,刚打开文件,光标在0位置)
f.seek(5)				# 移你的光标到整个文件的第6个字符那(因为0为第一个)
print(f.tell())			# 结果为5
f.seek(2)				# 移你的光标到整个文件的第3个字符那,从0开始算,而不是从上面的位置开始算
print(f.tell())			# 结果为2

f.close()

深入理解只读模式

示例:

f = open("/tmp/1.txt", mode="r")

data1 = f.read()		# 读了第一次后,光标在最后的位置
f.seek(0)				# 通过seek(0)将光标又重置回开始的位置
data2 = f.read()		# 再次读的话,就可以又重头读一遍了,data2变量的内容与data1的内容就一致了

f.close()

print(data1)
print("="*20)
print(data2)

**示例: **

f = open("/tmp/1.txt", "r")

f.seek(5)					# 光标移到第6个字符那里
data1 = f.read()			# read是读整个文件在光标后面的所有字符(包括光标所在的那个字符),读完后,会把光标移到你读完的位置

f.seek(5)					# 光标重置到第6个字符那里
data2 = f.readline()		# readline是读光标所在这一行的在光标后面的所有字符(包括光标所在的那个字符),读完后,会把光标移到你读完的位置

f.seek(5)					# 光标重置到第6个字符那里
data3 = f.readlines()		# readlines和read类似,但把读的字符按行来区分做成了列表

f.close()
print(data1)
print("="*30)
print(data2)
print("="*30)
print(data3)

示例: 打印文件的第3行

f = open("/tmp/1.txt", mode="r")

data = f.readlines()			# 把文件从第1行到最后1行全读取,并转成列表

f.close()
print(data[2].strip())		# 通过列表的下标2取第3行,取出来的行是字符串,使用strip()去掉换行符

文件读的循环方法

**示例: **

f = open("/tmp/1.txt", "r")

#循环方法一:
for index, line in enumerate(f.readlines()):
     print(index, line.strip())		# 需要strip处理,否则会有换行
        
# 循环方法二:这样效率较高,相当于是一行一行的读,而不是一次性全读(如果文件很大,那么一次性全读会速度很慢)
for index, line in enumerate(f):
     print(index, line.strip())

f.close()

示例: 打印文件的第3行

f = open("/tmp/1.txt", mode="r")

for index, line in enumerate(f):		# 边读边循环
    if index == 2:						# 通过enumerate产生的下标来取第3行
        print(line.strip())				# 每一行的内容为字符串类型,使用strip()处理换行符

f.close()

示例: 通过/proc/meminfo得到可用内存的值

f = open("/proc/meminfo", "r")

for line in f:
    if line.startswith("MemAvailable"):
        print(line.split()[1])

f.close()

只写模式(w)

**示例: **

f = open("/tmp/1.txt",'w')      # 只写模式(不能读),文件不存在则创建新文件,如果文件存在,则会复盖原内容(千W要小心)
data = f.read()  				# 只写模式,读会报错

f.close()

示例: 创建新文件,并写入内容

f = open("/tmp/2.txt", 'w')	# 文件不存在,会帮你创建(类似shell里的 > 符号)

f.write("hello\n")			# 不加\n,默认不换行写
f.write("world\n")
f.truncate()				# 截断,括号里没有数字,那么就是不删除
f.truncate(3)				# 截断,数字为3,就是保留前3个字节
f.truncate(0)				# 截断,数字为0,就是全删除
 
f.close()

练习: 把九九乘法表直接写到一个文件里

f = open("/tmp/3.txt", "w")

for i in range(1, 10):
    for j in range(1, i+1):
        f.write("{}*{}={} ".format(i, j, i*j))
    f.write("\n")

f.close()

追加模式(a)

示例:

f = open("/tmp/2.txt", 'a')	# 类似shell里的>>符

f.write("hello\n")	
f.write("world\n")
f.truncate(0)				# 追加模式也可以使用truncate截取前面的数据

f.close()

小结:

r: 只读模式 文件必须要存在;

w: 只写模式 文件存在则会清空原文件内容再写,不存在则会创建文件再写

a: 追加模式 与w模式的区别为a模式不清空原文件内容,在最后追加写

比较r+,w+,a+三种模式(拓展)

r+文件必须要存在,相当于在只读模式的基础上加了写权限;

w+会清空原文件的数据,相当于在只写模式的基础上加了读权限;(可以在任意位置写,但要用seek定位光标,还要区分读光标和写光标)

a+不会改变原文件的数据,相当于在只追加模式的基础上加了读权限;(写是在最后写,即使用seek把光标移到前面,仍然会写在最后)

r+,w+,a+混合读写深入理解(拓展)

**示例: **

f = open("/tmp/2.txt", "w+")

f.write("11111\n")
f.write("22222\n")
f.write("33333\n")

print(f.tell())			# 打印结果为18,表示光标在文件最后

f.write("aaa")			# 这样写aaa,相当于在文件最后追加了aaa三个字符

f.seek(0)				# 表示把光标移到0(也就是第1个字符)
f.write("bbb")			# f.seek(0)之后再写bbb,就是把第一行前3个字符替换成了bbb

f.seek(0)				# 把光标再次移到0
f.readline()			# 把光标移到第1行最后
f.seek(f.tell())		# f.seek到第1行最后(如果这里理解为两个光标的话,你可以看作是把写光标同步到读光标的位置)
f.write("ccc")			# 这样写ccc,就会把第二行的前3个字符替换成ccc

f.close()

练习: 往一个新文件里写九九乘法表,并直接读出结果

f = open("/tmp/4.txt", "w+")

for i in range(1, 10):
    for j in range(1, i+1):
        f.write("{}*{}={} ".format(i, j, i*j))
    f.write("\n")

f.seek(0)						# 这里需要seek(0),否则读不出来
data1 = f.read()

f.close()
print(data1)

总结:

r+,w+,a+这三种模式因为涉及到读与写两个操作,你可以使用两个光标来理解,但这样的话读光标与写光标会容易混乱,所以我们总结下面几条:

  1. f.seek(0)是将读写光标都移到第1个字符的位置

  2. 如果做了f.read()操作,甚至是做了f.readline()操作,写光标都会跑到最后

  3. 如果做了f.write()操作,也会影响读光标

==所以建议在做读写切换时使用类似f.seek(0)和类似f.seek(f.tell())这种来确认一下位置,再做切换操作==

二进制相关模式(拓展)

二进制模式用于网络传输等相关的情况

示例: 二进制读模式

f = open("/tmp/2.txt", "rb")

print(f.readline())
print(f.readline())

f.close()

示例: 二进制写模式

f = open("/tmp/2.txt", "wb")
f.write("hello word".encode())	# 需要encode才能成功写进去

f.close()

课后示例与练习

示例: 文件的字符串全替换(拓展)

两个文件, 一个读,另一个替换完后写,最后再覆盖回来

import os
f1 = open("/tmp/1.txt", 'r')
f2 = open("/tmp/2.txt", 'w')

oldstr = input('old string:')
newstr = input('new string:')

for i in f1:
	if oldstr in i:
        i = i.replace(oldstr,newstr)
    f2.write(i)

os.remove("/tmp/1.txt")
os.rename("/tmp/2.txt","/tmp/1.txt")

f1.close()
f2.close()

**练习:(有难度,想挑战的可以尝试) **

以下面字典中的数据,评选最佳group,最佳class和teacher

info={
    "group1":{
        "class1":["李老师","班级平均成绩85"],
        "class2":["张老师","班级平均成绩89"],
    },
    "group2": {
        "class3": ["王老师", "班级平均成绩78"],
        "class4": ["赵老师", "班级平均成绩91"],
    },
    "group3": {
        "class5": ["马老师", "班级平均成绩82"],
        "class6": ["陈老师", "班级平均成绩79"],
    },
    "group4": {
        "class7": ["钱老师", "班级平均成绩90"],
        "class8": ["孙老师", "班级平均成绩80"],
    },
}
答案:

练习: (有难度,想挑战的可以尝试)

找出同时选修了任意1种课程的人,任意2种课程的人,任意3种课程的人,任意4种课程的人

math = ["张三", "田七", "李四", "马六"]
english = ["李四", "王五", "田七", "陈八"]
art = ["陈八", "张三", "田七", "赵九"]
music = ["李四", "田七", "马六", "赵九"]


示例: 打印一个文件的前5行,并打印行号(不是下标)

f = open("/tmp/1.txt", "r")

for index, line in enumerate(f):
    if index < 5:
        print(index+1, line.strip())
 
f.close()

练习: 打印一个文件的3到7行,并打印行号

练习: 打印一个文件的奇数行,并打印行号

练习: 打印一个文件所有行,但把第2行内容替换成hello world(不能替换原文件,打印出的结果替换就可以)

练习: 通过/proc/cpuinfo得到cpu核数(processor 0代表第一个核,processor 1代表第二个核,以此类推)

只写模式(w)

**示例: **

f = open("/tmp/1.txt",'w')      # 只写模式(不能读),文件不存在则创建新文件,如果文件存在,则会复盖原内容(千W要小心)
data = f.read()  				# 只写模式,读会报错

f.close()

示例: 创建新文件,并写入内容

f = open("/tmp/2.txt", 'w')	# 文件不存在,会帮你创建(类似shell里的 > 符号)

f.write("hello\n")			# 不加\n,默认不换行写
f.write("world\n")
f.truncate()				# 截断,括号里没有数字,那么就是不删除
f.truncate(3)				# 截断,数字为3,就是保留前3个字节
f.truncate(0)				# 截断,数字为0,就是全删除
 
f.close()

练习: 配置本地yum

f = open("/etc/yum.repos.d/local.repo", mode="w")

f.write("[local]\n")
f.write("name=local\n")
f.write("baseurl=file:///mnt\n")
f.write("enabled=1\n")
f.write("gpgcheck=0\n")

f.close()
f = open("/etc/yum.repos.d/local.repo", mode="w")

f.write('''[enable]
name=local
baseurl=file:///mnt
gpgcheck=0
enabled=1
''')

f.close()
f = open("/etc/yum.repos.d/local.repo", mode="w")

f.write("[enable]\n"
        "name=local\n"
        "baseurl=file:///mnt\n"
        "gpgcheck=0\n"
        "enabled=1\n")

f.close()
f = open("/etc/yum.repos.d/local.repo", mode="w")

f.write("[enable]\nname=local\nbaseurl=file:///mnt\ngpgcheck=0\nenabled=1\n")

f.close()

练习: 把九九乘法表直接写到一个文件里

f = open("/tmp/3.txt", mode="w")

for i in range(1, 10):
    for j in range(1, i+1):
        f.write("{}*{}={}\t".format(j, i, i*j))
    f.write("\n")

f.close()

追加模式(a)

示例:

f = open("/tmp/2.txt", 'a')	# 类似shell里的>>符

f.write("hello\n")	
f.write("world\n")
f.truncate(0)				# 追加模式也可以使用truncate截取前面的数据

f.close()

小结:

r: 只读模式 文件必须要存在;

w: 只写模式 文件存在则会清空原文件内容再写,不存在则会创建文件再写

a: 追加模式 与w模式的区别为a模式不清空原文件内容,在最后追加写

比较r+,w+,a+三种模式(拓展)

r+文件必须要存在,相当于在只读模式的基础上加了写权限;

w+会清空原文件的数据,相当于在只写模式的基础上加了读权限;(可以在任意位置写,但要用seek定位光标,还要区分读光标和写光标)

a+不会改变原文件的数据,相当于在只追加模式的基础上加了读权限;(写是在最后写,即使用seek把光标移到前面,仍然会写在最后)

r+,w+,a+混合读写深入理解(拓展)

**示例: **

f = open("/tmp/2.txt", "w+")

f.write("11111\n")
f.write("22222\n")
f.write("33333\n")

print(f.tell())			# 打印结果为18,表示光标在文件最后

f.write("aaa")			# 这样写aaa,相当于在文件最后追加了aaa三个字符

f.seek(0)				# 表示把光标移到0(也就是第1个字符)
f.write("bbb")			# f.seek(0)之后再写bbb,就是把第一行前3个字符替换成了bbb

f.seek(0)				# 把光标再次移到0
f.readline()			# 把光标移到第1行最后
f.seek(f.tell())		# f.seek到第1行最后(如果这里理解为两个光标的话,你可以看作是把写光标同步到读光标的位置)
f.write("ccc")			# 这样写ccc,就会把第二行的前3个字符替换成ccc

f.close()

练习: 往一个新文件里写九九乘法表,并直接读出结果

f = open("/tmp/4.txt", "w+")

for i in range(1, 10):
    for j in range(1, i+1):
        f.write("{}*{}={} ".format(i, j, i*j))
    f.write("\n")

f.seek(0)						# 这里需要seek(0),否则读不出来
data1 = f.read()

f.close()
print(data1)

总结:

r+,w+,a+这三种模式因为涉及到读与写两个操作,你可以使用两个光标来理解,但这样的话读光标与写光标会容易混乱,所以我们总结下面几条:

  1. f.seek(0)是将读写光标都移到第1个字符的位置

  2. 如果做了f.read()操作,甚至是做了f.readline()操作,写光标都会跑到最后

  3. 如果做了f.write()操作,也会影响读光标

==所以建议在做读写切换时使用类似f.seek(0)和类似f.seek(f.tell())这种来确认一下位置,再做切换操作==

二进制相关模式(拓展)

二进制模式用于网络传输等相关的情况

示例: 二进制读模式

f = open("/tmp/2.txt", "rb")

print(f.readline())
print(f.readline())

f.close()

示例: 二进制写模式

f = open("/tmp/2.txt", "wb")
f.write("hello word".encode())	# 需要encode才能成功写进去

f.close()

十六、函数

使用函数的优点: 功能模块化,代码重用(编写的代码可以重复调用)

回顾下shell里的函数

# service sshd start
# /etc/init.d/sshd start
在centos6里,上面两条命令里的start都是最终调用/etc/init.d/sshd服务脚本里的start()函数
function start() {							# 定义函数名start,前面可以加function也可以不加
	/usr/sbin/sshd
}

stop() {
	kill -15 `cat /var/run/sshd/sshd.pid`
}

reload() {
	kill -1 `cat /var/run/sshd/sshd.pid`
}

restart() {
    stop
    start									# 函数里调函数就是函数的嵌套	
}

case "$1" in
	start )
		start								# 调用start函数
		;;
	stop )
		stop
		;;
	restart )
		restart
		;;
	reload )
		reload
		;;
	* )
		echo "参数错误"
esac

python里的函数

python里函数分为内置函数自定义函数

内置函数: 如int(), str(), len(), range(), id(), max(), print()等,所有的内置函数参考

https://docs.python.org/3/library/functions.html

自定义函数的定义与调用(重点)

Python 使用 def 开始函数定义,紧接着是函数名,括号内部为函数的参数,内部为函数的 具体功能实现代码,如果想要函数有返回值, 在 expressions 中的逻辑代码中用 return 返回

def funct1():				  # 函数名(),括号里可以写参数,也可以不写
    """函数说明或注释"""		 # 说明可以不写,大型程序为了程序可读性最好写
    print("进水")				# 函数代码主体
    print("洗衣服")		   # 函数代码主体
    print("脱水")				# 函数代码主体
    return 0				  # 函数返回值,可有可无


funct1()				 	# 调用函数的方式(调用函数也就是执行函数内部的代码)

函数传参数(重点)

为什么要传参?

答: 把自动洗衣机比喻成生活中的函数,我们不同的使用者也要告诉洗衣机加多少水,放什么衣服,洗衣的模式,脱水多久等,这些都可以看作是给洗衣机传参。

同样,给空调调模式和温度,给电视调频道与音量都可以看作是传参。

def test(a, b, c):                		# 定义函数,传3个参数,分别为a,b,c
    print("进水{}升".format(a))			# 调用a的值
    print("洗{}".format(b))				 # 调用b的值	
    print("脱水{}分钟".format(c))          # 调用c的值

test(3, "毛衣", 10)                    # 将值3赋值给a变量,值"毛衣"赋值给b变量,值10赋值给c变量

示例: 形参,实参,位置参数,关键字参数

def test(a, b):		# a,b是形参(形式上的参数,就是占位置用的)
    print(a + b)

    
test(1, 2)			# 1,2在这里是实参(实际的参数),实参也可以传变量,个数要与形参个数对应,也会按顺序来传参(位置参数);
# test(1)			# 执行的话会报错,位置参数要与形参一一对应,个数不能少
# test(1, 2, 3)		# 执行的话会报错,位置参数要与形参一一对应,个数也不能多
test(b=4, a=3)		# 这里是关键字调用,那么就与顺序无关了(关键字参数)

# test(5, b=6)		# 混用的话,就比较怪了,结果可以自行测试一下(结论:位置参数必须写在关键字参数的前面)

示例: 默认参数或者叫默认值参数

def connect_mysql(host, user, password, port=3306):	# port=3306为默认参数
    pass							# pass就类似一个占位符,保证函数完整,没有语法错误


host = input("input host:")
user = input("input user:")
password = input("password")

connect_mysql(host, user, password)			# 不用再传port的值的,默认就是3306;也可以传一个新的值替代3306
def ssh(ip, port=22):
    print("ssh {} -p {}".format(ip, port))

ssh("10.1.1.15", 2222)

一句话小结: 默认值参数就是不传值就用默认的,传了值就用传的值。

示例:可变长参数

def funct1(*args):		# 参数名前面加*(变量名可以自定义)就可以定义为可变长参数
    for i in args:
        print(i, end=" ")
    print()

    
funct1(1, 2, 3, 4, 5, 6, 7, 8)
定义一个函数,传多个整数,实现求和
def add_num(*args):
    sum = 0
    for i in args:
        sum += i
    print(sum)

    
add_num(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

小结:

形参,实参,位置参数,关键字参数,默认值参数,可变长参数

示例: 多个关键字参数转字典(拓展)

def test(**kwargs):			# **两个后面加变量(变量名可以自定义),这样后面传多个值(需要传关键字参数),并且结果为字典
    print(kwargs)

    
test(name="zhangsan", age=18, gender="M")

def people(name, *args, age=18, **kwargs):
    print(name)
    print(args)
    print(age)
    print(kwargs)

    
people("zhangsan", "man", 25, salary=20000, department="IT")
people("zhangsan", "man", 180, age=25, salary=20000, department="IT")
people("zhangsan", "man", 180, 25, salary=20000, department="IT")

函数返回值(重点)

函数的功能要专一, 一个函数只完成一个功能。

理解函数返回值的作用: ==把函数的执行结果返回给需要调用的地方==

函数return返回的是一个==值==,所以要赋值给一个变量,然后通过调用变量得到返回值。

函数返回值写在函数体的最后,因为函数返回值意味着函数的结束。

示例:

def test(a, b):
    c = a + b
    return c
	print("haha")	# 返回值后面的代码不执行,也就是说函数执行到return就结束了

test(1, 2)		# 再回顾一下,这是函数的调用,执行函数体内的代码,但这样得不到函数返回值

d = test(1, 2)
print(d)			# 这样终于得到函数的返回值了

print(test(1,2))	# 不赋值给变量,直接打印也是可以得到函数的返回值

比较下面两段(目前看不出来返回值的优势)

def test1(a, b):
    print(a + b)


def test2(a ,b):
    c = a + b
    return c

test1(1, 2)

print(test2(2, 3))

嵌套函数(了解)

还记得前面的if,while,for嵌套吗?再总结一下: if,while,for,函数都可以嵌套,也可以互相嵌套。

请问: 下面的两段代码结果是否一样?

def aaa():
    print("aaa")
def bbb():
    print("bbb")
    aaa()
bbb()


def bbb():
    print("bbb")
    aaa()
def aaa():
    print("aaa")
bbb()

请问: 下面的代码有没有问题

def bbb():
    print("bbb")
    aaa()
bbb()
def aaa():
    print("aaa")

请问:下面的代码能看明白吗? 并想想return能不能换成print直接打印?

def max_num2(a, b):
    if a > b:
        return a
    else:
        return b
    
def max_num3(n1, n2, n3):
    aaa = max_num2(n1, n2)
    bbb = max_num2(aaa, n3)
    return bbb

print(max_num3(1, 2, 3))

函数的变量作用域: 全局变量,局部变量

示例:

name = "zhangsan"   	# 全局变量

def change_name():
    name = "lisi"	# 这个变量只能在函数内生效,也就是局部变量(可以说这个函数就是这个变量的作用域)
    gender = "male"

    
change_name()		
print(name)			# 结果为zhangsan
print(gender)		# 这句会报错,因为它是局部变量,在外面调用不了

示例:

name = "zhangsan"   	# 全局变量

def change_name():
    global name,gender     # 这句可以把name改为全局变量,但不建议这样用,如果多次调用函数,这样很容易混乱,容易与外部的变量冲突
    name = "lisi"
    gender = "male"
    print(name)

    
change_name()		# 这句结果为lisi,调用函数内部的print(name)得到的结果
print(name)			# 这句结果为lisi
print(gender)		# 可以调用gender变量了,能打印出结果

递归函数(拓展)

函数可以调用其它函数,也可以调用自己;如果一个函数自己调用自己,就是递归函数,但递归也有次数上限(保护机制),所以递归需要有一个结束条件

在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出

示例: 下面代码就可以看到最高可以递归近1000次

def plus_one(n):
    print(n)
    return plus_one(n+1)


plus_one(0)

示例:

def abc(n):
    print(n)
    if n//2 > 0:
        return abc(n//2)

    
abc(100)

匿名函数(拓展)

python 使用 lambda 来创建匿名函数。

所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。

lambda 只是一个表达式,函数体比 def 简单很多。

lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。

lambda 函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。

示例: 比较下面的两段

# 自定义函数
def caclulate(a, b):
	print(a + b)

    
caclulate(2, 5)

# 匿名函数
caclulate = lambda a,b:a+b

print(caclulate(2, 5))

列表推导式(拓展)

匿名函数常用于写有行为的列表或字典,按照要求执行相应的动作

示例:把一个列表的值x2

# 方法一:
list1=[1,2,3,4,5]

list2=[]
for i in list1:
    i*=2
    list2.append(i)

print(list2)

# 方法二:
list1=[1,2,3,4,5]

for i,j in enumerate(list1):
    j=j*2
    list1[i]=j

print(list1)

# 方法三:列表推导式
list1=[i*2 for i in range(1,6)]
print(list1)

list2=list(map(lambda i:i+1,list1))
print(list2)

高阶函数(拓展)

高阶函数特点:

  • 把函数名当做实参传给另外一个函数(变量可以传参,函数就是变量,所以函数也可以传参)
  • 返回值中包含函数名

示例:普通的函数,里面会用到abs这种内置函数来做运算

def higher_funct1(a,b):
        print(abs(a)+abs(b))

higher_funct1(-3,-5)

示例: 高阶函数,像abs(),len(),sum()这些函数都当做了实参传给了另外一个函数

def higher_funct1(a,b,c):
        print(c(a)+c(b))

higher_funct1(-3,-5,abs)
higher_funct1("hello","world",len)
higher_funct1([1,2,3],[4,5,6],sum)

def higher_funct1(a,b,c):
		return c(a)+c(b)

print(higher_funct1(-3,-5,abs))
print(higher_funct1("hello","world",len))
print(higher_funct1([1,2,3],[4,5,6],sum))

装饰器(拓展)

装饰器(语法糖) 用于装饰其他函数(相当于是为其他函数提供附加功能)

不能去修改被装饰的函数的源代码和调用方式(如果业务已经线上运行,现在想新加一个功能,改源代码就会产生影响)

示例:

假设我的程序假设有三个复杂函数逻辑

import time

def complex_funct1():
    time.sleep(2)
    print("哈哈,我不复杂!")

def complex_funct2():
    time.sleep(3)
    print("哈哈,我也不复杂!")

def complex_funct3():
    time.sleep(4)
    print("哈哈,我还是不复杂!")

complex_funct1()
complex_funct2()
complex_funct3()

假设我现在想加一个计算复杂函数时间的功能,下面的做法太麻烦,一个个的加,并且还修改了原函数的代码

import time

def complex_funct1():
    start_time=time.time()
    time.sleep(2)
    print("哈哈,我不复杂!")
    end_time=time.time()
    print("此函数一共费时{}".format(end_time-start_time))

def complex_funct2():
    start_time=time.time()
    time.sleep(3)
    print("哈哈,我也不复杂!")
    end_time=time.time()
    print("此函数一共费时{}".format(end_time-start_time))

def complex_funct3():
    start_time = time.time()
    time.sleep(4)
    print("哈哈,我还是不复杂!")
    end_time=time.time()
    print("此函数一共费时{}".format(end_time-start_time))

complex_funct1()
complex_funct2()
complex_funct3()

我这里把计算时间的功能定义成一个函数,把被计算的复杂函数当做参数传进来进行计算(高阶函数),但后面的函数调用方式却需要改变

import time

def timer(funct):
    start_time=time.time()
    funct()				# 这里funct后面不接()也可以,但下面的调用里就要写,比如timer(complex_funct1())
    end_time=time.time()
    print("此函数一共费时{}".format(end_time - start_time))

def complex_funct1():
    time.sleep(2)
    print("哈哈,我不复杂!")

def complex_funct2():
    time.sleep(3)
    print("哈哈,我也不复杂!")

def complex_funct3():
    time.sleep(4)
    print("哈哈,我还是不复杂!")
timer(complex_funct1)
timer(complex_funct2)
timer(complex_funct3)			# 这里改变了原有的调用方式

高阶函数+嵌套函数=装饰器,实现不修改原函数代码,也不改变原函数调用方式,就可以加上新功能

def timer(funct):			# 把下面的多个复杂函数当做参数传给这个timer计时函数(高阶函数)
    def timer_proc():			# 函数里调函数(嵌套函数)
        start_time=time.time()
        funct()				# 执行调用的复杂函数(如complex_funct1()等),函数的过程会消耗一定的时间
        end_time=time.time()
        print("此函数一共费时{}".format(end_time - start_time))	# 算出时间,也就是我们最终需要的结果,但写在里面这样并不能打印出来,需要在外函数作为返回值
    return timer_proc			# 把嵌套内部函数的值在外面作为返回值,这样就可以被显示

@timer							# 相当于timer(complex_funct1)
def complex_funct1():
    time.sleep(2)
    print("哈哈,我不复杂!")

@timer							# 相当于timer(complex_funct2)
def complex_funct2():
    time.sleep(3)
    print("哈哈,我也不复杂!")

@timer							# 相当于timer(complex_funct3)
def complex_funct3():
    time.sleep(4)
    print("哈哈,我还是不复杂!")


complex_funct1()
complex_funct2()
complex_funct3()			# 没有改变最原始的函数调用方式就能实现需求

十七、模块

模块的定义,分类,存放路径

==模块就是一个.py结尾的python代码文件==(文件名为hello.py,则模块名为hello), 用于实现一个或多个功能(变量,函数,类等)

模块分为

  1. 标准库(python自带的模块,可以直接调用)
  2. 开源模块(第三方模块,需要先pip安装,再调用)
  3. 自定义模块(自己定义的模块)

模块主要存放在/usr/local/lib/python3.6/目录下,还有其它目录下。使用sys.path查看。

# python3.6
>>> import sys
>>> print(sys.path)		# 模块路径列表,第一个值为空代码当前目录
['', '/usr/local/lib/python36.zip', '/usr/local/lib/python3.6', '/usr/local/lib/python3.6/lib-dynload', '/root/.local/lib/python3.6/site-packages', '/usr/local/lib/python3.6/site-packages']
# sys.path和linux上的$PATH很类似,如果两个目录里分别有同名模块,则按顺序来调用目录靠前的。
# sys.path的结果是一个列表,所以你可以使用sys.path.append()或sys.path.insert()增加新的模块目录。

示例: 手动在当前目录下(pycharm当前项目目录)写一个简单模块(名为hello.py)

如果你命名为os.py这种就坑了,原因是什么?

def funct1():
    print("funct1")
    
def funct2():
    print("funct2")

def funct3():
    return "funct3"

if __name__ == "__main__":
    print("haha")		# 直接执行hello.py文件会执行这段代码 
else:
    print("hehe")		# 当hello.py以模块形式被调用时执行这段代码

示例:与上面的hello.py同目录下,再写一个1.py来调用hello.py

import hello		# 调用同目录的hello模块

hello.funct1()		# 可以调用hello模块里的funct1()函数
hello.funct2()		# 可以调用hello模块里的funct2()函数
print(hello.funct3()) # 调用hello模块里的funct3()函数,因为结果为函数返回值,所以还需要print打印

模块的基本导入语法

import导入方法相当于是直接解释模块文件

import导入单模块

import hello

import导入多模块

import module1,module2,module3
import module1
import module2
import module3

from导入模块里所有的变量,函数

from hello import *

from导入模块文件里的部分函数

from hello import funct1,funct2

import语法导入与from语法导入的区别

import导入方法相当于是直接解释模块文件

像from这样的语法导入,相当于是把hello.py里的文件直接复制过来,调用hello.py里的funct1()的话,就不需要hello.funct1()了,而是直接funct1()调用了,如果你本地代码里也有funct1(),就会冲突,后面的会overwrite前面的

# 代码一:
import hello
hello.funct1()			# 前面要接模块名

# 代码二:
from hello import *
funct1()				# 前面不用模块名了

# 代码三:
import hello
def funct1():
    print("local funct1")	
    
hello.funct1()			# 调用模块里的funct1
funct1()				# 调用本地的funct1

# 代码四:
from hello import *
def funct1():
    print("local funct1")
    
#hello.funct1()			# hello模块里的funct1与本地的funct1冲突了
funct1()				# 得到的是本地的funct1结果

为了区分本地funct1和导入的hello模块里的funct1,可以导入时做别名

from hello import funct1 as funct1_hello

示例: 利用别名来解决模块与本地函数冲突的问题

from hello import funct1 as funct1_hello

def funct1():
   print("local funct1")

funct1_hello()		# 用别名来调用hello模块里的funct1
funct1()			# 本地的funct1

问题: 比较了半天,import又方便也没使用问题,为什么还要有from这种导入方式呢? 因为是: 为了优化

import hello
hello.funct1()    # 如果本文件有大量的地方需要这样调用,那么也就是说需要大量重复找hello模块里的funct1函数

from hello import funct1
funct1()      	  # 如果本文件有大量的地方需要这样调用,这样就不用大量重复查找hello模块了,因为上面的导入就相当于把funct1的函数代码定义到本文件了;而且这样导入方式可以选择性的导入部分函数。

包(拓展)

包(Package)是用来逻辑上组织多个模块,其实就是一个目录,目录里必须有一个__init__.py文件(导入一个包就是执行包下的__init__.py文件

1542792471040

1542792646331

1542793157401

1542793229015

1542793382389

1542793474906

动物装饰