Python教程

Python

本文主要是介绍Python,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

目录
  • anaconda的环境设置命令
  • 赋值
  • 基本数据类型
    • 整型和浮点型
    • 字符串
    • 布尔值
    • 逻辑运算符
  • 分支与循环语句
    • if条件语句
    • for循环语句
    • while语句
  • 序列
    • 序列相关的内置函数
    • 列表
    • 元组
    • 封包和解包(元组,列表)
    • 字典
    • 集合
  • 模块和包
    • 导入模块
      • 使用主入口__main__的意义
    • 导入包
    • __init__.py的作用
  • 脚本运行
  • 帮助系统
    • 为函数编写帮助
  • 函数
    • 主函数
    • 函数的定义
    • 顺序参数与关键字参数
    • 变量的作用域
    • 形参和实参
    • 默认参数
    • 参数收集
    • 关键字参数收集
    • 逆向参数收集
    • 参数传递机制
    • return返回值
    • Lambda表达式
  • 异常处理
    • 异常处理的结构
    • 触发异常
  • 内置电池函数
    • 基本函数
    • 文件
  • 面向对象
    • 创建类和实例
    • 面向对象编程
      • 封装
      • 实例方法、类方法、静态方法
      • 动态的添加属性和方法
      • 动态添加属性
      • 动态添加方法
    • 继承
      • super()函数调用的方法
      • 对于属性的继承
    • 类变量
  • 常用模块
    • re模块
      • 正则表达式预定义字符
      • 正则表达式特殊字符
      • 正则表达式合理字符
      • 匹配方法 match, search
      • 查找方法 findall, finditer, fullmatch
  • 工程目录

anaconda的环境设置命令

anaconda 包含了conda和pip两个包管理工具。

conda -V / conda --version 查看conda的版本。

conda update anaconda 升级anaconda的版本。

conda update conda 升级conda包管理器的版本

conda update pip 升级pip包管理器的版本。

conda env list 查看系统中虚拟环境。

(base) leo@leo-Surface-Pro:~$ conda env list
# conda environments:
base                  *  /home/leo/anaconda3

conda activate env_name 切换虚拟环境

conda deactivate 退出当前虚拟环境,进入base。

conda create -n env_name 创建虚拟环境。

conda create -n env_name -c 源env_name 从其他环境复制一份新的虚拟环境。

conda remove -n env_name --all 删除虚拟环境

conda(pip) install -n env_name module_name 安装模块

conda install -n demo selenium
conda install python=3.9.4

conda remove -n 环境名 模块名 删除conda安装的模块

pip3 uninstall -n 环境名 模块名 删除pip删除的模块模块

conda list -n 环境名 显示指定环境下安装的模块。

配置Pycharm使用Anaconda的环境

创建新的项目,使用已经配置的虚拟环境。

赋值

x, y, z = 1,[1,2,3], 'Fidelio'

x = 'micros' , 'Fidelio' ==> ('micros' , 'Fidelio')

a, b = b, a 值互换

m = n = 'Fidelio' 链式赋值

id(对象) 显示对象的内存地址。

a is b 判断a 和 b 是不是一个对象。

基本数据类型

Python的每个对象在内存中都有自己的地址,使用 id(对象) 可以获得内存地址。

type(对象) 可以查看对象的类型。

a = 'www.163.com'
id(a)
4592242544

type(a)
<class 'str'>

对象有类型,变量无类型。 变量只是一个标签,贴到不同的对象上。

整型和浮点型

整型 int表示, 浮点型 float表示。

浮点数与整型运算,得到的是浮点型。

Python解决了整型溢出的问题。

浮点数可以使用科学记数法表示,2e3表示2000.0, 浮点数。

浮点数会溢出。

// 取得两个数的整数商,不是四舍五入,而是直接去整。

误差问题

100.0 / 3 得到的结果是33.333333333333336。

要获得准确的结算结果,需要使用decimal模块的Decimal类型。

使用内置的round(数值,保留小数位)来进行四舍五入计算。

#decimal.Decimal演示
import decimal
a = decimal.Decimal(100)
b = decimal.Decimal(3)
a / b
Decimal('33.33333333333333333333333333')

#round()的演示
round(a/b,2)
Decimal('33.33')

字符串

字符串可以使用单引号或者双引号,结果都是一样的。

转义

\ 是转义字符。

  • \n换行
  • \b 退格
  • \000 空白,其后面的内容不现实。
  • \f 换页

r'字符串' 代表字符串中的字符就是原始字符,不包含特殊含义。


print('Micros\nFidelio')
Micros
Fidelio

print(r'Micros\nFidelio')
Micros\nFidelio

字符串切片

