Python基础---从hello world到面向对象

python基础

python简介

python是一个高层次的结合了解释性、编译型、互动性和面向对象型的脚本语言。

解析型语言意味着python没有了像C语言编译这样的环节。类似于php

交互式语言意味着可以在一个python提示符>>>下执行代码。

面向对象语言意味着支持python支持面向对象将代码封装在对象的编程技术。

python是初学编程者最合适的语言,他是伟大的,既支持应用开发,从简单的文字处理到www浏览器到游戏。

python环境

python支持Windows、Linux、Mac多种平台。

通过终端窗口输入python就可以查看本机是否安装了python

windows安装python

下载python

python官网:https://www.python.org/downloads/windows/

下载合适的版本即可

配置环境变量

安装pycharm

pycharm是一个专业的python开发环境软件,当然可以使用其他的环境。

pycharm官网:

https://www.jetbrains.com/pycharm/download/#section=windows

安装完成后,可以进入终端输入python进入>>>然后输入print('hello world')

实现学习python的第一行代码

Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> print('hello world')
hello world
>>>

python中文编码

前面我们已经学会hello world,但是如果你输入你好,世界python可能就会报错,是因为python编码的问题。

python2默认编码是ascii,没有修改编码的时候python无法读取汉字,所以读取中文会报错。

只需要在python文件开头加入,# -*- encoding: UTF-8 -*-或者# encoding=utf-8即可。

如果使用的是python3环境,python3中默认使用的就是utf-8编码,就不会报错。

python基础语法

交互式编程

交互式编程不需要创建文件,只需要在python解释器中进行编写代码

只需要在终端中输入python就可以进入交互式终端,进入后会类似如下代码:

Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>

只需要在终端中输入print('hello world')然后回车就可以执行代码

>>> print('hello world')
hello world

脚本式编程

脚本式需要创建一个文件,然后后缀名以.py结尾。这里我创建一个test.py

下方代码是test.py内容

print('hello world')

如果这里环境变量配置正确,进入创建文件的目录,打开终端输入

python test.py,就可以指定代码

D:\>python test.py
hello world

python2python3的兼容性

如果python2想要使用python3print,可以导入__future__模块

form __future__ import print.funcation
print('hello world')
# 可以在python2中正常运行

python标识符

python,标识符由字母、数字、下划线组成

在python中,所有的标识符可以包括英文、数字、下划线但是不能使用数字开头。

python可以同一行执行多条代码,必须使用;隔开

Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> print('hello world');print('nihao')
hello world
nihao

python变量类型

变量是存储在内存中的,这就意味着在创建变量的时候会在内存中开辟一个空间。

变量可以指定不同的数据类型,可以存储整数、小数或字符

基于变量的类型,解释器会分配指定内存,并决定那些数据是可以存储在内存中。

变量赋值

python中的变量不需要声明数据类型

每个变量在进行创建时,都包括变量的标识,名称和数据。

每个变量都需要进行赋值,只有赋值后变量才会进行创建。

等号=用来给变量赋值。

格式为:变量名 = 值,也就是等号左边的为变量名,右边的为赋给变量的值。

实例:

name = "Jungle"
print(name)

# 结果输入 Jungle

多个变量赋值

如果多个变量需要使用相同的值

a = b = c = 1

根据变量赋值格式:变量名 = 值,首先1赋值给c,然后c的值就是1,然后将c赋值为b,所有b也是1,那么a也同理。

如果多个变量不同的值

a,b,c = 'lql','zt','zmz'

格式为:变量1,变量2,变量3,变量... = 'aaa','bbb','ccc'....

同样左边的为变量名,然后不同的变量名通过,逗号隔开,然后等号右边的不同变量的值也通过,逗号隔开,第一个值就赋值给第一个变量,第二个赋值给第二个变量....

标准数据类型

上述说到,在内存中存储的数据可以有多种数据类型。

例如:一个人的名字可以使用字符串来表示,而一个人的年龄可以用数字来表示

Python定义了一些标准的数据类型,用于在内存中存储各种数据类型,如下:

  • Nubmer(数字)
  • String(字符串)
  • List(列表)
  • Tunple(元组)
  • Dictionary(字典)

python数字

数字数据类型用于存储数值。

他们是不可改变的数据类型,这意味着改变数字数据类型会分配一个新的对象。

当你指定一个数字值时,数字类型就会被创建,例如:

num1 = 1
num2 = 11

可以使用del删除声明的变量。

del num1
del num1,num2

python中支持四种不同的数字类型

  • int(整形)
  • long(长整型,可以代表八进制和十六进制)需要注意是的在python3中long已经被int类型代替
  • float(浮点型)
  • complex(复数型)

下列举例一些常见的数据,以及数据类型的分类

类型 特点
0,1,5,7,10,-1,10 整形(int) 由整数组成
0.1,0.5,0.00001,-1.1 浮点型(float) 只有一个点
12 + 02.j 复数型(complex) 复数的特点呗

python字符串

字符串(strings)是有数字、字母和特殊字符组成。最常用到的数据类型,常用于表示文本。

表现形式:变量名 = "值",值通过单引号、双引号包裹。例如:

str1 = 'love'
str2 = "LQL"

字符串也可以视为列表,可以进行下标取值。其中取值有两种方法

例如字符串有有三位,为LQL

L Q L
方法1 0 1 2
方法2 -3 -2 -1

可以使用这两种方式进行取值。格式为:变量名[下标]

str1 = "love"
print(str1[0])	# 值是l
print(str1[1])	# 值是o

# 第二种方法
print(str1[-2])	# 值是v
print(str1[-1]) # 值是e

如果要实现取出一段数据的方法,可以使用切片的方法

格式:[开始下标:结束下标]

# coding=utf-8
str1 = "love 191"
print(str1[0:3])	# 值是lov
# 0 对应的是 l
# 3 对应的是 e
# 根据结果可以看出这个区间取值的方法包含开始不包含结束
print(str1[-3:-1])	# 值是 19

# 当取值中开始下标或者结束下标为空的时候,会直接定位最开始或最后
print(str1[0:])		# 值是 love 191
print(str1[:-4])	# 值是 love

字符串中之间使用+代表字符串的拼接,*代表重复次数

print("I" + "love" + "you")
# 输入 Iloveyou
print("I love you , 191" * 521)
# 输出 I love you , 191 一共 521次

python列表

列表也是python中经常使用的数据类型。

列表可以完成多种数据的集合。它支持字符、数字、字符串,甚至包含列表(嵌套)

列表使用[]标识,其中每个值使用,逗号隔开。

列表获取数据和刚刚讲的字符串获取数据一样的,通过下标切片。例如:

list1 = ['Junglezt','Jackson','Bob']
list2 = ['www']

# 下标获取
print(list1[1])      # 返回 Jackson
print(list1[-1])     # 返回 Bob

# 切片
print(list1[1:3])    # 返回 ['Jackson', 'Bob']
print(list1[2:])     # 返回 ['Bob']
print(list1 + list2) # ['Junglezt', 'Jackson', 'Bob', 'www']
print(list1 * 2) # ['Junglezt', 'Jackson', 'Bob', 'Junglezt', 'Jackson', 'Bob']

python元组

元组是另一个数据类型,类似于list列表

元组用()标识,中间使用,逗号隔开。但是元组不可以进行二次赋值,相当于只读列表。


tunple1 = ('test','aaa','bbb','ccc')
tunple2 = ('baidu','com')

print(tunple1[3])   # 返回 ccc
print(tunple2[1])   # 返回 com
print(tunple1[0:2]) # 返回 ('test', 'aaa')
print(tunple1 + tunple2) # 返回 ('test', 'aaa', 'bbb', 'ccc', 'baidu', 'com')
print(tunple2 * 2)  # 返回 ('baidu', 'com', 'baidu', 'com')

上述说到,元组是不可改变的,列表是可以的,所以再次给元组赋值时会报错。

实例:

list1 = ['aaa','bbb','ccc']
tunple1 = ('test','aaa','bbb')
# 更改列表的值
list1[0] = "你好"
print(tunple1)
print(list1)

# 更改元组的值
tunple1[1] = '你好'

返回结果,可以看到报错了。

Traceback (most recent call last):
  File "test.py", line 10, in <module>
    tunple[1] = '你好'
TypeError: 'tuple' object does not support item assignment
('test', 'aaa', 'bbb')
['你好', 'bbb', 'ccc']

python字典

字典(dictionary)使除了列表以外最灵活的数据类型。列表是有序的集合,而字典是无序的。

与列表不同的字典通过键名来获取。字典的标识是{},字典中的值是有键名键值组成,其中一个键名对应一个键值,若需要更多的值使用,逗号隔开,继续下一个值。

格式为:{'键名1':'键值1',"键名2":"键值2"}。实例:

dict = {}
dict['first'] = 'hello'
dict[2] = 'world'
test_dict = {"name":"Junglezt","age":"18"}

print(dict['first'])            # 打印 hello
print(dict[2])                  # 打印 wrold
print(test_dict)                # 打印列表
print(test_dict.keys())         # 获取所有key
print(test_dict.values())       # 获取所有值

返回结果

hello
world
{'name': 'Junglezt', 'age': '18'}
dict_keys(['name', 'age'])
dict_values(['Junglezt', '18'])

python数据类型转换

一些情况,我们需要对数据的类型转换,方便我们处理。

数据类型的转换的函数名很简单容易记住,就是我们要转换为的数据类型的名称。

例如我们要转换为列表类型,就是list转换为列表类型的函数就是list()

大部分是这样的,常见的数据类型转换的函数如下:

方法 作用
int() 转换为数字类型整形
float() 转换为数字类型浮点型
cpmplex() 转换为一个复数型,或者可以说创建一个复数
str() 转换为字符串类型
repr() 将对象转换为字符串
tunple() 转换为一个元组
list() 转换为一个列表
dict() 转化为一个字典,条件是必须满足key:value的条件
chr() ascii值转换为对应的字符
ord() 将字符转换为ascii
bin() 将数字转换为二进制
oct() 将数字转换为八进制
hex() 将数字转换为十六进制

这里不在一一举例。

python运算符

python中支持多种多样的运算符,什么是运算符,1+2=3这可以称为一个算数运算,4和5是运算的字符,+被称为算数运算符。

python支持以下几种运算符

算数运算符、比较运算符、赋值运算符、逻辑运算符、位运算符、成员运算符、身份运算符、运算符优先级

看样子很多运算符,很难?这怎么可能?那就让我来逐步击破吧

算符运算符

算数运算符是最简单的,就和数学是一样的,不过有一些特殊的算法。

python支持以下的运算符

运算符 作用 实例
+ 加法运算 1 + 2 = 3
- 减法运算 5 - 3 = 2
* 乘法运算 3 * 2 = 6
/ 除法运算,结果为浮点数 10 / 2 = 5.0
% 取余运算,得到余数 20 % 8 = 4
** 幂运算,几次方 2 ** 3 = 8
// 整除运算,得到结果的整数位 7 // 3 = 2

上述的大多数运算符只能对数字数据类型使用,特殊的+、*可以对其他的数据类型使用,在字符串和列表中+代表拼接的意思,*代表重复次数的意思。

eval()函数

python中为算符运算符提供了一个遍历的函数eval(),他的功能类似于计算器,能将输入的公式进行计算。

print(eval("1 + 2 * 3 / 4 * 5"))
# 返回 8.5

