Python基础知识

目录

  • 前言
  • 一、Python虚拟环境
    • 1、Python虚拟环境的意义:
    • 2、Python构造虚拟环境的方法
    • 3、Python虚拟环境问题处理
  • 二、Python其他知识点
    • 1、pip忽略缓存安装
    • 2、镜像源
    • 3、python查找项目依赖
    • 4、python环境变量设置
    • 5、代码编辑
    • 6、列表拷贝
    • 7、vscode
    • 8、小工具
    • 9、日志工具loguru
  • 三、类相关知识点
    • 1、静态方法和类方法
    • 2、super()方法
  • 四、正则表达式
    • 1、反斜杠
    • 2、"\1\n\2"

前言

  Python基础知识。

一、Python虚拟环境

1、Python虚拟环境的意义:

  在实际项目开发中,我们通常会根据自己的需求去下载各种相应的框架库,如Scrapy、Beautiful Soup等,但是可能每个项目使用的框架库并不一样,或使用框架的版本不一样,这样需要我们根据需求不断的更新或卸载相应的库。在多个项目同时进行的过程中,对其他项目造成很多不必要的麻烦,管理也相当混乱。通过创建python虚拟环境,可以将不同项目需要的python开发环境封装在一个独立空间中,在这个空间中,安装项目需要的各种python包,这样将不同项目独立开来,便于开发管理。

2、Python构造虚拟环境的方法

  • 创建虚拟环境
    conda create -n 虚拟环境名称 python=*(python版本)
    
    例:conda create -n venv1 python=3.8
    
    注:虚拟环境名称确定了,会建立个同名的文件夹,后续虚拟环境中安装的包都会在这个文件目录下
    
  • 激活虚拟环境
    conda activate 虚拟环境名称
    
    例:conda activate venv1
    
  • 退出虚拟环境
    conda deactivate
    
    例:conda deactivate
    
  • 删除虚拟环境
    conda remove --name 虚拟环境名称 --all
    
    conda remove --name venv1 --all
    
  • 其他有用命令
    # 列出系统存在虚拟环境
    conda info -e或者conda env list
    
    # 查看当前环境下已安装的包
    conda list
    
    # 查看某个指定环境的已安装包
    conda list -n venv1
    
    # 查找某个package信息
    conda search numpy
    
    # 安装package
    conda install -n venv1 numpy
    # 如果不用-n指定环境名称,则被安装在当前激活环境
    # 也可以通过-c指定通过某个channel安装
    
    # 更新package
    conda update -n venv1 numpy
    
    # 删除package
    conda remove -n venv1 numpy
    

3、Python虚拟环境问题处理

  • clear命令失效
    • 问题描述:当使用clear命令的时候,出现了下面的错误。
      ~$ clear
      terminals database is inaccessible
      
    • 解决办法:执行下面的命令之后,该错误被解决。
      ~$ export TERMINFO=/usr/share/terminfo
      
    • 备注:最好是将上面那条export命令添加到~.bashrc中。

二、Python其他知识点

1、pip忽略缓存安装

pip --no-cache-dir install xxx

2、镜像源

Python镜像源