字符串是一个序列,可以使用序列的方法进行操作。

  • 通过索引可以访问字符串的字符。
  • 切片 str[开始索引:结束索引] 包头不包尾。
  • len(str) 获得字符串长度。
  • + 连接两个序列。
  • * 重复序列的元素,生成新序列。
  • in 判断元素是否在序列中
  • max(str) , min(str) 虽然最大值元素和最小值元素。
str[0:3]
'abc'
str[:3]
'abc'
str[3:]
'de'
str[-3:-1]
'cd'
str[::2]
'ace'
max(str)
'e'
min(str)
'a'
'a' in str
True
str * 3
'abcdeabcdeabcde'

字符与编码转换

ord(字符) 获得字符对应的数字编码。 chr(数字) 获得数字对应的字符。

字符串的格式化

  • "{0:15}".format(str) 使用str替换占位符,15个字符长度,靠左对齐。
  • "{0:>15}".format(str) 使用str替换占位符,15个字符长度,靠右对齐。
  • "{0:^15}".format(str) 使用str替换占位符,15个字符长度,居中对齐。
  • "{0:>15.2}".format(str) 使用str的前两个字符替换占位符,15个字符长度,靠右对齐。
  • "{0:^10d}".format(int) 使用int替换占位符,10个长度,居中对齐。
  • "{0:010d}".format(int) 使用int替换占位符,10个长度,靠右对齐,不足补0。
  • "{0:010.2f}".format(float) 使用float替换占位符,10个长度,四舍五入保留两位小数,不足补0。
  • "{Key1} and {Key2}".format(Key1 = value, Key2=value)
  • f"{变量名} 其他内容 {变量名}"
'I love {0:^10}'.format('fidelio')
>>'I love  fidelio  '
'I love {0:^10.2}'.format('fidelio')
>>'I love     fi    '
'My weight is {0:^10.2f} kg'.format(87.567)
>>'My weight is   87.57    kg'
'My height is {0:^10d} cm'.format(180)
>>'My height is    180     cm'
'My height is {0:010d} cm'.format(180)
>>'My height is 0000000180 cm'
'I like {lang} and {name}'.format(lang = 'Python', name = 'Leo')
>>'I like Python and Leo'

字符串检查方法

  • str.isalnum(): 是否只包含字母和数字。
  • str.isdigit():是否只包含数字。
  • str.isspace(): 是否只有空白, \n\t都会是True。
  • str.istitle():是否每个单词都是第一个字母大写。
  • str.islower():是否都是小写。
  • str.isupper(): 是否都是大写。
  • str.startswith(str1):字符串是否是str1开头
  • str.endswith(str1):字符串是否是str1结尾

字符串修改

  • str.split(str1): 使用str1分割字符串,返回一个字符串列表。默认参数是空格。
  • str.lstrip():去掉字符串左边的空白。
  • str.rstrip(): 去掉字符串右边的空白。
  • str.strip():去掉字符串两边的空白。
  • str.upper():全部转为大写
  • str.lower():全部转为小写
  • str.capitalize(): 首字母大写
  • str.title():每个单词的第一个字母大写
  • str.join(序列):返回 序列元素1+'str'+序列元素2+'str'. split的逆操作。

布尔值

True / False

直接得到真值: 数字1, 任何非空的东西,例如:非空字符串,非空序列。

直接得到假值:数字0, 任何空的东西,例如:空字符串,空序列,None。

逻辑运算符

and

or

not

分支与循环语句

if条件语句

if 条件:

​ 语句块

elif 条件 :

​ 语句块

else :

​ 语句块

三目运算符:

​ A = X if 条件 else Y 条件为真,A=X,否则A=Y。

pass 站位语句,什么也不做。if语句后如果什么也不写会抛出异常,可以使用pass占位。

for循环语句

  • for i in range(10):

​ 语句块 i = 0 ~9

  • for element in 集合 :

    ​ 语句块

  • for 条件:

​ 语句块

​ else:

​ 语句块

​ for 运行完以后,else语句块执行。

​ for被break以后,else语句块不会执行。

  • 列表推导式 list = [ i for i in range(10) ]

while语句

while 条件 :

​ 语句块

else :

​ 语句块(当while条件不在成立时)

while条件为True时, else语句块不会执行。当While条件为False时,else语句块执行。

break 跳出循环体

continue 从continue所在位置调到循环语句块的最后一行(不执行最后一行)

序列

序列相关的内置函数

len(序列) 序列元素的个数,或者字符串的字符个数。

max(序列) 序列的最大元素。

min(序列) 序列的最小元素。

列表

list = [元素,元素]

list = list(元组) 将元组转为列表

list = list[: :-1]反转元素。

list.count(元素) 元素出现的次数。

list.index(元素) 元素出现的位置。找不到返回ValueError异常。