当然计算只是eval()函数的其中一个功能,在使用eval()函数的使用,移动要谨慎使用,最好不要吧input()动态传输的参数传入到eval()函数,因为该函数也可以执行系统内置函数和方法。

# 可以使用__import__('模块名')导入模块
# 其中os模块下的system方法可以执行系统命令

print(eval("__import__('os').system('dir')"))

可以执行系统命令

比较运算符

大于,小于,等于就是这样

比较运算符返回的结果只有,TrueFalse正确错误

对了,需要注意的是如果比较两个值是否相等,使用的是双等号==,因为单个等于号是=赋值的意思,或许会详细讲到。

运算符 作用 实例
== 等于 1 == 1 (True)
!= 不等于 1 != 2 (True)
<> 不等于,python3已经弃用 1 <> 3 (True)
> 大于 3 > 2 (True)
< 小于 1 < 5 (True)
>= 大于等于 5 > 4 (True)
5 >= 5 (True)
<= 小于等于 8 < 9 (True)
8 <= 8 (True)

上述也是只对于数字的比较,字符串也是可以进行比较的,只不过比较的是他的ascii值,使用chr()ord()可以快速转换字符串ascii

例如:aascii值是97bascii值是98,所以在比较字符串'a' > 'b'的时候,返回的结果是False

# 查看a和b的ascii值
print(ord('a'),ord('b'))    # 返回 97 98
print(chr(97),chr(98))      # 返回 a b

# 比较 a 和 b
print('a' > 'b')    # False
print('a' < 'b')    # True

赋值运算符

上述我们已经使用过了变量的赋值=运算符,这里介绍更多的赋值运算符

只有=赋值运算使用最多,其他的大概了解即可。

运算符 作用
= 简单的赋值运算
+= 加法赋值运算,a += c 就是 a = a + c
-= 减法赋值运算,a -= c 就是 a = a - c
*= 乘法赋值运算,a *= c 就是 a = a * c
/= 除法赋值运算, a /= c 就是 a = a / c
%= 取余赋值预算, a %= c 就是 a = a % c
**= 幂赋值运算, a **= c 就是 a = a ** c
//= 取整赋值运算, a //= c 就是 a = a // c

可能理解着有点别扭,看一下实例:

# 简单的赋值运算
a = 5

# 加法赋值运算
a = 2
b = 3
a += b  # 就是 a = a + b,也就是 2 + 3 = 5
print(a)    # 返回结果是 5

# 减法赋值运算
aa = 111
bb = 55
aa -= bb    # 就是 aa = aa - bb,也就是 111 - 55 = 56
print(aa)   # 返回结果是 56
# 或许的类似,不在叙述

位运算

位运算是相对于数字的二进制值进行预算。

先不说位运算,这里叙述一下Python中的二进制、八进制、十六进制,他们的表现形式为

进制 表述形式
二进制 0b开头
八进制 0o开头
十六进制 0x开头
print(0b10)     # 返回 2
print(0o10)     # 返回 8
print(0x10)     # 返回 16

我们通常使用的进制为十进制,就是逢十进一,例如0,1,2,3,4,5,6,7,8,9到了10就需要进一位,而二进制是逢二进一,八进制就是逢七进一,十六进制就是逢十六进一

反码、补码

计算机在平常我们使用算数运算的时候,其实使用的就是二进制运算,输入的值都会别识别为二进制然后进行运算

这里我们来看一下5-5的运算


# 5 和 -5 相加的二进制原理
a = 5
b = -5
# 首先 5 和 -5 转换为二进制
# 5 二进制   b0000 0101
# 在进行二进制运算时,最高位为符号位,0代表正数,1代表负数
# -5 二进制  b1000 0101

# 负数在进行运算时需要执行 反码 和 补码 两个过程
# 反码 : 符号位不变,其余取反,就是1变0,0变1
# 补码 : 在反码的基础上 + 1
# 所以在进行运算前需要将 -5 的二进制进行 反码 和 补码
    # 原始 : b1000 0101
    # 反码 : b1111 1010
    # 补码 : b1111 1011
# 然后进行预算
    # 5 的二进制            b0000 0101
    # -5 反码补码后的二进制   b1111 1011
    # 结果 :                b10000 0000
# 得到的结果一共九位,二进制只能有八位,对多出的舍弃,所以最后的结果为
# 0b0000 0000
print(a + b)    # 输出 0
# 所以结果就是 0

位运算符

运算符 作用
& 按位与运算,只有两个值都为1结果才是1,否则为0
| 按位或运算,两个值只要有一个1,值就是1,否则为0
^ 按位异或预算,两个值不同是,值为1
~ 按位取反,单独的预算,1001
<< 左移动运算符,将二进制全部向左移动指定位数,不受反码、补码影响
>> 右移动运算符,将二进制全部向右移动指定位数,不受反码、补码影响
a = 60  # 60 = 0011 1100
b = 10  # 10 = 0000 1010

print(a & b)    # 8 = 0000 1000
print(a | b)    # 62 = 00111110
print(~a)       # -61 = 11000011   # 需要进行 反码、补码,注意符号位不计入计算
print(a ^ b)    # 54 = 0011 0110
print(a << 2)   # 240 = 1111 0000
print(a >> 3)   # 15 = 0000 1111

逻辑运算符

逻辑运算符是编写程序的精髓,很多情况下我们都需要逻辑运算符

运算符 作用
and 逻辑与,通常为x and y的格式,通过布尔值进行判断,如果有一个布尔值为False返回值就是False,必须全部返回的值都是True,结果才是True
or 逻辑或,通常为x or y的格式,通过布尔值进行判断,如果有一个布尔值为True返回值就是True,必须全部返回的值都是False,结果才是False
not 逻辑非not x,是非颠倒,如果xTrue返回结果就是False,如果为False,返回结果就是True

实例:



print(True and True)            # 返回 True
print(True and False)           # 返回 False
print(True and False and True)  # 返回 False
# 在进行逻辑运算的时候,会进行布尔值类型的隐士转换
print(33 and 55)    # 返回 55
print(bool(33))     # 返回 True
print(bool(55))     # 返回 True

# 逻辑 or 运算
print(False or True)    # 返回 True
print(False or False)   # 返回 False
print(False or False or True)  # 返回 True

# 逻辑非
print(not False)    # True
print(not True)     # False

and 在遇到 False 时停止

or 在遇到 True 是停止

在逻辑运算符中,优先级not > and > or

成员运算符

成员运算符用于判断指定值是否在序列中,这些序列例如字符串、列表、元组

运算符 作用
in 如果在指定的序列中找到了返回True,否则False
not in 如果在指定的序列中没有找到返回True,找到了返回False
str1 = "fsjkldfjsadlfjasd;lfdjsal;fadjslf;adsjkfl;adsjkfl"
# in
print("f" in str1)  # 返回 True
print("i" in str1)  # 返回 False

# not in
print("f" not in str1)  # 返回 False
print("i" not in str1)  # 返回 True

身份运算符

身份运算符用于比较两个对象的存储单元,就是比较在内存中地址是否相同

运算符 作用
is 判断两个标识符是否引用一个对象,x is y类似于id(x) == id(y)这样的命令,如果相同True,不相同返回False
is not 判断两个标识符是否引用不同对象,x is not y类似于id(x) != id(y)

id()函数用于获取对象的内存地址。

a = 10
b = 20
print(a is b)   # False
print(a is not b)   # True

a = 100
b = 100
print(a is b)   # True
print(a is not b) # False

数值在内存中有缓冲区,其中保存的有-5256的数据,在这个段的数据都会先指向缓冲区,由于pycharm有优化,在终端中进行测试

Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 256
>>> b = 256
>>> a is b
True
>>> a = 257
>>> b = 257
>>> a is b
False

运算符优先级

讲了很多很多的运算符,他们和数学一样是有优先级,例如小学学习的先算乘除,再算加减

下边通过从高往低来介绍运算符的优先级

运算符 描述
** 幂运算,最高级别
~ 按位取反
* / % // 乘、除、取余、取整
+ - 加、减
>> << 右移,左移位运算
& 按位与
^ | 按位异或、按位或
<= < > >= 比较运算符
<> == != 等于运算符
= 赋值运算符
is、is not 身份运算符
in、not in 成员运算符
not and or 逻辑运算符

所以呢,可以总结一下,在有算数规则的时候,先进行

算符规则(+、-、*、/)>位运算>比较运算>等于运算>身份运算>成员运算>逻辑运算(not and or)

大概了解即刻,一定要知道not > and > or逻辑运算的优先级。

python条件语句

Python条件语句通过一条或多条语句的执行结果的布尔值(Ture、False)来决定代码块。可以简单理解为条件满足执行的语句不满足条件执行的语句

if语句的格式为:

if 判断条件:
    条件满足执行的语句
else:
	条件不满足执行的语句

python中在:后面的语句需要进行缩进,其代表的意思就是一段代码块。

缩进相同代表代码在同一范围。

可以看一个具体的例子:

name = "Junglezt"
# 只有在 name 的值是 Jack 才会执行打印 Jack,nice to meet you
if name == "Jack":
    print("Jack,nice to meet you")
# 条件不满足,输出 He's not Jack 他不是Jack
else:
    print("He's not Jack")

上述是一个很简答的例子,通过名称判断name是否为Jack,如果是输出Jack输出Jack,nice to meet you,如果不是He's not Jack

if语句的判断条件可以是各种表达式,例如常见的> >= < <= == !=返回的结果是布尔值类型,可以进行有效的判断。

上述是一种条件,如果有多个名字呢,例如:我想把Alice也加入,对其输出Alice ? I think I know you.

这里就使用到了if语句的多条件判断,格式如下:

if 判断条件1:
    执行代码1
elif 判断条件2:
    执行代码2
elif 判断条件3:
    执行代码3
elif 判断条件4:
    执行代码4
else:
    执行代码

其中elif可以拥有多个,也可以没有,看实例:

name = "Alice"
# 判断是否为 Jack
if name == "Jack":
    print("Jack,nice to meet you")
# 判断是否为 Alice
elif name == "Alice":
    print("Alice? I think I know you.")
# 如果两个条件都不满足
else:
    print("He's not Jack or Alice")

python不支持switch ... case ..语句,只能使用elif来进行判断,有些时候可以使用一个条件进行判断,就是使用or

例如:if name == "Jack" or name == "Alice",这样也可以达到同样的目的。

num = 226
# 判断数字是否在 200 ~ 300 之间
if num >= 200 and num <= 300:
    print("这个数字在200 ~ 300之间")
else:
    print("这个数字不在200 ~ 300之间")

也可以在一行使用if语句

a = 5
if a > 3 : print('这个数字大于3')

if语句可以进行嵌套

# 例如模拟车站入口
resp = input("你问题买票了吗?(yes/no)")
if resp == 'yes':
    print("你买票了,请过安检!")
    resp = input("是否通过了安检(yes/no)")
    if resp == "yes":
        print('恭喜你通过了安检!去候车区等待上车吧')
    else:
        print("你很可疑呢?诶?这个是什么?")
else:
    print("你没有买票,你去售票台买票")

While循环

Python中使用while循环执行程序,在条件成立的情况下循环执行某段语句,d达到重复处理相同的任务。格式为:

while 判断条件:
    执行语句		

判断条件返回值为True时,执行循环中的语句,判断条件返回值为False跳过循环或者说循环结束。类似于if语句。

可以通过断点来查看while循环的详细流程

a = 0
while a < 10:
    print(a)
    a += 3

在上述情况中,如果不在循环中对a的值进行递增,就会造成死循环