3、python查找项目依赖

  • 链接:查找python项目依赖的两种方法;
  • 说明:项目开发的时候,总是要搭建和部署环境,这时,就需要一个python第三方包的list,一般叫做requirements.txt。如果项目使用virtualenv环境,直接使用pip freeze即可,但是如果项目的依赖没有维护,就会很麻烦,这时我们就需要一个叫pipreqs的工具,可以帮助我们自动生成requirements.txt文件;
  • 方法
    • 使用pip freeze
      pip freeze > requirements.txt
      
      # 这种方式配合virtualenv 才好使,否则把整个环境中的包都列出来了。
      
    • 使用pipreqs
      安装:
      	pip install pipreqs
      
      用法:   
      	在项目的根目录下使用    pipreqs ./   
      
      注:
      	如果是Windows系统,会报编码错误 (UnicodeDecodeError: 'gbk' codec can't decode byte 0xa8 in position 24: illegal multibyte sequence)  ,使用时,指定编码格式:pipreqs ./ --encoding=utf8
      
      生成requirements.txt 文件后,可以根据这个文件下载所有的依赖
      用法:
      	pip install -r requriements.txt 即可
      
      如果遇到connection问题,使用如下命令:
      	pipreqs ./ --pypi-server http://pypi.douban.com/simple/
      
      这个工具的好处是可以通过对项目目录的扫描,自动发现使用了那些类库,自动生成依赖清单。
      缺点是可能会有些偏差,需要检查并自己调整下。
      

4、python环境变量设置

PATH、PYTHONPATH、sys.path


PATH
作用:
    定义python解释器路径
    
设置方法(当前用户永久生效):
    vi ~/.bashrc
    export PATH=$PATH:{python解释器所在目录},例如export PATH=$PATH:/home/zhangce/anaconda3/bin
    source ~/.bashrc

PYTHONPATH
作用:
    定义python模块的搜索路径

设置方法:
    vi ~/.bashrc
    export PYTHONPATH=$PYTHONPATH:{python模块所在目录},例如export PYTHONPATH=$PYTHONPATH:/home/zhangce/anaconda3/lib/python3.8/site-packages
    source ~/.bashrc

sys.path
作用:
    在python文件运行时,动态添加python模块搜索路径

设置方法:
    import sys
    sys.path.append("/home/zhangce/anaconda3/lib/python3.8/site-packages")

5、代码编辑

python文件的第一行代码一般为:
    # !/usr/bin/env python3
或者
    # !/usr/bin/python3

作用:
    当在命令行,没有指定执行py文件的解释器,此行会指定执行代码的解释器

区别:
    # !/usr/bin/python3 
    表示 python3 解释器所处的绝对路径就是/usr/bin/python3, 路径被写死了
    # !/usr/bin/env/ python3 
    表示从 "PATH环境变量"中查找python3解释器的位置,路径没有被写死,而是在"环境变量"中寻找python3解释器的安装路径,再调用该路径下的解释器来执行脚本。
    显然,采用后者的写法更灵活更具有通用性,推荐使用这种写法。

优先级:
    python3 test.py的优先级最高,无论代码首行指定的是哪个解释器版本,都比以命令行输入的python解释器要弱。

6、列表拷贝

【浅拷贝】
A = A1
# 说明:
# 改变A1的值,A的值也会发生变化    

【copy浅拷贝】
A1 = A.copy()
#或者
import copy
A1 = copy.copy(A)    
# 说明:
# 改变A1的值,A的值不会发生改变,除非A中包含子对象,比如:
                     #A = [0,1,2,[3,4,5],6,7,8]
                     #A  copy拷贝给A1之后,若给A1添加一个元素9,则:
                     #A = [0,1,2,[3,4,5],6,7,8]  而A1 = [0,1,2,[3,4,5],6,7,8,9]
                     #若给A1[3]这个元素[3,4,5]添加一个元素9,则:
                     #A = [0,1,2,[3,4,5,9],6,7,8]   A1 = [0,1,2,[3,4,5,9],6,7,8]

【深拷贝】
import copy
A1 = copy.deepcopy(A)   
# 说明:
# 深拷贝则是无论A有无子对象,A1改变,A也不会发生改变。

7、vscode

  • 问题:如果vscode导入包时,出现如下提示,则按照下面解决办法解决。
    Import "XXX" could not be resolved Pylance reportMissingImports
    
  • 解决办法
    1、打开.vscode文件下的settings.json文件
    2、添加如下代码块:
        {
            "python.analysis.extraPaths": ["/home/work/anaconda3/envs/zhangce-chatgpt/bin"]
        }
        其中:list中存储的是上述问题模块的路径
    

8、小工具

  • 中文数字<->阿拉伯数字
    • Python实现「中文数字」和「阿拉伯数字」相互转化
  • 文本时间抽取工具
    • 时间语义解析工具 Python版,从文本中提取时间,并解析其含义,在线使用,时间语义识别_语义分析 时间_jionlp数据分析的博客-CSDN博客

9、日志工具loguru

# 安装
pip install loguru

# 使用
from loguru import logger
from pathlib import Path
import time

# 获取当前工作路径的上一层路径
project_path = Path.cwd().parent
# 构建日志输出目录
log_path = Path(project_path, "logs")
# 构建时间变量
today = time.strftime("%Y_%m_%d")
# 构建日志工具
logger.add(f"{log_path}/ernie_bot_{today}.log", rotation='100MB', encoding="utf-8", retention=3, level="INFO")

# rotation='100MB':每100M创建一个新日志
# retention=3:同时保留三个日志文件

三、类相关知识点

1、静态方法和类方法

@staticmethod和@classmethod

相同点:
a. 都可以使用类对象和类对象实例访问

不同点:
a. @classmethod是一个函数修饰符,它表示接下来的是一个类方法,而对于平常我们见到的则叫做实例方法。 
b. 类方法的第一个参数cls,而实例方法的第一个参数是self,表示该类的一个实例。
c. 普通对象方法至少需要一个self参数,代表类对象实例。
d. 类方法有类变量cls传入,从而可以用cls做一些相关的处理。
e. 对于类方法,可以通过类来调用,就像C.f(), 也可以通过类的一个实例来调用,就像C().f(),这里C(),写成这样之后它就是类的一个实例了。
f. 静态方法则没有cls参数,它基本上跟一个全局函数相同。
d. 有子类继承时,调用该类方法时,传入的类变量cls是子类,而非父类。

例:
class A(object):
    @classmethod
    def cm(cls):
        print('类方法cm(cls)调用者:', cls.__name__)
    @staticmethod
    def sm():
        print('静态方法sm()被调用')

class B(A):
    pass

A.cm()
B.cm()
A.sm()
B.sm()

# 输出:
# 类方法cm(cls)调用者: A
# 类方法cm(cls)调用者: B
# 静态方法sm()被调用
# 静态方法sm()被调用

2、super()方法

  参考Python的super函数直观理解

super的作用就是执行父类的方法,虽然这句话不完全对,但是也差不多是那么个意思了。

1super方法简介
比如以单继承为例:
class A:
    def p(self):
        print('A')
class B(A):
    def p(self):
        super().p()
B().p()

输出:A

可以看到B().p()其实就是执行的A.p

2、MRO简介
class A:
    def p(self):
        print('A')
class B():
    def p(self):
        print('B')
class C(A,B):
    def p(self):
        print('C')
class D(C):
    def p(self):
        print('D')
a = A()
b = B()
c = C()
d = D()

四个类的MRO (可以通过查看__mro__属性获得,例如A.__mro__)) 分别是:

A: (A, object)
B: (B, object)
C: (C, A, B, object)
D: (D, C, A, B, object)

什么意思呢,我们以A类为例,它的MRO顺序是他自己和object,很好理解,因为python里一切都是对象,所以你可以看到四个类的终点都是object。那C类的MRO也好理解,第一个顺序永远是自己,然后按照代码顺序依次是A,B,最后是object3super用法

super本身其实就是一个类,super()其实就是这个类的实例化对象,它需要接收两个参数 super(class, obj),它返回的是obj对应类的MRO中class类的父类(或者说在MRO中按顺序的下一个类,下同):

class:就是类,这里你可以是A,B,C或者D
obj:就是一个具体的实例对象,即a,b,c,d。我们经常在类的__init__函数里看到super的身影,而且一般都是写成这个样子的super(className, self).__init__(),self其实就是某个实例化的对象。

4、举例

例1

super(C, d).p()
前面我们说过super的作用是 返回的是obj的MRO中class类的父类,在这里就表示返回的是d的MRO中C类的父类:
返回的是d对应类的MRO:(D, C, A, B, object)中C类的父类:A
那么super(C, d)就等价于A,那么super(C, d).p()会输出A


例2

super(A, c).p()
返回的是c的MRO中A类的父类:
返回的是c的MRO:(C, A, B, object)中A类的父类:B
所以最后的输出是B


例3

class A:
    def p(self):
        print('A')
class B(A):
    def p(self):
  super().p()
        print('B')
class C(B):
    def p(self):
        print('C')
class D(C):
    def p(self):
        print('D')

d = D()
d.p()
这个很简单,最后只会输出D