list.remove(元素) 从列表中删除元素,找不到元素返回ValueError异常。

list.pop(i) 删除索引为i的元素,并返回元素。不加参数默认删除最后一个元素。

del 列表[索引] 删除列表指定索引的元素。

list.reverse() 反转列表中的元素。

list.sort() 将列表的元素进行升序排序。list.sort(reverse = True) 进行降序。list.sort(key=len) 以元素的长度排序。

list.append(元素) 将元素添加到list。

list.insert(位置, 元素) 将元素插入到位置。

reversed(列表) 返回一个反向排序的元组。

str.join(列表) 返回一个str连接列表元素的字符串。

列表支持加法和乘法。

元组

tuple = (元素, 元素), 只有一个元素是,使用 tuple = (元素, ) 来创建元组。

tuple = tuple(list) 将列表转为元组

tuple.count(元素) 元素出现的次数。

tuple.index(元素)

封包和解包(元组,列表)

封包: 将多个值赋值给一个变量,会产生一个元组。

解包:将一个元组或者列表的元素赋值给多个变量。

#封包
>>> names = 'leo', 'kevin', 'winston'
>>> names -> ('leo', 'kevin', 'winston')

#解包
>>> name1, name2, name3 = names
>>> print(name1, name2, name3, sep='\n')
leo
kevin
winston

字典

字典的key一定是不可改变的类型,比如字符串常量,数值常量,布尔类型,元组。

dict() 转换元组或者列表为字典。

a= (['name', 'leo'], ['age', 18], ['gender', 'male'])
b = dict(a)
b
{'name': 'leo', 'age': 18, 'gender': 'male'}

dict.copy() 产生另外一个字典对象。

如果dict中的元素有引用型,需要使用copy模块的deepcopy命令来产生一个完全不同的字典。

import copy
a = {'name': ['leo','kevin']}
b = copy.deepcopy(a)

dict[键] 或者dict.get(键) 区别是get方法找不到key的时候也不返回异常。

dict.get(key , [ default ] ) 找到key,返回value,找不到,返回default(可选参数,默认为None)。

dict[key] = value 来设置键值对,缺点是如果存在键值对,会被覆盖掉。

dict.setdefault(key, [default] ) ,如果能找到key, 则返回value。 找不到key,就设置一个dict[key] = default , 并返回default。

dict.update(dict) 融合两个字典的键值对。如果作为参数的字典的key在当前字典存在,则更新value。

del dict[key] 删除键值对,找不到返回KeyError 异常。

dict.pop(key , [default]) 删除一个键值对,返回value,找不到默认返回异常。如果设置了default,返回default。

dict.popitem() 随机删除一个键值对,并用元组的形式返回删除的键值对。

dict.clear() 清除字典的所有键值对。被清空的字典为{ } , 仍然存在内存中。 del(dict) 就把字典从内存中销毁。

dict = {'name':'leo', 'age':18, 'gender':'male'}

dict.keys() 得到所有的key,以列表返回。['name', 'age', 'gender']

dict.values() 得到所有的value,以列表返回。['leo', 18, 'male']

dict.items() 得到所有的键值对,每个键值对放在一个元组中,所有的元组放在一个列表中。

[('name', 'leo'), ('age', 18), ('gender', 'male')]

集合

使用set(序列)可以创建可变集合。

set1 = set(['Leo' , 'Fidelio'])
{'Fidelio', 'Leo'}

list1 = list(set1) #将集合转为列表 或者用tuple转元组。

集合没有索引,也没有顺序,不属于序列。

集合中不能有重复的数据,重复数据会自动删除。

集合中不能添加可变类型的数据,例如列表不能添加到集合中。

set.add(元素) 向集合中添加元素。

set.update(set1) 将set1的元素添加到集合中。

set.pop() 随机删除集合的元素,不能有参数指定。空集合删除元素返回异常。

set.remove(元素) 删除指定的元素。删除不存在的元素会返回异常。

set.discard(元素) 删除指定的元素。元素不存在也不会返回异常。

set.clear() 清除集合的所有元素。

可以用集合set() 方法消除重复项。

list1 = [1,2,3,4,5,1,1,2,3,1,4]
list1 = list(set(list1))
print(list1)   -> [1, 2, 3, 4, 5]

元素 in 集合 判断元素是否存在于集合。

集合1 == 集合2 判断两个集合的元素是否相同。

集合1 < 集合2 判断集合1是不是集合2的子集。a.issubset(b)

集合1 > 集合2 判断集合1是不是集合2的超集。a.issuperset(b)

集合1 | 集合2 返回两个集合的并集。 a = a.union(b)

集合1 & 集合2 返回两个集合的交集。a = a.intersection(b) intersection_update 直接更新a