a = 0
while a < 10:
    print(a)
# 这里就会不停的输出 a 的值 0

循环输出1~9

num = 1
while num < 10:
    print(num)
    num += 1

break、continue

while也支持breakcontinue关键字,非常的重要,break用于结束本次循环,continue用于跳过本轮循环,具体看实例:

# 循环 1~10,奇数跳过,偶数输出
num = 1
while num < 11:
    # 如果除以 2 的余数不为0
    if num % 2 != 0:
        num += 1
        continue
    else:
        print(num)
    num += 1
    
# 循环 1~10 ,大于 10 时,停止循环
num = 1
while num < 100:
    if num > 10:
        break
    print(num)
    num += 1

while ... else ...

上述说到while循环类似于ifif一样,while可以使用while ... else...格式的语句。

num = 1
while num <= 5:
    print(num)
    num += 1
else:
    print("数字已经大于5")
1
2
3
4
5
数字已经大于5

while 简答语句

while也可以单行进行使用

num = 1
while num <= 5: print(num);num +=1

for循环

python可以使用循环遍历任何序列的项目,例如:列表字符串

for循环的语法格式如下:

for 迭代变量 in 迭代对象:
    循环体

可能看着有一点奇怪,看个例子:

# 循环字符串
name = "LQL"
for a in name:
    print(a)

# 循环列表
list = ['爱在西元前','发如雪','说走就走']
for b in list:
    print(b)

结果

L
Q
L
爱在西元前
发如雪
说走就走

range()

如果我们想要循环一些数字就是用到了range()方法,

方法 作用
range(start,stop,step) 生成一个指定范围的数字,包含开始,不包含结束,start为开始值,stop为结束值,step为步长

是用实例:

# 输入 1~9 数字
for i in range(1,10):
    print(i)

# 输出 0 2 4 6 8
for j in range(0,10,2):
    print(j)

for ... else ..

while循环语句一样,for循环也支持for ... else...语句。

这里标注一个重点,循环重的else语句是在循环结束后执行的语句。

for i in range(1,6):
    print(i)
else:
    print("循环结束了")
1
2
3
4
5
循环结束了

求质数

首先:在自然数中,质数是只有1和本身以外没有其他因数,就是只能通过1和本身乘法得到该结果。

得到这个条件,书写代码

# 求 1~100 的质数
for i in range(1,101):
    for j in range(2,i):
        if i % j == 0:
            break
    else:
        print(i)

Python中的循环是可以进行嵌套的,上述就是用了循环嵌套

pass关键字

pass关键字用于占位,可以理解为没用的,空的

例如我们执行if语句的时候:后面的代码块必须有内容,有时我们现在不知道要写什么,可以使用pass展示代替。

age = int(input("请输入你的年龄: "))
if age >= 18:
    print('你成年了')
else:
    pass

input()函数会获取用户输入的信息,默认格式为字符串。

上述案例中,如果输入的数字大于18,就会打印你成年了,如果不满足条件,就会不予理睬。

python字符串

字符串是Python中最常用的数据类型。通常使用''""进行包裹。

创建字符串字需要在''或者""中加入值即可。

str1 = "hello world"
str2 = 'hello python'

访问字符串

在上述简单数据类型的时候,我们已经讲解过可以使用下标切片获取字符串的内容。

格式为:字符串[下标]字符串[开始下标、结束下标]

str1 = "hello world"
str2 = 'hello python'

print(str1[0])      # h
print(str1[0:6])    # hello

print(str2[-1])     # n
print(str2[-6:])    # python

字符串拼接、重复

字符串之间可以使用+运算符进行拼接'你' + '好'你好

str1 = "你"
str2 = "好"
print(str1 + str2)  # 你好

print("love " + "191") # love 191

想要重复单个字符串多次,可以使用*多次

a = 'love 191\n' * 1314
print(a)
# 这里的 \n 是转义字符,为\n

转义字符

在需要使用特殊字符的时候,什么是特殊字符,例如换行tab键这种特殊字符,Python中使用\反斜杠代表转义字符。

常见的特殊字符如下:

特殊字符 作用
\\ 一个反斜杠字符
\' 一个单引号
\" 一个双引号
\b 退格键,Baskspace
\n 换行
\r 回车
\t 横向制表符
\v 纵向制表符
\f 翻页

字符串常用运算符

字符串会常使用一下运算符

运算符 作用 实例
+ +号两边的字符串进行拼接 "a" + "b" = "ab"
* 将字符串重复指定次数 "a" * 2 = "aa"
[] 下标取值 "abc"[0] = "a"
[:] 切片取值 "abcdefg"[0:3] = "abc"
in 成员运算符 "a" in "abc" = "True"
not in 成员运算符 "a" not in "abc"= "False"
r/R 原始字符串,不使用转义,打印最原始的字符串,开头r可以大写可以小写 print(r'\n') = \n
% 格式化字符串,或许详细讲解 print("abc%d"%100) = abc100

例如成员运算符,可以判断指定的字符是否在字符串中。

str = "love 191"
print("191" in str)         # True
print("love" not in str)    # False

格式化字符串

Python支持格式化字符串输出。这样会用到更复杂的表达式,最基本的用法是将一个字符串插入到一个带有字符串格式符%s的字符串中。如下例子:

print("你好,%s"%"世界")
# 你好,世界
print("今天的天气是%s,温度是%d°"%("晴天",23))
# 今天的天气是晴天,温度是23°

上述使用到了%s字符串的替换和%d数字的替换,当然不仅仅是这些。

下列为常用格式化字符:

格式化字符 作用
%s 格式化字符串
%d 格式化整数
%f 格式化浮点数
%c 格式化ascii

三引号

上述说到单引号双引号可以创建字符串,三个单引号三个双引号其实也可以进行创建字符串。

三个引号默认是多行注释的意思,可以书写多行的注释。

如果在开头使用赋值运算符就可以进行变量的创建。

'''
我是一段注释
可以换行的注释
# 号只是单独的一行的注释
'''
str = """
    我也是一个字符串变量,
    我与普通'或"不一样的我可以进行换行,
    没想到吧,我就是这么好用,
    但是人们平常不使用我呢,
    但有些人喜欢使用,就是这样。
"""
print(str)

Unicode字符串

定义Unicode字符串很简单,和原始字符串类似,字符需要在字符串前加入u即可。

str = u"hello world"
print(str)
# hello world
str2 = u"你好,\u4e16\u754c"
print(str2)
# 你好,世界

字符串常用内置方法

后续在进行我们会很多次使用到字符串,这里学习字符串常用的内置方法

方法 作用
str.capitalize() 首字母大写
str.count() 计算指定字符出现的次数
str.decode() 解码字符串
str.encode() 编码字符串
str.find() 查找字符串下标,默认左边第一个
str.strip() 去除字符串左右两边的空
str.replace() 替换字符串,注意字符串值不可改变类型
str.split() 分割字符串
str.lower() 字母全小写
str.upper() 字母全大写
str.partition() 使用指定字符将字符串分割为三个元组元素
例如:print('test.jpg'.partition('.'))
输出:('test','.','jpg')
str.index() find()类似,查找指定字符下标,默认左边第一个,错误会返回一个异常
str.format() 格式化字符串,和%方法类似,专门用于格式化字符串的方法
str = "heLLo woRLD"
# 首字母大写
print(str.capitalize())     # Hello world
# 计算一共有几个 L 的值
print(str.count('L'))       # 3 一共有三个 L 字符
# 使用gbk编码字符串
print(str.encode('gbk'))    # b'heLLo woRLD'
# 查找从左边字符串第一次出现的下标
print(str.index('L'))   # 2
print(str.find('o'))    # 4
# 查找从右边字符串第一次出现的下标
print(str.rindex('L'))   # 9
print(str.rfind('o'))    # 7
# 替换字符串的值
# 注意这里字符串值不可变类型,需要新创建一个字符串保存替换后字符串的值
str2 = str.replace("woRLD","191")
print(str2)     # heLLo 191
# 使用空格分割字符串为列表
print(str.split(' '))   # ['heLLo', 'woRLD']
# 全大写
print(str.upper())  # HELLO WORLD
# 全小写
print(str.lower())  # hello world

format()格式化字符串

format()%的使用方法类似,使用{}代替之前的%。看实例:

str = "{} {}"
print(str.format("hello","world"))  # 可以赋予控制
# hello world

# 根据下标赋值
str = "{0} {1}"
print(str.format("world","hello"))
# world hello
str = "{0} {1} {0}"
print(str.format("world","hello"))
# world hello world

# 根据属性赋值
print("名称:{name},喜欢:{like}".format(name="Jungelzt",like="write python code"))

上述就是format()函数的简单用法。

format()函数也可以调用字典中的键名键值对应的方法,需要在字典前加入**。看实例:

dict = {"name":"IG","sign":"中国第一个英雄联盟LPL世界冠军。"}
print("战队名称:{name},标志:{sign}".format(**dict))
# 战队名称:IG,标志:中国第一个英雄联盟LPL世界冠军。

print("网站:{name},地址:{url}".format(**{"name":"百度一下,你就知道","url":"http://www.baidu.com"}))
# 网站:百度一下,你就知道,地址:http://www.baidu.com

详细使用方法:于菜鸟教程-python字符串

python列表

列表属于序列,序列中的每一个值都会分配一个值(位置),可以叫做下标,索引,第一个的索引是0,第二个的索引是1...以此类推。

Python中最常用的序列就是列表元组

序列可以进行索引、切片、加、乘,成员运算等操作。

序列中内置确定序列长度、最大值、最小值的方法。

此次我们将的列表是一个很常用的数据类型,其中每个值使用逗号隔开,最外层使用[]包裹,列表中的值可以是任何数据类型,当然也可以是列表(列表嵌套)。

在之前的案例中我们已经简单了解过列表

创建列表:

list1 = ['值1','值2','值3']
list2 = [1,2,3,4,5,6]

访问列表值

和字符串类似的方法,可以使用下标切片获取数据

names = ["周杰伦","孙燕姿","许嵩","韩红","成龙"]
print(names[0])   # 周杰伦
print(names[1:4])   # ['孙燕姿', '许嵩', '韩红']

更新列表

也就是在列表中插入新值,最常用的方式就是list.append('值')

# 定义一个空列表
list = []
# 在列表最后加入 Junglezt 值
list.append('Junglezt')
print(list)     # ['Junglezt']
# 在列表最后加入值
list.append('http://cnblogs.com/Junglezt')
print(list)
# ['Junglezt', 'http://cnblogs.com/Junglezt']

另一个常用的方法insert()也可以在列表中插入数据,insert()可以指定下标插入值。格式为insert(下标,值)

list = ['Junglezt', 'http://cnblogs.com/Junglezt']
list.insert(0,'博客园')
print(list)
# ['博客园', 'Junglezt', 'http://cnblogs.com/Junglezt']

删除列表元素

常用的列表删除值得方法有del、remove()和pop()

list= ['博客园', 'Junglezt', 'http://cnblogs.com/Junglezt']

# del
# 删除列表中下标为 0 的值
del list[0]
print(list)
# ['Junglezt', 'http://cnblogs.com/Junglezt']

# remove()
# 指定列表值为 Junglezt 的值进行删除
list.remove('Junglezt')
print(list)
# ['http://cnblogs.com/Junglezt']

# pop()
# pop()方法默认会将列表中最后的值进行删除,并会将删除的值作为返回结果
test = list.pop()
print(test)
# http://cnblogs.com/Junglezt