那如果D类改成如下样子呢?

class D(C):
    def p(self):
        super().p()
        print('D')
很简单,我们首先写出D的MRO为 (D,C,B,A,object),缺省状态下,super()就表示前一个父类,这里就是C类,那么super().p()就会调用C的p函数,但是C.p里没有调用super,所以就与A,B类无关了,那么最终的输出就是C,D


例4

class A:
    def p(self):
        print('A')
class B(A):
    def p(self):
        super().p()
        print('B')
class C(B):
    def p(self):
        super().p()
        print('C')
class D(C):
    def p(self):
        super().p()
        print('D')
d = D()
d.p()
输出:A B C D


例5

多继承
如果一个类继承多个类,原理一样,我们只要知道了MRO就能知道执行顺序了,比如下面的例子:

class A:
    def __init__(self):
        print('A')
class B:
    def __init__(self):
        print('B')
class C(A,B):
    def __init__(self):
        super(C,self).__init__()
        print('C')
class D(B,A):
    def __init__(self):
        super(B,self).__init__()
        print('D')
        
print(C.__mro__)
print(D.__mro__)
print('initi C:')
c = C()
print('initi D:')
d = D()

输出结果为

(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
initi C:
A
C
initi D:
A
D

结果解释,C 初始化后的打印结果应该很好理解,首先需要执行 super(C,self) 的_init_ 函数,根据C 的MRO可以知道super(C,self) 返回的是A ,所以可以看到最后的确是先打印出了A,然后是C
我们再看D 初始化的结果,注意执行的是super(B,self) ,根据D 的MRO我们可以知道返回的是A 所以打印的结果也是 A,然后打印出了D


总结
对于无论有多少个super(class, obj),我们首先需要知道obj的MRO是什么,然后找到class的前一个class是什么就好了。

super().__init__()xxxClass.__init__(self)的关系:Python类中super()和__init__()的关系

四、正则表达式

1、反斜杠

一、匹配 \d

被匹配的文本 'abcdef\d1234'

方法一:(不使用r)

普通字符串中\d无特殊含义,所以仅需对\进行转义, 即:'abcdef\\d1234' (此步骤称为:字符转义)
正则表达式中\和\d均有特殊含义,所以需摒弃\和\d的特殊含义,即再进行一次转义(此步骤称为:正则转义)

str1 = 'abcdef\\d1234'  # 因为\为转义符,所以需摒弃\的含义,因此此处为\\
print('原字符串',str1)
print('1. ',re.findall('\\\\d',str1))
 
控制台输出结果
# 原字符串 abcdef\d1234
# 1.  ['\\d']


方法二:(使用r)

r'' 代表raw string 原始字符串,引号内括起来的内容所见即所得,所以不需要进行字符转义。即:r'abcdef\d1234'
在正则表达式中\d具有特殊含义,所以需对此进行转义,摒弃\d的特殊含义。即:r'abcdef\\d1234'
所以最终结果为:
str1 = 'abcdef\\d1234'  # 因为\为转义符,所以需摒弃\的含义,因此此处为\\
print('原字符串',str1)
print('2. ',re.findall(r'\\d',str1))
 
控制台输出结果
# 原字符串 abcdef\d1234
# 2.  ['\\d']


二、匹配\\d

被匹配的文本 'abcdef\\d1234'

方法一:(不使用r)

字符转义。即'abcdef\\\\d1234'
正则转义(对前三个\转义和\d转义)。即'abcdef\\\\\\\\d1234'

方法二:(使用r)

r所见即所得,无需转义。即r'abcdef\\d1234'
正则转义。即r'abcdef\\\\d1234'
str2 = 'abcdef\\\\d1234'
print('原字符串',str2)
print('3. ',re.findall('\\\\\\\\d',str2))
print('4. ',re.findall(r'\\\\d',str2))
 
控制台结果
# 原字符串 abcdef\\d1234
# 3.  ['\\\\d']
# 4.  ['\\\\d']

2、“\1\n\2”

re.sub(pattern, r"\1\n\2", content)

"\1\n\2": 在第一个和第二个组之间用\n替换

你可能感兴趣的:(python,开发语言)