集合1 - 集合2 返回集合1相对于集合2的差集。a.difference(b) difference_update会直接更新a。

集合1 ^ 集合2 返回集合1和集合2的对称差集。a.symmetric_difference(b)

使用frozenset() 创建不可变集合。

dir(frozenset) 查看可用的命令。

模块和包

使用模块的优点:

  • 提供代码可重用性。
  • 提供独立的命名空间。

导入模块

import 模块名

import 模块名, 模块名, 模块名

from 模块名 import 函数名 导入模块下的某个函数。

from 模块名 import 函数名 as 别名 导入模块下的某个函数,并给一个别名。

from 模块名 import * 导入模块下的所有函数,不推荐。

使用主入口__main__的意义

当import的时候,会立即运行一遍导入的模块的代码。

如果模块有主入口的main函数语句,只有当前py文件被当成程序执行的时候才执行。作为模块被导入时,不会执行main函数的语句。

当模块没有包含在sys.path中,是无法导入的。

两个方法:

  1. 将模块创建在这个目录: '/Users/leo/opt/anaconda3/lib/python3.9/site-packages'

  2. 将需要使用的目录添加到sys.path 环境变量。

import sys
new_path = '/home/leo/PycharmProjects/leo1/venv/fid/fid'
sys.path.append(new_path)
import my_first_module
my_first_module.say_hello()

导入包

使用. 进入包的目录,找到对应的模块。

import 包路径

import 包路径.包路径

from 包路径 import 模块名

from asyncio.events(包.模块) import Handle(类)

__init__.py的作用

导入包的时候,就会读取包目录下的__init__.py文件。

__init__.py的作用是:

  1. 编写一些让导入者可以看到的信息。
  2. 提供可以调用的信息,比如: 类、方法、函数、变量等。
  3. 把下级成员的模块导入到顶层模块,然后通过顶层模块直接调用。
Fidelio包的__init__.py中定义了函数.
def intro():
    print('Hello, I will facilitate the opera manipulation....')
   

导入Fidelio包的时候,init.py自动运行,函数可以使用.
import Fidelio

Fidelio.intro()    -> Hello, I will facilitate the opera manipulation....
Fidelio包中的init.py,将其包含的模块的方法导入Fidelio包的环境。
from Fidelio.mod1 import fun1
from Fidelio.mod2 import fun2
from Fidelio.Opera.mod3 import fun3

写程序的时候,导入Fidelio包就可以通过Fidelio.fun1()去调用了。
Fidelio.fun1()

脚本运行

脚本开头的两句话,第一句指明python的位置,第二句指明使用utf8编码,避免中文乱码。

#!/usr/bin/env python

#coding:utf-8 

python运行的时候,会将py文件编译为pyc文件。如果没有修改py文件,那么执行这个程序的时候,会直接运行之前生成的pyc文件,这样可以提升执行速度。