# pop()
# pop() 可以执行下标获取删除的值
list = ['a','b','c']
str = list.pop(2)
print(str)
# 返回 c

列表常用操作

列表会经常使用以下运算符

操作 作用
len(['a','b','c']) 获取列表元素个数 3
['a','b','c'] + ['d','e','f'] 列表拼接 ['a','b','c','d','e','f']
['a'] * 5 列表重复 ['a','a','a','a','a']
'c' in ['a','b','c'] 成员运算 True
for i in ['a','b','c'] 循环对象 迭代值,第一次a,第二次b,第三次c

列表常用函数

方法 作用
len() 获取列表元素个数
max() 返回列表最大值,如果是字母,按照ascii比较
min() 返回列表最小值
list() 转换为列表类型
com() 比较列表值

列表常用的方法

方法 作用
list.append(值) 在列表最后添加元素
list.count(值) 计算元素在列表中出现的次数
list.extend(序列) 在列表最后追加另一个序列的值,类似于+
list.index(值) 查找列表元素的下标
list.insert(下标,值) 在列表指定下标追加值
list.remove(值) 在列表中删除指定元素
list.pop(下标) 在列表中删除指定下标,并将删除元素作为返回结果,如果不指定元素下标,默认删除最后一个元素
list.reverse() 列表排序,元素倒序排序,反向排序
list.sort(reverse=False) 列表排序,默认使用升序排序,首先符号、数字、大写字母、小写字母reverseTrue时为降序

详细使用,菜鸟教程-python列表

list1 = ['Junglezt','226','$_zt','test','test']

# count()
# 计算 test 在列表中出现的次数
print(list1.count('test'))       # 2

# extend()
list2 = ('a','b','c')
# 将 list2 元组序列的值,添加到 list1 列表序列中
list1.extend(list2)
print(list1)
# ['Junglezt', '226', '$_zt', 'test', 'test', 'a', 'b', 'c']

# index()
# 在列表中查找 226 的下标
print(list1.index('226'))   # 1

# reverse()
# 对列表进行倒序排序
list1.reverse()
print(list1)
# ['c', 'b', 'a', 'test', 'test', '$_zt', '226', 'Junglezt']

# sort()
# 对列表进行 字符、数字、大写字母、小写字母 升序排序
list1.sort()
print(list1)
# ['$_zt', '226', 'Junglezt', 'a', 'b', 'c', 'test', 'test']
# 对列表进行 字母、数字、大写字母、小写字母 降序排序
list1.sort(reverse=True)
print(list1)
# ['test', 'test', 'c', 'b', 'a', 'Junglezt', '226', '$_zt']

python元组

元组和列表使用的方法是一样的,不过列表不可以进行值得修改。

如果说列表是游戏中的角色临时buf,那么元组就可以看为游戏中角色默认属性,是不可以进行修改的。

元组和列表的使用基本一直,这里不在进行叙述。

元组最重要一点

在我们进行变量名1,变量名2,变量名3 = 值1,值2,值3这种格式赋值时,其实使用的就是元组赋值,相当于变量名1,变量名2,变量名3 = (值1,值2,值3)

a,b,c = "001","002","003"
print(a,b,c)    # 001 002 003

# 加上括号
o,p,q = ("111","222","333")
print(o,p,q)    # 111 222 333

# 可以看出,上述两条语句是一样的

python字典

字典很常用,格式为每个元素key:value组成,这里我们就成为键:值

字典中的元素是由组成,之间使用:隔开,这是一个元素;每个元素之间使用,逗号隔开,最外层使用{}大括号进行包裹。

格式为:{key1:value1,key2:value2,key3:...}

上述列表和字符串采用下标取值,而字典是没有下标的,采用key键的方式取值。

基本操作

获取字典值、赋予字典新值、修改字典值、删除值。

# 注意:使用 dict 给字典的变量命名是不规范的,不建议使用。

dict = {'name':'Junglezt','age':'18'}
# 获取字典值
print(dict['name'])     # Junglezt

# 给字典赋值
dict['sign'] = "一个在学习网络安全的小萌新。"
print(dict)
# {'name': 'Junglezt', 'age': '18', 'dign': '一个在学习网络安全的小萌新。'}

# 修改字典值
dict['name'],dict['sign'] = 'LQL','like Her'
print(dict)
# {'name': 'LQL', 'age': '18', 'sign': 'like Her'}

# 删除字典元素
del dict['name']
print(dict)         # {'age': '18'}
# 删除字典
del dict

字典键的特性

字典的健有两个重要的特点

  1. 在创建字典时,不能拥有相同的键名,如果创建了,后创建的键名的值回被记住
  2. 键名是不可变类型,可以是用数字、字符串、元组,但是不可以使用列表。注意:字符串和元组是不可变类型。
# 后创建的键名会被记住
dict = {'name':'Junglezt','name':'LQL'}
print(dict['name'])
# LQL

如果键名为列表,则会报错

dict = {['list']:"test"}
Traceback (most recent call last):
  File "test.py", line 3, in <module>
    dict = {['list']:"test"}
TypeError: unhashable type: 'list'
# 类型错误: 不允许的类型,列表

字典常用函数

函数 作用
cmp() 比较两个字典元素
len() 计算字典元素个数
str() 转换为字符串类型
type() 查看数据类型

字典常用方法

方法 作用
dict.keys() 获取字典所有键名
dict.values() 获取字典所有值
dict.clear() 清空字典
dcit.copy() 对字典进行浅拷贝
dict.fromkeys(key,value) 创建一个新字典,键名为key,值为value
dict.get(key,value) dict[键名]获取值得方法一样,get()在没有查找到结果会返回None,而通过dict[键名]会报错,返回值可以通过value自定义
dict.items() items()方法会获取字典中所有的键名和值,然后组成一个元组。
dict.update() 把指定字典中的键和值更新到当前字典
dict.pop(key,default) 删除指定的值,没有找到`键会报错,可以通过设置默认返回值来避免。
dict.popitem() 删除字典中最后一个元组的键和值,并以元组作为放回结果(键,值)

fromkeys()

在不对元素值进行赋值时,默认值为None,如果直接使用列表对元素值进行赋值,会直接将列表赋值过去,需要遍历列表值,进行赋值。

key = ['name','age','sign']

dict = dict.fromkeys(key)
print(dict)
# {'name': None, 'age': None, 'sign': None}

value = ['Junglezt','22','like security']
# 这里可以直接遍历value列表即可,当时也不知道脑子怎么想的,这种方法
for i in range(0,len(value)):
    dict = dict.fromkeys(key,value[i])
print(dict)
# {'name': 'like security', 'age': 'like security', 'sign': 'like security'}

items()

items()方法会获取字典中元素的键和值并将每个元素组成一个元组

dict = {'name':'Junglezt','age':'22','sign':'like security'}
print(dict.items())
# {'name': 'like security', 'age': 'like security', 'sign': 'like security'}

# 通过 items() 遍历字典所有的键和值
for key,value in dict.items():
    print(key,value)

返回结果:

name Junglezt
age 22
sign like security

pop()、popitem()

pop()可以指定删除的键值,并将删除键的作为返回结果,如果没有找到该键值,默认会报错,设置默认返回值可以避免该结果。

popitem()会删除字典最后的元素,将键名和值组合为元组进行返回(键,值),如果字典为空,则会报错。

dict1 = {'name':'Junglezt','age':'22','sign':'like security'}

# pop(key,default)
resp = dict1.pop('name')
print(resp)         # Junglezt
aaa = dict1.pop('test','没有找到该键名')
print(aaa)          # 没有找到该键名

# popitem()
bbb = dict1.popitem()
print(bbb)          # ('sign', 'like security')

python日期和时间

python有很多处理日期的方式,转换日期格式是一个很常见的功能。当然这里我只知道一个time模块。

时间间隔使用的是以秒为单位的浮点小数

每个时间戳都是从1970年1月1日午夜(历元)经过了多长时间表示。

当前时间戳

time模块下可以进行很多时间格式的转换,常见的有time.time()获取当前时间的时间戳。

import time

now = time.time()
print("当前时间戳是",now)
# 当前时间戳是 1666228226.9647925

时间戳适合做日期运算。但是1970年以前的日期就无法表示了,遥远的日期也不可以,windows只支持到2038年

获取当前时间

时间戳我们是看不懂的,需要将其转换为可以看懂的格式,这是就用到time.localtime()方法。

import time

now = time.time()
print(time.localtime(now))
# time.struct_time(tm_year=2022, tm_mon=10, tm_mday=20, tm_hour=9, tm_min=25, tm_sec=9, tm_wday=3, tm_yday=293, tm_isdst=0)

# 根据返回结果,可以看出时间为 2022 10/20 9:25 星期四 今天的293天 

其实time.local.time()方法不需要添值,可以直接获取当前时间。

这里每个值以tim_名称开头,这是一个时间元祖。具体含义:

属性 作用
tm_year 年份
tm_mon 月份 1-12
tm_mday 日数 1-31
tm_hour 小时 0-23
tm_min 分钟 0-59
tm_sec 秒,60或者61是闰秒 0-61
tm_wday 星期,0是周一 0-6
tm_yday 今年第几天, 0-366
tm_isdst 夏令时 0、1、-1

格式化当前时间

上述使用localtime()方法获取的时间只是对时间戳进行了格式化,得到的只是一个时间元组格式的时间,还需要我们手动进行解析,总之这不是最终想要的结果,还需要使用time.asctime()格式化时间。

import time

now = time.time()
# 使用 time.asctime()方法格式化 时间元组
print(time.asctime(time.localtime(now)))
# 返回时间类型为:
# 星期 月份 日期 小时:分钟:秒 年
# Thu Oct 20 09:41:11 2022

这样就得到了一个看着很顺眼的时间。

上述使用了time()方法获取当前时间戳,然后使用localtime()解析当前时间戳获取当前时间,最后使用asctime()方法格式化当前时间,所以我们就得到一个步骤。

时间戳 -> 解析 -> 格式化

strftime()格式化时间

strftime()方法专门用于格式化时间。

import time

print (time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()))
# 2022-10-20 09:57:41

上述使用到了%Y、%m这样的格式化时间字符,详细:

字符 作用
%Y 当前年份 00-99
%y 当前年份 0000-9999
%m 月份 01-12
%d 月份中的某一天 0-31
%H 24小时制小时 0-23
%I 12小时制时间 01-12
%M 分钟 00-59
%S 00-59
%b、%h 当前月份 英文缩写,十月(Oct)
%a 当前星期 英文缩写,星期四(Thu)
%B 当前月份 全写
%A 当前星期 全写
%j 年内的一天 001-366
%p 上午或下午 AM或者PM
%U 一年的第一个星期 00-53
%Z 时区 例如:中国标准时间
%x 显示日期 例如:10/20/22,月份/日期/年份
%X 显示时间 例如:10:43:02,小时/分钟/秒
%c 本地相应日期和时间 例如:Thu Oct 20 10:43:36 2022
星期 月份 天 小时:分钟:秒 年

python函数

函数是组织好的,可以重复使用的,用来实现单一或相关联功能的代码。

函数可以重复利用,Python中有许多内置函数,比如我们常用的函数print()

我们也可以自定义函数,被称为用户自定义函数。

定义、调用函数

定义函数的目的一般是为了实现某一个功能,函数的规则:

  • 使用 def 进行定义,然后跟函数标志符,然后跟上()
  • 任何函数中的代码必须都在()中。
  • 函数第一行一般是函数的注释介绍。
  • 函数内容由:冒号开始,必须遵守缩进。
  • return[表达式]结束函数,选择性返回一个值。不使用return默认返回None

语法:

def 函数名称(参数):
    "注释——函数说明"
    函数内容
    return [返回值]

例如这里将一个值传入函数,最后将值输入到页面。

# 定义函数
def print_text(name):
    # 函数说明
    "打印传入的name"
    # 函数功能,打印
    print(name)
    # 函数结束
    return

# 调用函数
print_text('我的老哥')
# 我的老哥

参数传递

python中,变量属于对象,是没有数据类型的。

a = [1,2,3]
a = 'Junglezt'

在上述代码中,[1,2,3]list(列表)类型,'Junglezt'str(字符串)类型,而变量a是没有数据类型的,变量的作用仅仅是一个指针(引用),可以是列表也可以是字符串

mutableimmutable对象

就是可变类型和不可变数据类型,前面在讲解字符串等数据类型事有提到过,字符串、元组、数字是不可变数据类型,而列表、字典是可变数据类型。

不可变数据类型

例如如果我们赋值变量a = 1,这是如果我们想修改a的值,需要再次赋值变量a,例如:a = 2这并不是修改,而是重新赋值,实际上是新生成了一个数字对象2,然后指向a,之间的1值被丢弃。注意这里并不是修改了a的值,可以理解为重复赋值,新创建了一个a值。

参数传递

比如整数、元组、字符串,例如:function(a),传递的只是a的值,对a的本身没有影响。如果在function(a)内部修改a值,只是修改函数内部复制的a值,不会影响对象a本身

可变数据类型

例如变量a = [1,2,3,4],然后再赋值a[1] = 5,这里是将a中第二个元素进行修改,a本身并没哟进行修改,只是将内部的值进行了修改。

参数传递

比如列表、字典,例如:``funcation(b),将b值真正的传递过去,如果在函数中修改对象b值,对象b`会真正发生改变。