帮助系统

  • 单行注释 #

  • 多行注释

    ```

​ 多行注释

\```

查看函数的功能,可以使用 help(函数) 来查看。

help(id)
输出如下:
Help on built-in function id in module builtins:

id(obj, /)
    Return the identity of an object.
    
    This is guaranteed to be unique among simultaneously existing objects.
    (CPython uses the object's memory address.)

可以使用函数或者对象的__doc__属性来查看帮助文档。

print(print.__doc__)

output:
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file:  a file-like object (stream); defaults to the current sys.stdout.
sep:   string inserted between values, default a space.
end:   string appended after the last value, default a newline.

为函数编写帮助

使用三引号将帮助信息包含在函数定义的下一行。

def calc_score(*scores):
    """
    本函数用来计算总成绩。
    :param scores: 可以填写多个成绩。
    :return: 返回总成绩
    """

    total = 0
    for i in scores:
        total += i
    return total

函数

函数可以封装代码,达到代码复用的目的; 创建一个新的命名空间。

主函数

main函数时程序的主入口。作为模块被调用的时候,主函数中的语句避免了脚本运行。

#pycharm中输入main()即可
#main函数的上面定义函数和类。
if __name__ == '__main__':
  代码...

函数的定义

def 函数名(参数...):
  语句...
  语句...

顺序参数与关键字参数

顺序参数按照型参定义的顺序传递参数,顺序不能乱,参数不能少。

使用函数名 = 值的形式传递的参数。顺序可以乱,参数不能少。

def func(var1, var2):
    print(var1, var2)
    
func(var2 = 'Zhang' , var1 = 'Leo')

变量的作用域

作用域定义了变量能在多大的范围内被访问。

  • 全局变量:直接在内存中定义的单独变量。全局变量可以在任何地方访问。
  • 局部变量: 在函数中定义的变量叫做局部变量。局部变量只能在定义的函数中,或者函数的函数中被访问。
def demo():
    var = 20  #局部变量
    
#函数中使用global var可以访问全局变量。不实用global,则会创建一个新的局部变量。

if __name__ == '__main__':
    var = 10  #全局变量

形参和实参

定义函数的参数列表叫做形参。

调用函数传入的参数列表叫做实参。

def demo(var): #定义函数的规定的参数是形参
    pass

demo(123)  #调用函数时实际传入的参数是实参。

默认参数

指定默认值的参数的值,调用的时候可以不传递这个参数。

默认值参数应该放在型参列表的最后。

为默认值参数传递值,新值会覆盖默认值。

def func(var1, var2='Zhang')
    print(var1, var2)
    
func('Leo')

参数收集

当时用的参数数量不确定的时候,可以使用参数收集的方式传递多个参数,传递的实参以元组形式存放。

这种参数名前加 * 表示。

应当注意:

  • 型参中只能由一种这样的参数。
  • 尽量将这种参数放在型参列表的尾部。
  • 出现在这种参数之后的参数,只能使用关键字调用(想想print函数)。
def func(*args):
    print(f'number of args: {len(args)}')
    print(args)

func('Leo', 'Zhang')   

output:
number of args: 2
('Leo', 'Zhang')

关键字参数收集

当有不确定数量的关键字参数时,可以使用关键字参数收集,将收集到的关键字实参封装为字典存放。

这种参数名前加 ** 表示。

应当注意:

  • 型参中只能由一种这样的参数。
  • 必须将这种参数放在型参列表的尾部。
def func(**kargs):
    print(kargs)

func(name = 'Leo', age = '41')

output:
{'name': 'Leo', 'age': '41'}

逆向参数收集

将序列对象传递给函数,按照一定规则将序列对象的元素分配给型参。

应当注意:

实参为元组或者列表时,元素的数量应当与型参相同。

实参为字典时,元素的key必须与型参名字相同。

def func(var1 , var2):
    print(var1, var2)

arg1 = ['Leo', 'Zhang']
arg2 = {'var1': 'Leo' , 'var2':'Zhang'}

func(*arg1)
func(**arg2)

参数传递机制

不可变类型作为参数传递给函数后,按值传递的机制会复制一份传递,对于实参的任何操作都不会影响实参的值。

def func(name):                               
    name = 'IT: ' + name    #修改传递的参数                  
    print(name)             #IT: Leo                         

if __name__ == '__main__':                    
    my_name = 'Leo'                            
    func(my_name)                             
    print(my_name)           #Leo                  

可变类型作为参数传递给函数后,因为传递的是可变类型的地址,对于参数的任何操作都会影响实参的值。

def func(name_list,name):
    name_list.append(name)  #name_list作为可变参数被添加了新值。


if __name__ == '__main__':
    names = []
    func(names, 'Leo')
    print(names)            #['Leo']

return返回值

函数执行到return,会立即返回。return后面的语句不会执行。

return可以多个值,自动封包为元组。

不定义return的时候,函数返回一个None。

def demo():
    return 1,2,3

if __name__ == '__main__':
    result = demo()
    print(result)  # -> (1, 2, 3)

Lambda表达式

Lambda匿名函数,使用lambda关键自定义。 func = lambda 逗号分割的参数列表: 表达式主体

Lambda表达式主体只能放一个语句。Lambda自带return语句。

Lambda表达式支持的参数形式和正常函数一致。

func = lambda x, y: x + y
args = (1,2)
print(func(*args))   #3

异常处理

所有的异常都派生于BaseException类,不同的类记录了不同的异常信息。

异常处理的结构

try:

​ 可能发生异常的语句

except 异常类型 [as 别名]:

​ 异常处理语句

except Exception [as 别名]:

​ 异常处理语句

[else:

​ 没有异常发生所处理的语句]

[finally:

​ 有无异常一定处理的语句]

如果有多个except,处理异常的时候会去找最准确的异常类型,如果找不到在看有没有父类的异常类型,所以exception会在没有匹配上的时候在执行这个异常处理的分支。

finally分支用来进行资源的回收,无论try分支是否有异常,都会执行finally分支。

资源的回收包括: 打开文件、建立的网络套接字、数据库连接、多线程多进程。

触发异常

raise关键字主动抛出异常raise Exception

raise Exception('异常信息说明')

raise TypeError('This s a user-defined exception message....')

output:
Traceback (most recent call last):
  File "/home/leo/PycharmProjects/Fidelio/main.py", line 1, in <module>
    raise TypeError('This s a user-defined exception message....')
TypeError: This s a user-defined exception message....

内置电池函数

基本函数

round(数值, 小数位) : 四舍五入

bool(对象) 判断对象是否为空。当变量为数字0,None,空字符串或者空序列的时候,得到的结果为False。

reverved(列表) 将列表反转,返回列表。

sorted(列表) 将列表排序,返回列表。

range(开始值,结束值,步长) 返回从开始到结束值-1 的 range对象。

zip(集合1 , 集合2) 返回zip对象,集合1与集合2 索引相同的值作为zip对象的元素。

a = (1, 2, 3)
b = ('a' ,'b', 'c')
print(list(zip(a,b)))  ==> [(1, 'a'), (2, 'b'), (3, 'c')]

enumerate(集合) 将每个集合的值的索引与值形成一个数组。

a = (1,2,3)
list(enumerate(a))  ==> [(0, 1), (1, 2), (2, 3)]

for i,d in enumerate(a):
    print(i,d)

    
0 1
1 2
2 3

文件

file = open(文件路径 , 'r') 打开文件

file = open(文件路径 , 'w') 清空写入文件

file = open(文件路径 , 'a') 追加写入文件

for line in file : 针对文件每行进行扫描,遇到\n 结束本行。

file.read(size) 返回文本文件的所有内容 或者 size个字符的内容。

file.readline() 读取一行的内容。

file.readlines() 将文件的内容读到一个列表中,每行是列表的一个元素。

file.seek(行号) 移动文件读取的指针。

file.tell() 显示当前指针的位置。

file.write(内容) 写入一行数据

file.writelines(字符串列表) 将列表的每个元素作为一行写入文件。

file.close() 关闭文件

面向对象

创建类和实例

class 类名:

​ 类的语句

class 类名(父类) :

​ 类的语句

类名的首字母需要大写。

类名() 创建了一个实例。

面向对象编程

面向对象的三大特征:

  • 封装
  • 继承
  • 多态

封装

将类的属性和方法包含到类中。

构造方法 __init__ 将属性绑定到类的对象。

self代表将被创建出来的类的对象。

class User:
    def __init__(self,name, age, major):
        self.name = name
        self.age = age
        self.major = major

    def __str__(self):
        print(f'{self.name}\'s age is {self.age} and major is {self.major}',end='')
        return ''

user1 = User('Leo', 30, 'History')
user2 = User('Kevin',34, 'Math')
print(user1)  -> Leo's age is 30 and major is History
print(user2)  -> Kevin's age is 34 and major is Math
        
#self 参数用来指明创建出来的属性绑定到哪个对象。

类的方法中也可以添加类的属性,所添加的属性在类中可以全局调用。

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

    def set_age(self, age):
        self.age = age

    def get_age(self):
        print(self.age)

user1 = User('leo')
user1.set_age(30)  -> 这里产生了一个属性age
user1.get_age()    -> 查询类属性age

实例方法、类方法、静态方法

实例方法:首个参数是self,绑定给类的实例调用的,类本身不能调用。

类方法:首个参数是cls,并以classmethod修饰的方法,类可以直接调用,类的实例也能直接调用。类的属性在类方法中是无法使用的。

静态方法:无首个参数,使用修饰器staticmethod修饰的方法,类可以直接调用,类的实例也能直接调用。类的属性在类方法中是无法使用的。

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

    @classmethod
    def cls_method(cls, name):
        print(name)

    @staticmethod
    def sta_method(name):
        print(name)


User.cls_method('Leo')   #-> Leo
User.sta_method('Winston')  #-> Winston

动态的添加属性和方法

动态添加属性

为类添加的属性影响所有类的实例。为对象添加属性只影响单个对象。

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


if __name__ == '__main__':
    user1 = User('Leo') 
    User.age = 30     ->为类添加动态属性
    print(user1.age)  -> 30
    #虽然先创建的实例,添加类属性后,前面创建的对象也获得了这个属性。
    
  	

动态添加方法

实例方法:只能单独为对象添加,不能为类添加。需要使用types模块来协助。只有在添加方法的对象可以调用,其他对象无法调用。

import types    

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

def say_hello(self):      定义需要添加到对象的方法
    print('Hello World')

if __name__ == '__main__':
    user = Person('Leo')
    user.say_hello = types.MethodType(say_hello, Person)  添加方法到对象。
    user.say_hello()

类方法:使用@classmethod装饰器定一个类方法,然后复制给类。类和对象都可以调用。

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

@classmethod
def say_hello(cls):
    print('Hi, I am newly added class method...')

if __name__ == '__main__':
    Person.say_hello = say_hello
    Person.say_hello()   -> Hi, I am newly added class method...
    user = Person('Leo')
    user.say_hello()     -> Hi, I am newly added class method...

静态方法:使用@staticmethod装饰器定一个类方法,然后复制给类。类和对象都可以调用。

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

@staticmethod
def get_rid_from_china():
    print('No way...')

if __name__ == '__main__':
    Person.get_rid = get_rid_from_china
    Person.get_rid()
    user = Person('Leo')
    user.get_rid()

继承

子类继承父类后,可以直接使用父类的属性和方法。

子类定义了和父类同名同参的方法,则会覆盖父类的方法。

class 类名(父类名):

​ 类定义代码

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

    def show_message(self):
        print('Show message in user view')

    def add_message(self):
        print('Add a new message')

class Admin(User):
    def show_message(self):
        print('Show message in admin view')

if __name__ == '__main__':
    admin1 = Admin('Leo')       调用了父类的__init__(self, name)方法
    admin1.show_message()       调用了子类覆盖父类的show_message
    admin1.add_message()		调用从父类继承的show_message

super()函数调用的方法

可以在子类中调用父类的任何方法。

如果父类的方法要传参,子类调用的时候同样要传递参数。

子类调用父类的方法时,方法定义的self指向的是子类而不是父类。

class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def see(self):
        print('I can see you')

class Teacher(Person):

    def __init__(self,name, age, school):
        super().__init__(name, age)      #调用父类构造函数
        self.school = school     

    def see_student(self):
        super().see()                    #调用父类的方法    
if __name__ == '__main__':
    leo = Teacher('Leo', 30, 'Collins')
    leo.see_student()                    #I can see you
    print(leo.name, leo.school)          #Leo Collins

对于属性的继承

全部保留属性:子类不重写父类的__init__函数,就会全部保留父类的属性。

全部替换属性:子类重写父类的__init__函数,父类的__init__函数因为不调用,所以父类的属性都不存在。

class Vehicle:
    def __init__(self, brand, wheel):
        self.wheel = wheel
        self.brand = brand

class Car(Vehicle):
    def __init__(self, manufacturer):
       self.manufacturer = manufacturer

if __name__ == '__main__':
    my_car = Car('Japan')

部分保留,无新增:子类的__init__函数使用super()调用父类的__init__函数,用不到的参数传递None。

class Vehicle:
    def __init__(self, brand, wheel):
        self.wheel = wheel
        self.brand = brand

class Car(Vehicle):
    def __init__(self, brand):                   -> 只使用brand参数创建car对象
        super().__init__(brand, wheel=None)      ->使用None去掉不需要的属性  
       self.model = model

部分保留,有新增:子类的__init__函数使用super()调用父类的__init__函数,用不到的参数传递None。也新加子类专用的属性。

class Vehicle:
    def __init__(self, brand, wheel):
        self.wheel = wheel
        self.brand = brand

class Car(Vehicle):
    def __init__(self, brand, model):        ->新增一个model属性,使用brand,model参数创建新对象
        super().__init__(brand, wheel=None)  ->使用None去掉不需要的属性  
       self.model = model

类变量

在类中定义的变量,不是类的属性。

使用类来访问和修改类变量。实例只能访问但无法修改类变量。

类对变量的访问顺序:

​ 实例的属性(动态添加) -> 类的属性 -> 类变量 -> 父类的属性 -> 父类的类变量 -> 再继续往父类找....

class User:
    var = 10

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

if __name__ == '__main__':
    print(User.var)
    a = User('a')     #10
    print(a.var)      #10
    User.var = 100
    print(a.var)      #10
    a.var = 50        #实例改变不了类变量,只是给自己动态增加了一个属性。
    print(a.var)      #50
    print(User.var)   #100

类方法和静态方法可以访问和修改类变量

class User:
    var = 10

    @classmethod
    def change_var(cls, new_var):
        User.var = new_var

    @staticmethod
    def modify_var(new_var):
        User.var = new_var

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

if __name__ == '__main__':
    User.change_var(200)
    print(User.var)
    User.modify_var(250)
    print(User.var)

常用模块

re模块

用来创建正则表达式,用来验证和查找符合规则的文本。广泛用于搜索引擎和账号密码的验证。

正则表达式预定义字符

\d : 匹配十进制数字。

\D : 匹配所有的非数字。

\s : 匹配所有空白字符, 空格,tab。

\S :匹配所有非空字符和下划线。

\w : 匹配所有字母、汉字、数字。a-z, A-Z, 0-9.

\W : 匹配所有字母、汉字、数字和下划线。

import re

str1 = '[我是你爷爷abcd] 1234'
finded = re.search('\d\d\d', str1)  #从字符串匹配三个连续数字,从后往后找。
print(finded.group())   # 第一个匹配的是123

正则表达式特殊字符

^ : 文本的开头

$ : 文本的结尾

* : 前面的字符出现0次或者多次。

+ : 前面的字符出现1次或者多次。

? : 前面的字符出现0次或者多次,但变变贪婪模式为勉强模式匹配。
贪婪模式匹配出的字符串尽量的长,勉强模式匹配的字符串尽量的短。

. : 匹配除了\n以外的任何单个字符。

| : 使用竖线左右的正则表达式进行匹配。

import re

str1 = '[我你是你爷爷爷爷abcd] 你爷爷, 你爷1234'
finded_star = re.findall('你爷*', str1) #从字符串匹配你[爷0-无限次]
finded_plus= re.findall('你爷+', str1)  #从字符串匹配你[爷1-无限次]
finded_question = re.findall('你爷?', str1) #勉强模式从字符串匹配。
finded_dot = re.findall('.*', str1)
finded_or = re.findall('你爷+|\d', str1)

print(finded_star)      # ['你', '你爷爷爷爷', '你爷爷', '你爷']
print(finded_plus)      #['你爷爷爷爷', '你爷爷', '你爷']
print(finded_question)  #['你', '你爷', '你爷', '你爷']
print(finded_dot)       #['[我你是你爷爷爷爷abcd] 你爷爷, 你爷1234', '']
print(finded_or)        #['你爷爷爷爷', '你爷爷', '你爷', '1', '2', '3', '4']

[ ] : 代表一个集合。

  1. [abc] -- 匹配指定的单个字符。
  2. [a-zA-Z0-9 ] -- 匹配范围内的单个字符,可取反。 [^表达式] 取反。
  3. [0-5][0-9] -- 可以组合匹配。
import re

str1 = '我的名字是zhangsan,我的电话是18660236631'
str1 = '86, 71, 99, 97,00'

find1 = re.findall('[5-9][5-9]|0', str2)
print(find1)      #['86', '99', '97', '0', '0']

find3 = re.findall('[^a-zA-Z0-9,]+',str1)  #取反
print(find3)      #['我的名字是', ',我的电话是']

{ } : 标记前面字符出现的频率。

  1. {m, n} -- 前面字符最少m次,最多n次。
  2. {m, } -- 前面字符最少m次,上不封顶。
  3. { , n} -- 前面字符最多出现m次,最少一次都可以不出现。
  4. { n } -- 前面字符最少出现n次。

正则表达式合理字符

\t : 制表符

\n : 换行符

\r : 回车符

\f : 换页符

\a : 报警符

\e : Escape符

re.match将目标文本与正则表达式进行匹配。

如果匹配成功,将返回一个匹配对象,对象中包含匹配到的第一个子串。

如果匹配不成功,将返回None。

  • match 在目标文本的开头进行匹配。

    import re
    str1 = 'https://www.baidu.com'
    not_find = re.match('www', str1)
    do_find = re.match('ht+p\w+', str1)
    print(not_find)     # -> None
    print(do_find)      # -> <re.Match object; span=(0, 5), match='https'>
    
  • search 在整个目标文本中进行匹配。

    import re
    while True:
        email_addr = input('Please input email: ')
    
        match_result = re.search('\w+\.\w+@\w+\.\w+', email_addr)
        print(match_result)    
    

查找方法 findall, finditer, fullmatch

  • findall 扫描整个字符串,将与规则相匹配的子串拿出来组成列表。 没有匹配的字符串,返回空的列表。

    import re
    
    str1 = 'https://mail.163.com/email/webmail'
    finded = re.findall('\w{,3}mail',str1)
    print(finded)      # -> ['mail', 'email', 'webmail'] 
    
  • findall 扫描整个字符串,将与规则相匹配的子串组成一个迭代器。 没有匹配的字符串,返回空的迭代器。

    import re
    
    str1 = 'https://mail.163.com/email/webmail'
    finded = re.finditer('\w{,3}mail',str1)
    for i in finded:
        print(i)
    
    output:
      <re.Match object; span=(8, 12), match='mail'>
    	<re.Match object; span=(21, 26), match='email'>
    	<re.Match object; span=(27, 34), match='webmail'>
    
  • fullmatch 要求整个字符串完全符合规则,否则返回None。

    import re
    
    str1 = 'https://mail.163.com'
    finded = re.fullmatch('\w*.//\w*\.\w*\.\w*',str1)   #正则必须完全匹配文本
    print(finded)     # -> <re.Match object; span=(0, 20), match='https://mail.163.com'>
    

工程目录

将不同的代码分开,不同功能的代码放在不同的目录中。

每个子目录设置为不同的模块包,方便调用。

主流的子目录:

  • bin目录,放置主逻辑,main.py。
  • log目录,放置日志文件。
  • db目录,存放数据库目录。
  • data目录,存放普通数据文件,txt,json等。

一定要有readme文件,readme包含:

  • 那个目录做什么用的

  • 包含的方法,函数,类的说明。

这篇关于Python的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!