在python按照严格来说,一切都是对象,我们并不能说是值传递,还是引用传递,应该说传不可变对象传可变对象

实例

# 不可变类型,字符串实例
def fun1(test):
    test = 10
    print("函数中的test值",test)
    return

test = 226
# 调用 fun1 方法
fun1(test)	# 10
print("函数外的test值:",test) # 226

# 可变数据类型,列表实例
def fun2(test):
    test.append('Junglezt')
    test.append('Jackson')
    print("函数中的test",test)
    return

test = ['Alice','Bob']
print("函数外的test值",test)     # ['Alice', 'Bob']
# 调用 fun2
fun2(test)      # ['Alice', 'Bob', 'Junglezt', 'Jackson']

print("调用fun2方法后,test值",test)   # ['Alice', 'Bob', 'Junglezt', 'Jackson']
# 可以看出 可变数据类型 在方法中确实会被修改

必备参数

必备参数必须以正常的顺序传入函数。调用时的数量必须和声明是的数量一样。

如果在调用上述模拟printprint_test()函数,我们必须传入一个参数,否则会报错。

# 定义函数
def print_test(name):
    print(name)
    return
# 调用函数
print_test()

返回结果

Traceback (most recent call last):
  File "test.py", line 6, in <module>
    print_test()
TypeError: print_test() missing 1 required positional argument: 'name'
# 类型错误:print_test() 缺少一个必备的位置参数

关键字参数

关键字参数和函数调用时关系紧密,函数调用使用关键字可以确定传入的参数值

在我们使用函数时,需要按照函数定义好的参数顺序进行值的传递,在使用关键字参数传递值,因为直接采用属性名进行传递,顺序是不重要的。

看一下实例:

def print_info(name,age,sign):
    print("Name",name)
    print("age",age)
    print("sign",sign)
    return

# print_info("Junglezt",18,"like security")
# 采用 关键字 值传递,和上述代码效果一样
print_info(sign = "like security",name = "Junglezt",age = 18)

返回结果

Name Junglezt
age 18
sign like security

不定长参数

在声明参数的时候,有时传入的参数会多出我们声明的参数。可以使用*开头的参数,将接收的未定义的多出的参数进行存储,这个参数叫做不定长参数

实例:

# * 开头为 不定长参数
def print_info(name,age,*str):
    print("name:",name)
    print("age:",age)
    # 循环多出的 参数
    for i in str:
        print("{}:".format(i),i)
    return

print_info("junglezt",18)
print("-------------------------")
print_info("Junglezt",18,"test","aaa","bbb")

返回结果

name: junglezt
age: 18
-------------------------
name: Junglezt
age: 18
test: test
aaa: aaa
bbb: bbb

匿名函数

Python使用lambda来创建匿名函数

lambda是一个表达式,比定义函数def方法要简单很多。

语法格式:

lambda [参数1,参数2,...]:方法

具体使用:

# 定义 sum() 进行数字加法运算
sum = lambda num1 , num2 : num1 + num2

# 调用函数
sum(10,20)  # 没有返回结构,因为并没有将结果进行打印
# 使用 print() 嵌套 sum()
print(sum(10,20))   # 返回 30
print(sum(100,200)) # 返回 300

return语句

在定义函数的最后,用于定义返回结果。没哟定义返回结果默认值为None

格式:return[表达式]

在之前中没哟使用过return的返回结果,这里详细演示

# 定义 ride() 乘法运算函数,但不定义 return 返回结果
def ride(num1,num2):
    result = num1 * num2
    return
print(ride(2,2))    # 返回值为 None

# 定义返回结果为运算结果
def ride(num1,num2):
    result = num1 * num2
    return result
print(ride(2,2))    # 返回 4

变量作用域

一个程序的变量不是在哪里都可以访问的,这取决的变量在哪个作用域进行的赋值。

分别分为

  • 全局变量
  • 局部变量

全部变量可以在程序的任何位置进行访问,而局部变量只能在函数或者是被定义的作用域进行使用。看例子:

result = 0  # 这是一个全局变量
def sum(num1,num2):
    result = num1 + num2    # 这是一个局部变量
    print("局部变量result的值为:",result)
    return result

sum(50,50)  # 调用 sum() 函数
print(result)   # 返回结果 0

# 可以看到调用了sum()函数后,result的结果还是0
# 说明sum()函数中的result值并没有起到效果
# 打印输入的结果还是全部变量result的值 0

python模块

模块(module),是一个python文件,以.py结尾,包含了python对象定义和python语句

模块可以让你有逻辑的组织你的代码段,在使用相关的代码放到一个模块中,能让你的代码更好用,更易懂。

模块中能定义函数、类和变量,模块;就是一个python文件

例如,以下是一个名为test.pypython文件

def print_test(main):
    print(main)
    return

该文件可以理解为一个python,也可以被当做module模块导入到其他的python文件。

import导入模块

上述我们就相当于定义了一个python模块,这时只需要我们导入即可。

格式:import 模块名,例如导入test模块。import test

如果想要使用test模块下的print_test()

需要使用以下格式:模块名.函数名。例如:test.print_test()

# 导入 test 模块
import test

# 使用 test 模块中的 print_test() 方法
test.print_test("Junglezt")
# Junglezt

在进行模块的导入时,一般将import语句方法程序的开头。

在执行import语句的时候,如果模块在当前路径,就会被导入。

一个模块只会别导入一次,不管执行了多少次的import,这样做是为了防止导入模块被一遍又一遍的执行。

注意事项:在导入模块的时候,可以使用__file__内置方法获取模块文件地址,给python文件命名,不要起名和模块名一样。

from ... import

from ... import是用于导入模块中的函数,并不会将模块进行导入,只是导入模块指定的一个函数。

from 模块名 import 函数1,函数2,函数3...

注意事项:在使用from...import...的导入两个不同模块中两个一样的函数名时,后导入的函数或对象会被纪录,如果非要在两个不同模块中,导入两个相同的函数名,可以使用as关键字起别名

例如需要导入base64模块中的b64decode函数

from base64 import b64decode

这个操作只会把b64decode函数导入到程序中,并不会将base64导入到程序。

如果想一次性导入模块中的所有方法,from 模块名 import *语句

# 导入 base64 模块中的所有项目
from base64 import *

importfrom ... import的区别就是,import导入的模块需要使用模块.函数的方法调用,而from ... import可以执行调用导入的函数。

搜索路径

我们导入模块的时候,Python会在本地计算机中寻找相关模块的路径,是有一定顺序的。

  1. 当前路径
  2. 如果不在当前路径,搜索PYTHONPATH下的每一个目录
  3. 如果都找不到,python会查看默认路径

PYTHONPATH就是python默认安装目录

模块搜索路径存储在system模块的sys.path变量中。

一般默认路径为安装路径

sys,system模块中,path变量存储着所有python会查找的路径

使用print sys.path查看搜索路径

import sys
print(sys.path)

返回

['F:\\python', 'F:\\python', 'C:\\Users\\Jackson\\AppData\\Local\\Programs\\Python\\Python39\\python39.zip', 'C:\\Users\\Jackson\\AppData\\Local\\Programs\\Python\\Python39\\DLLs', 'C:\\Users\\Jackson\\AppData\\Local\\Programs\\Python\\Python39\\lib', 'C:\\Users\\Jackson\\AppData\\Local\\Programs\\Python\\Python39', 'C:\\Users\\Jackson\\AppData\\Local\\Programs\\Python\\Python39\\lib\\site-packages']

保证导入模块不执行测试语句

python开发中,我们可以导入任何一个文件,所以我们在开发时,建议写的每一个python文件都可以被导入,在导入时,会自动执行一些没有缩进的代码,这并不是我们想要的,所以要对这种被导入时执行的代码,做我们需要做一些处理

__name__属性

系统内置默认变量__name__如果在当前文件默认值是__main__,如果被其他文件当做为模块使用,返回的是__name__所在的文件,可以用该值进行判断代码在执行的时候是被当做模块导入还是在当前文件

定义aaa.py,内容为

if __name__ == '__main__':
    print("这是一个aaa.py测试文件")

使用test.py导入,并执行

import aaa

如果使用默认方法导入aaa.py,会执行这是一个aaa.py测试文件

dir()

dir()函数会返回模块中定义过的名字,例如函数变量

例如:

import sys
# 查看 dir 模块中定义的名字
print(dir(sys))

reload()

当一个模块被导入到程序中,import只会导入模块一次,如果这是模块加入的了新的内容,这是就需要使用reload()函数重新加载模块。

格式:reload(模块名)

python中的包(package)

包是一个分层的文件目录结构,定义了一个由模块中字包字包下的字包等组成的python应用环境。

包其实就是文件夹,但每个文件夹下必须有__init__.py文件,该文件内容可以为空,但必须存在,它用于像python标识当前文件夹是一个包。

例如,我们在test_packets下创建packet1.pypacket2.py和必不可少的__init__.py文件。

方法1

使用from 包名 import 包文件,或者from 包名.包文件 import 包方法可以导入到

packet1.py

def fun1():
    print("There is packet1.py")

packet2.py

def fun2():
	print("There is packet2.py")

__init__.py

这里可以为空

if __name__ == '__main__':
    print('作为主程序运行')
else:
    print('test_packets 初始化')

test.py

from test_packets.packet1 import fun1
from test_packets import packet2

# 不同的导入方法,使用不同的方法使用
fun1()              # 返回 There is packet1.py
packet2.fun2()      # 返回 There is packet2.py

运行结果

test_packets 初始化
There is packet1.py
There is packet2.py

方法2

使用import 包名也可以导入包,但是导入后是不可以使用的,需要在包目录中__init__.py文件中使用from . import 包文件导入包文件

  • __init__.py文件中导入包文件
  • 在需要导入包的文件使用import 包名,导入包

send_mess.py

def send(mess):
    print(mess)

__init__.py

from . import send_mess

test.py

import zt_test

zt_test.send_mess.send("hello")

上述中,包就是一个目录,名称为zt_test,其中有两个文件send_mess.py__init__.py。最后使用test.py导入包。

python 输入输出

print()

输入就是我们最常用的print()函数,它会将传入的值输入的页面中

print("结束了")

input()

输入,输入可以理解为获取键盘输入的值,常用的函数为input()函数

input()获取的值是字符串类型

name = input("请输入你的名称")
print("你的名字是",name)

文件基础操作

Python中提供了对文件读取、写入的常用方法

open()函数

如果想要打开一个文件,读取其中的内容,python需要使用open()函数。

open()函数返回的结果是一个file对象。

函数格式:open(文件名[,对文件的操作方法,buffering])

常用的操作方法

方法 作用
t 文本模式,默认模式
r 只读,文件必须存在
w 只写,文件存在清空内容,文件不存在创建文件
a 只写,文件存在追加内容,文件不存在创建文件
r+ 读写,文件必须存在
w+ 读写,文件存在清空内容,不存在创建文件
a+ 读写,文件存在追加内容,不存在创建文件
ab 使用二进制模式读取文件
wb 使用二进制模式写入文件

实例:

# 对 test.txt 执行 r 读取操作
f = open("test.txt",'r')

# 使用 type() 函数查看返回变量 f 数据类型
print(type(f))      # <class '_io.TextIOWrapper'>

# 使用 file 对象内置方法 read() 读取变量 f 的内容
print(f.read())

file对象常用的属性

属性 作用
file.name 文件的名称
file.mode 打开文件的模式
file.closed 文件被关闭返回true,打开返回false
f = open('test.txt','r')
# 文件名
print(f.name)   # test.txt

# 模式
print(f.mode)   # r

# 文件是否关闭
print(f.closed)   # false
# 关闭文件
f.close()
print(f.closed)    # true

close()方法

使用close()方法会对缓冲区的数据进行刷新,并关闭改文件。

就是在进行写入追加的操作后,需要使用close()关闭打开的file对象。

write()方法

write()方法提供了写入打开文件的作用,python中的字符串可以是二进制数据,并不完全是数字。看实例


# 对 test.txt 执行 写入 操作
f = open("test.txt",'w')
# 使用 write() 放发符 test.txt 进行写入
f.write("hellow-----world")
# 关闭打开的文件 test.txt
f.close()

# 再次对 test.txt 文件进行 读取 操作
b = open("test.txt","r")
# 读取 test.txt内容
print(b.read())     # 返回 hellow-----world
# 关闭打开的文件 test.txt
b.close()

read()方法

上述中我们也是用到了read()方法,read()可以读取file对象中的字符串,类似的有readlines()读取一行的数据

f = open('test.txt','r')
# 使用 readline() 读取 test.txt 第一行数据
print(f.readline())     # 返回 Junglezt
# 使用 read() 读取 test.txt 所有数据
print(f.read())
'''
返回 
www.baidu.com
www.cnblgso.com/Junglezt
LQL
Admin123

其中值没有 Junglezt 的原因是,readline()方法在读取一行后,会将指针移动到下一行
'''

with open() as ...

在进行文件的写入中,需要经典的三个步骤,open()函数打开文件 -> write()方法写入文件 -> close()方法关闭文件,如下

# 打开文件
f = open('test.txt','w')
# 写入文件
f.write('xxxxxx')
# 关闭文件
f.close()

使用with open() as 变量名:的方法可以让代码更简介,并且可以不使用close()方法关闭文件,因为该方法会默认自动调用close()方法。实例:

# 打开文件
with open('test.txt','r') as f:
    # 读取文件
    print(f.read())

这样可以避免读取文件是的一些错误。

文件指针

在使用read()readline()时有提到过,read()可有提供参数,参数的含义为读取多少字节。

read(8)读取前文件前八个指针的数据,通常一个字节一个指针

f = open('test.txt','r')
# 文件指针往后移动 8 位
print(f.read(8))

此时如果再次读取test.txt的文件内容,就会从指针8开始往后读取

tell()方法可以获取文件的指针位置

f = open('test.txt','r')
# 文件指针往后移动 8 位
print(f.read(8))
print(f.tell()) # 返回 8

seek(开始,条件)方法可以更改文件的指针,开始控制开始的指针,条件只能在开始0时设置,条件为0代表文件开始的位置,1定位到当前指针,2定位到结束指针

f = open('test.txt','r')
# 文件指针往后移动 8 位
print(f.read(8))
# 获取当前指针
print("当前指针是",f.tell()) # 返回 8

# 更改指针
f.seek(6)
print("当前指针是",f.tell()) # 返回 6

# 将指针更改为当前指针
f.seek(0,1)
print("当前指针是",f.tell()) # 返回 6

# 将指针更改为开始位置
f.seek(0,0)
print("当前指针是",f.tell()) # 返回 0

# 将指针更改为结束位置
f.seek(0,2)
print("当前指针是",f.tell()) # 返回 64

os文件操作

如果要对文件进行重命名删除的操作,python中提供了os模块执行系统的操作命令。

os.rename(旧文件,新文件)方法可以将文件重命名

os.remove(文件)方法可以将文件删除

os.mkdir(新目录)创建目录

os.chdir(目录)切换目录

os.getcwd()获取当前目录

os.rmdie(目录)删除目录

os.path.exists(文件)文件存在返回True,否则返回false

import os

# 将 test.txt 重命名为 aaa.txt
os.rename('test.txt', 'aaa.txt')
# 将 aaa.txt 文件删除
os.remove('aaa.txt')


# 创建 Junglezt 目录
os.mkdir('Junglezt')

# 获取当前目录
print(os.getcwd())  # F:\python

# 切换到 Junglezt 目录
os.chdir('Junglezt')
# 获取当前目录
print(os.getcwd())  # F:\python\Junglezt
print(os.path.exists('Junglezt'))

# 删除目录
os.rmdir('Junglezt')
'''
这里删除目录可能会报错,因为python解析型语言,只需要解释后交给内存和CPU处理
并不会顾及代码是否可以执行,
所以Python解释器会将所有的代码一行一行的交给处理器处理
删除文件时很快的,但是创建文件相对于较慢,
由于程序处理过快,在没有创建 Junglezt 目录的时候,就进行了删除
这里改进后的代码可以是,通过 if 语句判断 Junglezt 目录是否存在,然后进行删除

if os.path.exists('Junglezt'):
    os.rmdir("Junglezt")
    print("目录已经删除")
else:
    print("没有找到 Junglezt 目录")
'''

python 异常处理

异常就是报错,在程序程序执行的时候遇到了错误,导致了报错、程序异常终止的事件发生

异常处理

在一个良好的程序中,不可能我们的程序报错、出现问题就不可以执行了,一些错误是可以避免的,python提供了try: ... except:...语句,用于捕捉异常。

try...except语句会从try语句块中判断语句中的错误,遇到异常交给except捕获异常信息,并处理。

try except else语法格式

try:
    运行代码
except [异常类型]:
    在try部分遇到异常,执行的代码
else:
    没有发生异常执行的代码

语句逻辑很容易理解,首先执行try语句代码块,后续如何执行取决于try执行的代码是否异常。看具体实例:

try:
    f = open('aaa.txt', 'r')
except:
    print("没有找到文件,读取失败")
else:
    print(f.read())
    f.close()

当没有创建aaa.txt的时候,try语句异常,就会执行except语句,输出没有找到文件,读取失败,如果aaa.txt存在就会输出aaa.txt的内容。

这样做的好处就是没有报错提示信息,让代码逻辑更清晰,正确时执行的语句,异常是执行的语句。

默认情况下except会捕获所有的异常,这并不是理想的状态,我们可以指定异常类型,让except捕获指定的异常类型

格式为:except 异常类型1,异常类型2,...

常见的异常

异常 原因
SyntaxError python语法错误
TypeError 类型错误,常见于不同数据类型的无效操作
NameError 访问了一个未知的变量
ImportError 无法导入模块,路径和名称的错误
IndentationError 代码没有正确对齐,主要缩进错误
IndexError 下标错误,超出序列范围
IOError 输出输出异常,主要是无法打开文件
AttributeError 访问的对象属性不存在
KeyError 访问字典不存在的键
OverflowError 数值运算超过最大限制
TabError Tab和空格用法的错误
ValueError 无效的值,即使值得类型值正确的
ZeroDivisionError 算数中的除数为0

这些都是基本上常见的,大概了解即可,详细可见菜鸟教程

其中有一个特殊用法Exception,默认会捕捉所有异常。

try-finally 语句

try-finally无论是否发生异常,都会执行最后的语句。

try:
    a = 5
# 会输出 hello world,如果这里是except则不会执行
finally:
    print('hello world')

获取异常信息

except语句后加入错误类型然后as 变量名即可获取错误信息

# 当用户输入的不是整数,输出报错信息,是整数打印数字退出循环
while True:
    try:
        num = int(input("请输入一个整数:"))
    except ValueError as V:
        print("出错了",V)
    else:
        print(num)
        break

触发异常

我们可以使用raise 异常类型自己触发异常

def loop(num):
    if num < 5:
        raise ValueError("num值不能小于5")
    else:
        print(num)
    return
loop(1)

自定义错误

  File "test.py", line 4, in loop
    raise ValueError("num值不能小于5")
ValueError: num值不能小于5

进程已结束,退出代码1

OS模块

Python的os模块提供了很对文件处理的方法,在上述中,我们对文件的处理简单使用了os模块,这里我们了解os模块中常用的方法

方法 作用
os.getcwd 获取当前工作路径
os.listdir(path) 获取路径下所有的文件和目录组成的列表
os.walk(path) 获取路径下文件和文件夹,并进行分类,并获取子目录的文件和文件夹,返回结果为元组(路径,目录,文件),可使用循环获取
os.path.exists(path) 判断文件和文件夹是否存在,存在返回True,不存在返回False
os.mkdir(path) 创建文件夹,如果文件夹存在创建会报错,建议配合os.path.exists先检查文件夹是否存在
os.makedirs(path) 递归创建文件夹
os.rmdir(path) 删除文件夹,不过只能删除空文件夹
os.path.join(path,name) 拼接路径,例如:
os.path.join("F:/python","a.jpg")
返回:F:/python/a.jpg
os.path.split(path) 拆分路径,返回路径文件名
os.path.dirname(path) 返回路径,类似split的获取路径
os.path.basename(path) 返回文件名,类似split的获取文件名
os.path.isdir(path) 判断是否为文件夹
os.path.isfile(path) 判断是否为文件
os.path.sep 返回当前系统路径分隔符
os.path.getsize(path) 获取文件大小(字节)

对文件处理是少不了路径这个概念的,python的路径有个以下几种表述方式

"F:/python"		# 默认
r"F:\python"	# 原生字符
"F:\\python"	# \转义字符

使用实例:

import os

# 获取当前工作路径
path = os.getcwd()
print(path)     # F:\python

# listdir() 获取指定目录下的所有文件
files = os.listdir('D:/upload')
print(files)
# ['.user.ini', '11.gif', '2.php', '23146.gif', 'a.py']

# walk() 获取指定目录下所有目录和文件,还有子目录中的目录和文件
for path,dirs,files in os.walk(r"D:\网络搭建"):
    print(path)
    print(dirs)
    print(files)
    print('\n')

# path.exists() 判断文件、目录是否存在
print(os.path.exists('D:/2.jpg'))   # True

# 创建、删除文件夹
# os.mkdir('Junglezt')
# os.makedirs('aaa/bbb/ccc')
# os.rmdir('Junglezt')        # 只能删除空文件夹

# 拼接路径
path = r"D:\test"
print(os.path.join(path,'a.jpg'))   # D:\test\a.jpg


# 从完整路径获取 路径 文件名
path = r"C:\windows\system32\cmd.exe"
# os.path.split()
print(os.path.split(path))  # 返回元组 ('C:\\windows\\system32', 'cmd.exe')
# dirname() 单独获取路径
print(os.path.dirname(path))    # C:\windows\system32
# basename() 单独获取文件名
print(os.path.basename(path))   # cmd.exe

# isdir() 判断是否为目录
print(os.path.isdir('test'))    # True
# isfile() 判断是否为文件
print(os.path.isfile('test.txt'))   # True

# 获取系统路径分隔符
print(os.path.sep)  # \

# 获取文件大小,字节单位
print(os.path.getsize('test.txt'))    # 13

python面向对象

在python中,设计之初就是为了面向对象而设置,在python中创建一个对象很容易。

什么是类?

当我们要做一些事情的时候,例如我们可以把有一些共同特征的对象放入到一个类,所以在创建过程中,我们要先创建类,然后使用实例化一个对象,也可以说是创建一个对象,然后每个对象有不同的属性方法

可以看为游戏中的英雄,每个应用都是类似的,只是技能属性值不相同,所以他们可以归到一个类,这是我们就可以创建一个类。

对象可以看为英雄(类)中的一个角色(对象),每个对象有不同的技能属性

在操作中,我们可以将类似的东西(对象)归类到一个类中,这样在编写代码的时候思路更清晰,更有条理,每个对象拥有不同的功能和方法。

对象和类中含有属性和方法,可以理解为变量函数

基础语法

dir()函数

python中,对象无处不在,之前学习的变量、数据、函数都是对象。

使用dir()函数可以查看对象中的所有方法,利用好dir()函数,就可以不用死记硬背很多的内置函数。

对象的内置方法,一般为__开头和__结束

定义类、创建对象

定义类

在一个类中定义多个方法,这样通过类创建的对象,就可以直接调用其中的方法

class 类名:
    def 方法1(self,参数列表):
        pass
    def 方法2(self,参数列表):
        pass
  • 使用class 类名:就可以创建一个类
  • 定义方法和之前定义函数一样,不同的是第一个值为self

注:类名必须大驼峰命名

创建对象

对象时根据类创建的,所以想要创建对象必须先创建类,然后将类实例化,就是创建对象,创建对象语法格式如下:

对象名 = 类名()

示例

# 创建猫类
class Cat:
    """这是一个猫类注释"""
    # 定义 eat() 方法
    def eat(self):
        print("喜欢吃鱼")
    # 定义 drink() 方法
    def drink(self):
        print("要喝水")

# 使用Cat类,创建jack对象
jack = Cat()

# 调用 eat()、drink() 方法
jack.eat()
jack.drink()

创建对象属性

使用对象名.属性 = 值赋值运算符可以给对象属性赋值。

如下案例,统计过Person类创建了lql对象,给lql对象设置name属性,起个名字

# 定义 Person 类
class Person:
    pass

# 创建 lql 对象
lql = Person()
# 给 lql 对象设置 name 属性,值为 LQL
lql.name = "LQL"
# 输出 lql 对象 name 属性的值
print(lql.name)

self参数含义

删除在def 方法名(self)创建类中方法的时候,其中第一个参数为self,这是一个固定的格式,self参数名并不固定,可以是其他的名称,但是其意义是一样的。

那个对象调用方法,那个对象就是self的引用;例如:tom对象调用eat(self)方法,eat(self)方法中,self就是tom对象。

看实例:

# 定义 Cat 类
class Cat:
    # 定义 eat 方法
    def eat(self):
        # 该方法会输出 self 值
        print("小猫爱喝水",self)
# 创建 tom 对象
tom = Cat()

# 查看 tom 对象信息
print(tom)
# <__main__.Cat object at 0x0000027AFB9BE370>

# 调用 eat() 方法,可以看到输出的 self 的值就是 tom对象
tom.eat()
# 小猫爱喝水 <__main__.Cat object at 0x0000027AFB9BE370>

由此可以得到self,哪个对象调用方法,self就是那个对象。

看以下案例

# 定义 Cat 类
class Cat:
    # 定义 eat 方法
    def eat(self):
        # 输出 self 对象的 name 属性
        print("%s爱喝水"%self.name)
# 创建 tom 对象
tom = Cat()

# 定义 tom 对象的 name 属性为 Tom
tom.name = "Tom"

# 调用 eat() 方法
tom.eat()
# Tom爱喝水

上述案例使用格式化字符串的方法.

首先给tom对象name属性赋值,然后再调用eat()方法的时候,self.name就是tom.name获取name属性的值进行格式化字符串,得到返回结果Tom爱喝水

  • 在日常开发中,不推荐对象的属性进行外部的属性增加,赋值。

初始化方法

  • 当时用类名()这种方式穿件对象的时候,会自动进行一下操作:
    1. 在内存中为对象分配空间,创建对象
    2. 为对象设置初始值,初始化方法__init__

初始化方法对象创建的完毕后进行调用,方法名称为__init__,上述说到以__开头和结束的是python对象内置方法

__init__方法专用于创建一个对象时,拥有那些属性

查看实例:


class Test:
    def __init__(self):
        print("这是一段测试代码")

a = Test()
# 返回 这是一段测试代码

上述代码中,我们并没有手动调用__init__方法,但是执行了__init__方法中的语句,当然我们也可以手动调用。

可以看到__init__方法中,默认也有self参数,所以看下面代码


class Person:

    def __init__(self):
        self.name = "LQL"

zt = Person()
print(zt.name)  # LQL

代码中我们并没有手动的创建name属性的值,是__init__方法自动调用,在对象创建后默认添加的值,但是这里很明显有一个缺陷,我们创建的人的名称是zt,结果赋name的值是LQl

方法改造

  • 在实际过程中,我们希望在创建对象的同时,可以自定义对象的初始值
    1. 把需要设置的属性值,定义为__init__的参数
    2. 在方法中使用self.属性 = 形参接收外部传入的参数
    3. 在创建对象时,使用类名(形参1,形参2,...)方式创建

# 创建 Person 类
class Person:
    # 创建初始化方法
    def __init__(self,name):
        # 获取创建方法时的 name 值,使用upper()字符串内置方法将 name 值进行大写
        # 并赋值给 self.name 值
        self.name = name.upper()

# 创建 zt、lql 对象
zt = Person("zt")
lql = Person("lql")

# 输出 zt、lql 对象 name 属性
print(zt.name)
print(lql.name)

内置方法

__del__方法

__init__方法可以在对象创建后,进行操作,让我们的代码更加灵活。

如果我们想在对象销毁时,进行一些操作,可以使用__del__方法

  • 销毁指的是对象在内存中消除时
__str__方法
  • 默认情况下,创建一个对象后,使用print()函数输出对象的信息是对象属于的类,和对象在内存中的十六进制地址
  • 使用__str__方法可以自定义print()输出的信息,

需要注意的是,__str__必须有一个返回值,并且是字符串类型

class Cat:
    def __init__(self,name):
        self.name = name

    def __str__(self):
        "__str__方法可以定义 对象 的返回值"
        return "这里%s对象"%self.name

zt = Cat('ZT')
print(zt)

tom = Cat('Tom')
print(tom)

练习1

小明爱跑步例子

  1. 小明体重75.0公斤
  2. 小明每次跑步会减肥0.5公斤
  3. 小明每次吃饭体重增加1公斤

首先需要分析,对象小明需要名称体重属性。需要定义跑步吃饭两个方法。

看实例:

class Person:
    def __init__(self,name,weight):
        self.name = name
        self.weight = weight
        self.count = 0

    def run(self):
        self.weight -= 0.5
        self.count += 1
        print("{}体重减少了0.5公斤,现在体重是{},已经跑步{}次".format(self.name,self.weight,self.count))

    def eat(self):
        self.weight += 1
        print("{}体重增加了1公斤,现在体重是{}".format(self.name,self.weight),end='\n\n')


xm = Person("小明",75.0)
xm.run()
xm.eat()

在房子里添加家具

  1. 房子有户型总面积家具名称
  2. 家具有名称占地面积
    • 床(bed)占地4平米
    • 衣柜(chest)占地2平米
    • 餐桌(table)占地1.5平米
  3. 家具添加到房子
  4. 打印房子信息,要求输出:户型、总面积、剩余面积、家具名称
# 创建房子类
class Hourse:
    def __init__(self,type,area):
        self.hourse_type = type
        self.hourse_area = area
        self.area_free = self.hourse_area
        self.jiaju_list = []

    def add_jiaju(self,name,area):
        if self.area_free < area:
            print("当前屋子已经放不下这个家具了\n")
            return
        self.area_free -= area
        self.jiaju_list.append(name)

    def __str__(self):
        return "户型:{}\n总面积:{} [剩余面积:{}]\n家具列表:{}".format(self.hourse_type,self.hourse_area,self.area_free,self.jiaju_list)
# 创建家具类
class Jiaju:
    def __init__(self,name,area):
        self.name = name
        self.area = area

    def __str__(self):
        return "%s占地 %s平米"%(self.name,self.area)

# 创建家具对象
bed = Jiaju("床",20)
chest = Jiaju("衣柜",10)
table = Jiaju("餐桌",15)

# 创建房子对象
kehu1 = Hourse("二室一厅",80)

# 往房子里添加家具
kehu1.add_jiaju(bed.name,bed.area)

print(kehu1)

士兵开枪

  1. 士兵有名称、枪
  2. 士兵可以开火
  3. 枪能发射子弹更换弹夹

首先需要定义士兵类枪类,然后创建士兵和枪对象。设计思路,设计时先设计使用的物品,枪拥有名称和子弹数量两个属性,开火和换弹夹两个方法,士兵可以需要名称属性和枪属性,而枪属性取决于是否定义开火方法

例如不定义士兵的开火方法


class Gun:
    def __init__(self,name):
        self.name = name
        self.count = 0

    def add_count(self):
        self.count = 40
        print("子弹更换完成[40/40]")

    def shoot(self):
        if self.count < 1:
            print("[%s] 没有子弹...[0/40]"%self.name)
            return
        self.count -= 1
        print("[%s] tututu... [%d/40]"%(self.name,self.count))

    def __str__(self):
        return "[%s] 子弹:[%d/40]"%(self.name,self.count)

class Man:

    def __init__(self,name):
        self.name = name
        self.gun = None

SCAR = Gun("FN SCAR")

soap = Man("索普")
soap.gun = SCAR

# 调用射击方法
soap.gun.shoot()    # [FN SCAR] 没有子弹...[0/40]
# 调用换弹夹方法
soap.gun.add_count()    # 子弹更换完成[40/40]
# 调用射击方法
soap.gun.shoot()    # [FN SCAR] tututu... [39/40]
# 查看当前枪子弹
print(soap.gun)     # [FN SCAR] 子弹:[39/40]

另一个方法需要在士兵类中创建一个fire(self)方法,判断士兵是否有枪,调用枪对象开火方法。

私有属性、方法

在实际的开发中,对象的某些属性或方法只希望在内部被调用,不希望外部被访问到。

定义方法

属性和方法的基础上,开头加上两个下划线。

  • 格式:__属性名、__方法名

私有属性并不是完全不可以访问,是可以访问的,但是最好不要访问,因为设置私有拥有其存在的意义。

访问格式:_类名__属性名、_类名__方法名

继承

中的属性方法可以继承给子类,创建子类语法格式:class 子类名(父类)

看案例:

# 创建 Animal 类
class Animal:
    def eat(self):
        print("吃")

# 创建 Cat 类
class Cat(Animal):
    def dark(self):
        print("喵喵叫")

# 使用 Cat 类创建 tom 对象
tom = Cat()

# 使用 tom 对象调用 eat()和dark() 方法
tom.eat()
tom.dark()

上述中,使用Cat类创建出的tom对象,在Cat类中,并没有eat()这个方法,但是调用是成功的,说明类中的属性和方法是可以继承的。

覆盖父类

覆盖父类(重写)的属性和方法,有时候父类定义一些的特征,子类是不希望拥有,可以在子类中进行定义,覆盖父类中定义的属性和方法。

直接在子类中进行赋值、创建语句就可以覆盖

扩展父类

扩展父类适用于在覆盖父类方法的基础上,在子类覆盖了父类的属性和方法时,如果这时子类需要调用父类属性和方法,就需要使用super()对象,super()对象可以在子类中调用父类的属性。

这就相当于在子类对父类进行了一个扩展,使用格式:super().方法()


# 创建 Animal 类
class Animal:
    def eat(self):
        print("吃")

# 创建 Cat 类
class Cat(Animal):
    def eat(self):
        print("斯文的吃")
        super().eat()

# 使用 Cat 类创建 tom 对象
tom = Cat()

# 使用 tom 对象调用 eat()和dark() 方法
tom.eat()
'''
斯文的吃
吃
'''

python2中,使用类名.方法名(self)来调用,这个方法是不太好的,不推荐使用。

私有属性、方法的继承

私有属性和方法无法被子类继承的,私有方法只能在当前类中被调用,也不能在外部进行调用

多继承

一个子类可以拥有多个父对象,并且子类会继承每个父类的属性和方法

# 创建A类
class A:
    def ZZZ(self):
        print("ZZZ 方法")
# 创建B类
class B:
    def TTT(self):
        print("TTT 方法")
# 创建C类
class C(A,B):
    pass
# 使用 C类 创建 one 对象
one = C()
# 调用继承来之A对象的ZZZ()方法
one.ZZZ()   # ZZZ 方法
# 调用继承来之B对象的TTT()方法
one.TTT()   # TTT 方法

但是这也也出现了多继承的一个问题,如果继承的类中有相同的方法名,或者属性名,那么,到底执行谁的属性和方法?

注意:在开发时,避免出现这种会让人困惑的操作,也就是避免重名

到底继承谁的,在继承的时候先继承的谁,就调用谁的方法,如上述C(A,B)AB类中有相同的方法,由于先继承的A所有A的优先级比较高,就会调用A类中的方法。

python中的 MRO

python针对提供了一些内置属性__mro__,可以查看方法的搜索顺序。

所谓方法搜索顺序,就是在调用类中的方法时,python会根据__mro__值来决定调用哪个方法

类属性

在我们创建对象的时候,需要使用进行创建,其中我们可以给创建的对象赋值属性,类也是可以创建属性的,只需要在类中属性名 = 值进行赋值即可

也是一个对象,给类对象属性赋值,通常用于纪录与与这个类相关的特征

调用类属性和对象的方法一样,类名.类属性

class Tools:
    # 定义类属性count,初始值为0
    count = 0
    # 定义初始化方法
    def __init__(self,name):
        # 获取name传参赋值给对象name属性
        self.name = name
        # 类属性 count 自增 1,也就是没创建一个对象,count +1
        Tools.count += 1

# 创建三个对象
one = Tools("斧头")
two = Tools("剪刀")
three = Tools("弓箭")
# 输出 Tools 对象的 count 值
print(Tools.count)

属性获取机制

在创建类属性后,使用类创建的对象也可以访问类属性中的值,对象在获取属性时,如果自身没有,会找到自己的类,查看是否有该属性。

class A:
    test = 1

one = A()
# 访问 test 属性
print(one.test)

但是不推荐使用对象来访问类属性,在开发中可能会产生一些混淆。

类方法

之前我们使用的方法def 方法名(self):属于实例化方法,是针对于对象的方法,因为self默认第一次传参需要是一个对象

类方法,就是针对于类对象的方法。语法格式:

@classmethod
def 方法名(cls):
    pass
  • @classmethod修饰符用于告诉python,下面的方法是一个类方法

  • 类方法 的第一种参数是cls,和self类似

    • cls的意思为,哪一个调用的方法,cls就是哪一个类
    • 也可以使用其他的名称,只是默认第一个参数含义是这样,可以修改名称
class A:
    @classmethod
    def test(cls):
        print(cls)

A.test()
one = A()
one.test()

静态方法

静态方法和实例化方法、类方法不同,可以理解为中的普通方法,没有任何特殊的参数,只需要在前一行传入@staticmethod修饰符,然后下一行就可以定义静态方法

class A:
    @staticmethod
    def test():
        print("这是一个静态方法")
# 类名调用
A.test()

# 对象调用
one = A()
one.test()

class Game:
    top_source = 0
    def __init__(self,name):
        self.player_name = name
    @staticmethod
    def show_help():
        print("提示: 种植植物,抵挡僵尸进攻")

    @classmethod
    def show_top_source(cls):
        print("历史最高分为%d"%cls.top_source)

    def start_game(self):
        print("%s 已经开始了游戏"%self.player_name)

one = Game("Junglezt")

one.start_game()

单例设计模式

  • 设计模式是一些开发前辈留下的开发思路,我们可以直接套用,不用再做掉头发的事情。
  • 单例设计模式
    • 让类创建的对象,在系统中只有一个唯一的实例
    • 也就是每次执行类名()创建返回的对象,内存地址都是相同的
    • 使用场景如:打印机、音乐播放器、回收站,虽然处理的东西很多,但只有一个处理对象

__new__方法

  • 使用类名()创建对象的时候,python首先会调用__new__方法为对象分配空间
  • __new__方法是一个由object基类提供的内置静态方法,主要作用有两个:
    • 在内存中给对象分配地址
    • 返回对象的引用
  • python在获取了对象的引用的后,会将引用作为__init__初始化方法的第一个参数

重写__new__方法

上述我们说到,所有的对象的基类都是object,默认我们创建的对象都是继承object的内置方法,我们可以手动重写__new__方法,让我们知道知道在什么时候对象被分配的内存地址,但是重写__new__需要固定的格式

  • 因为__new__方法默认会返回对象的内存地址的引用,所以我们在重写后,必须加上return super().__new__(cls),不然会返回一个空的对象

创建单例

上述说到,单例是通过类创建的对象,只要唯一一个实例

  1. 定义一个类属性,初始值为None,用于纪录单例对象的引用
  2. 重写__new__方法
  3. 如果类属性is None,调用父类方法分配对象内存地址,并使用类属性进行纪录对象引用
  4. 如果值不是None就返回类属性中记录的对象引用

这样就可以达到,所有的对象都引用的一个内存地址的需求,看代码实例:

# 创建 Musicplayer 类
class Musicplayer:
    # 定义 instance 用来纪录创建对象分配的内存地址
    instance = None
    # 重写__new__方法
    def __new__(cls, *args, **kwargs):
        # 判断 instance 值是否为 None
        if cls.instance is None:
            # 如果为 None,分配动态地址给赋值给 instance 属性
            cls.instance = super().__new__(cls)
        # 如果不为 None,返回 instalce 的值引用内存地址
        return cls.instance
# 测试 instance 的值是否为 None
print(Musicplayer.instance)

# 实例化 one 对象
one = Musicplayer()

# 验证 instance属性 的值和 one 对象为一个内存地址
print(Musicplayer.instance)
print(one)

# tow对象引用的内存地址也是一样的
two = Musicplayer()
print(two)

初始化动作只执行一次

在使用__init__方法的时候,我们会多次调用其中的动作,每次创建对象都会触发,我们只想要在第一次创建的时候触发,如何实现。

  • __new__创建单例类似,使用一个类属性存储是否执行过初始化方法,如果执行过,就不在执行其中的动作。
  1. 使用一个类属性纪录是否进行过初始化方法,值为False
  2. 使用if语句判断,如果值为False,执行初始化方法
  3. 在执行初始化方法后,将类属性纪录值改为True

class A:
    count = False
    def __init__(self):
        if A.count == False:
            print("对象初始化")
            A.count = True

one = A()
print(one)

two = A()
print(two)

返回结果

对象初始化
<__main__.A object at 0x000001BA872BF220>
<__main__.A object at 0x000001BA872BF1C0>

可以看出,输出了对象初始化一次

发布模块

如果自己在再发中,创建了很好用的模块,可以分享给其他人。

python中提供了setup方法方便模块的共享。

使用from distutils.core import setup即可导入

1.创建 setup.py

from distutils.core import setup

setup(name="zt_test",                       # 包名
      version="1.0",                        # 版本
      description="测试发布模块",             # 描述
      long_description="来自Junglezt的测试", # 长的描述
      author="Junglezt",                    # 作者
      author_email="353823806@qq.com",      # 作者邮箱
      url="www.cnblogs.com/Junglezt",       # 主页地址
      py_modules=["zt_test.send_mess",
                  "zt_test.resp_mess"]      # 模块名
      )

2.构建模块

python setup.py  bulid

会在执行命令的当前目录生成一个bulid目录,里面的目录为指定的包名包模块

3.生成压缩包

python setup.py sdist

将构建的模块打包为一个tar.gz的压缩包

4.使用模块

首先将文件解压,使用命令

tar zxvf 压缩包名.tar.gz

解压后进入解压目录,其中有一个build目录,就是包的模块库文件,还要一个PKG-INFO是作者的描述,其中有一个setup.py,进入命令行

python setpu.py install

安装模块,会提示模块安装的路径。如果要将模块删除,到执行目录下删除包名的目录即可。

pip使用

因为中有很多强大的第三方模块,例如:PygameRequestsScapyIpython

这些模块都不是python内置的函数,是由别人开发的模块,因为像上述使用setup.py install的方式一个一个安装很慢,python推出使用pip进行快速的安装卸载模块,非常方便

使用php -V可以查看php的版本

pip -V

使用php list可以查看当前已经安装的模块

pip list

使用pip install 模块名pip uninstall 模块名可以安装卸载模块

pip install requests
pip uninstall requests

使用pip install -r 文件名 可以逐行读取文件中的模块进行安装

pip install -r requirements.txt

设置清华源

pip默认下载从国外的网站下载速度很慢,可以参考清华源暂时使用清华开源的地址下载。

更新pip

python -m pip install --upgrade pip

# 使用清华源更新pip
python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --upgrade pip

临时使用清华源

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 模块名

把清华源设置为默认源

pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
posted @ 2023-10-18 09:47  Junglezt  阅读(102)  评论(0编辑  收藏  举报