快捷目录

  • 简介
  • Python安装
  • IDE
  • 注释
  • 单行注释
  • 类注释
  • 方法注释
  • 基本数据类型
  • 字符串
  • 创建字符串
  • 字符串查找
  • 字符串长度
  • 索引
  • 特定字符串
  • 判断某字符串是否在该字符串里
  • 计算子字符串在字符串中出现的次数
  • 字符串操作
  • 删除某特定尾字符
  • 字符串类型转换
  • 字符串类型转换为其他类型
  • 其他类型转换成字符串类型
  • 正则表达式
  • 引入模块
  • match
  • search
  • sub
  • 变量
  • 私有变量
  • 变量赋值
  • 类变量
  • 局部变量
  • 全局变量
  • 实例变量
  • 删除变量
  • 面向对象
  • 创建类
  • 构造方法
  • 类的方法
  • 实例化对象
  • 访问属性
  • 引用类
  • from .... import ....
  • import ....
  • 继承
  • 调用
  • 重写父类方法
  • 继承实现接口
  • 反射
  • 判断属性或方法是否存在
  • 添加/设置属性
  • 获取属性或方法
  • 删除属性或方法
  • 文件操作
  • Open
  • with关键字
  • close
  • read
  • readline
  • readlines
  • write
  • OS
  • 引入
  • 删除文件
  • 判断是否存在该文件
  • 创建文件夹
  • 获取某文件的绝对路径
  • 检索目录下的文件
  • 改变当前工作目录到指定的路径
  • shutil
  • 引入
  • 移动文件
  • 复制文件
  • 相对路径解决办法
  • 默认
  • 动态获取绝对路径
  • 动态切换当前工作目录


简介

Python 是一种解释型、面向对象、动态数据类型的高级程序设计语言。Python 由 Guido van Rossum 于 1989 年底发明,第一个公开发行版发行于 1991 年。像 Perl 语言一样, Python 源代码同样遵循 GPL(GNU General Public License) 协议。

官方宣布,2020 年 1 月 1 日, 停止 Python 2 的更新。Python 2.7 被确定为最后一个 Python 2.x 版本。

笔者使用的是python3.8该博文并不适合完全零基础的读者,并且不会将所有的python基础全部展示出来,该博客旨在解决一些python的关键用法,python零基础请移步以下网址:

  1. Python3 基础语法 | 菜鸟教程 (runoob.com)
  2. Python 教程 (w3school.com.cn)

Python安装

安装python有两种方式

  1. 直接安装python环境,网址:Download Python | Python.org
  2. 安装conda环境,搭建虚拟python环境,推荐这个办法搭建python环境,可使用不同python环境进行编程,具体搜笔者的另外一个博客,Anaconda

IDE

  1. pycharm(笔者正在使用的ide)
  2. vscode

注释

引用:Python代码注释规范代码实例解析 - 知乎 (zhihu.com)

  • 注释不是越多越好。对于一目了然的代码,不需要添加注释。
  • 对于复杂的操作,应该在操作开始前写上相应的注释。
  • 对于不是一目了然的代码,应该在代码之后添加注释。
  • 绝对不要描述代码。一般阅读代码的人都了解Python的语法,只是不知道代码要干什么

单行注释

描述某个变量(某行代码)的作用

第一种写法:

# 注释
ui = 1

第二种写法:

ui = 1 # 注释

突出某段代码的重要性

# ==================
# 请勿删除该变量!!!!
# ==================
ui = 1

类注释

描述某个类的作用

格式如下:

"""类用处"""

使用实例:

class test:
    """类用处"""
    pass

方法注释

描述某个方法的作用

DocStrings 文档字符串使用惯例:它的首行简述函数功能,第二行空行,第三行为函数的具体描述。

格式如下(reST风格):

"""
方法的用处

:param parm: 形参的用处
:return: 返回的数据
"""

这是现在流行的一种风格,reST风格,Sphinx的御用格式,比较紧凑。

  • param为说明传入的形参
  • return为说明返回的数据

使用实例:

def test(self,parm01,parm02):
    """
    方法的用处
    
    :param parm01: 形参的用处01
    :param parm02: 形参的用处02
    :return: 返回的数据
    """
    pass

基本数据类型

Python3 中有六个标准的数据类型:

  • Number(数字)
  • String(字符串)
  • List(列表)
  • Tuple(元组)
  • Set(集合)
  • Dictionary(字典)

Python3 的六个标准数据类型中:

  • **不可变数据(3 个):**Number(数字)、String(字符串)、Tuple(元组);
  • **可变数据(3 个):**List(列表)、Dictionary(字典)、Set(集合)。

字符串

创建字符串

字符串是 Python 中最常用的数据类型。我们可以使用引号('")来创建字符串。

创建字符串很简单,只要为变量分配一个值即可。例如:

String1 = 'Hello World!'
String2 = "Hello python"

字符串查找

字符串长度

调用len,该方法不仅仅用在字符串,也可以统计列表,元组的长度

name = "helloworld"
len(name)

索引

对标java的indexOf(int ch,int fromindex),索引是通过字符串下标返回该下标的字符

str[0:1]

其中str为变量,0是头下标,1是尾下标

特定字符串

调用find函数,返回首字母在匹配字符串的下标

name.find("World")

判断某字符串是否在该字符串里

in关键字,若存在则返回True

name = "helloworld"
print("world" in name)

计算子字符串在字符串中出现的次数

调用count方法

name = "helloworld"
count = name.count("l",0,len(name))
print(count)

字符串操作

删除某特定尾字符

调用rstrip,如果方法不传参则默认删除空格符

name = "helloworld;"
print(name)
count = name.rstrip(';')
print(count)

字符串类型转换

字符串类型转换为其他类型

int类型(整数类型)

str = '1'
int(str)

str = 'a'
int(str) # 强转

float类型(浮点类型)

str = '0.05'
float(str)

这里提一下浮点类型的四舍五入,可以调用round函数计算

number = 5.454245435
round(number,3)

number为传入的浮点类型,3位保留3位数

其他类型转换成字符串类型

number = 1
str(number)

正则表达式

正则表达式是一个特殊的字符序列,它能帮助人们方便的检查一个字符串是否与某种模式匹配。

可用RegExr: 学习、构建 和 测试 正则表达式 Test RegEx (regexr-cn.com)生成正则表达式

引入模块

import re

match

尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match() 就返回 none

re.match(pattern, string, flags=0)

形参作用如下(按传入顺序):

  • pattern:匹配的正则表达式
  • string:要匹配的字符串
  • flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等
import re

name = "helloworld"
matcher = re.match("hello",name)
print(matcher)

匹配完成后,可用span方法在起始位置匹配

matcher.span()

search

扫描整个字符串并返回第一个成功的匹配

re.search(pattern, string, flags=0)

形参作用如下(按传入顺序):

  • pattern:匹配的正则表达式
  • string:要匹配的字符串
  • flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等
import re

name = "helloworld"
matcher = re.search("hello",name)
print(matcher)

匹配完成后,可用group方法在返回匹配的字

matcher.group()

sub

替换字符串中的匹配项

re.sub(pattern, repl, string, count=0, flags=0)

形参作用如下(按传入顺序):

  • pattern:匹配的正则表达式
  • repl : 替换的字符串,也可以是一个函数
  • string:要匹配的字符串
  • count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配
  • flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等
import re

name = "helloworld"
print(name)
name = re.sub("hello","bello",name)
print(name)

变量

私有变量

不与其他共享,自己独享,如函数和方法的局部变量,实例变量

写的时候,在变量左边加两个下斜杆(_)即可

例如:

__a = 1
__b = "1"

变量赋值

单个变量赋值

i = 1000  # int型
j = 1000.0  # float型
name = "tom"  # 字符串型

print(i)
print(j)
print(name)

多个变量赋值

  1. 给多个变量同时赋值,变量的值相同:a = b = c = 1
  2. 为多个变量指定多个值:a, b, c = 1, 2, "tom"

类变量

class内,不在class的任何方法内,使用类变量时,将类实例化后调用

class test:
    a = "123"
    __b = 1
    
    def test01(self):
        print(self.a) # 方法调用类变量
            
    @classmethod
    def test02(cls):
        print(cls.__b) # 静态方法调用类变量

局部变量

函数内、class的方法(类方法、静态方法、实例方法)内,且变量前面没有修饰

def test01(self):
	a = 1 # 局部变量

全局变量

全局变量供全局共享,全局类和函数均可访问,达到同步作用。同时还可以被外部文件访问。

全局变量使用的时候,需要用global显示声明。
一般情况下,如果函数直接调用全局变量,不做更新的话,一般没有问题,但如果有重新赋值,又没有在函数内部使用 global声明的话, 就相当于在内部创建了一个同名的局部变量,局部变量优先级要高于全局变量。

def myfunc():
  global x
  x = "fantastic"

实例变量

class的构造方法内,使用self修饰

def __init__(self):
    self.a = 1 # 实力变量

删除变量

调用del,可删除变量

name = "helloworld"
print(name)
del(name)
print(name)

面向对象

用来描述具有相同的属性和方法的对象的集合。

创建类

使用 class 语句来创建一个新类,class 之后为类的名称并以冒号结尾:

class Test01:
    """创建类"""
    a = "1" # 类变量

构造方法

当创建了这个类的实例时就会调用该方法

def __init__(self):
    pass

类的方法

类方法

def test01(self):
    pass

私有方法

def __test01(self):
    pass

抽象方法(不需要实例化对象直接调用,像调用类变量,例如:Test01.test01()

@classmethod
def test01(cls):
    pass

实例化对象

实例化类其他编程语言中一般用关键字 new,但是在 Python 中并没有这个关键字,类的实例化类似函数调用方式。

test01 = Test01() # 创建一个名为test01对象
test02 = Test01() # 创建一个名为test02对象

访问属性

访问方法

test01.test01() # 调用类方法

调用类变量

test01.a

在模块中,有一个__init__.py的文件,这个文件说明该文件夹为一个,该文件夹的名字为包名

__init__.py可以指定某个包下导入的类,例如,在Utils包中的__init__文件写入:

from .DataTimeUtils import DataTimeUtils
from .YAMLReader import YAMLReader

__all__ = ["DataTimeUtils",
           "YAMLReader",]

在其他类中导入时使用from Utils import *即可导入__init__文件中指定的所有类

from Utils import *
print(DataTimeUtils.getDay(0))

也可以指定某一个特定的类

from Utils import DataTimeUtils
print(DataTimeUtils.getDay(0))

该办法可以让导入更加容易,并且一定程度封闭该包下的类,但是该方法实测过会损耗性能

__init__.py默认不写时,可导入该包下的类,用from Utils.DataTimeUtils import DataTimeUtils即可

引用类

from … import …

引用类时,使用from Test.Test02 import Test02,具体是from 包名.类名 import 类名,调用时,直接实例化即可,例:

from Utils.DataTimeUtils import DataTimeUtils
dtu = DataTimeUtils()
dtu.getDay(0)

当一个py文件中没有类时(面向过程编程),使用from Test.Test02 import function,具体是from 包名.py文件名 import 方法名,想要使用该方法时,直接调用即可,例:

from Test.Test02 import function
function()

import …

引用类时,使用import Utils.DataTimeUtils,具体是import 包名.模块名(py文件名),调用时,需要完整写出包名.模块名.类名()去实例化一个类,例:

import Utils.DataTimeUtils
dtu = Utils.DataTimeUtils.DataTimeUtils()
day = dtu.getDay(0)

当一个py文件中没有类时(面向过程编程),使用import Test02,具体是import 包名.模块名(py文件名),想要使用该模块中的方法时,使用模块名.方法名()即可调用该方法,例:

import Test02
Test02.function()

继承

通过继承创建的新类称为子类派生类,被继承的类称为基类父类超类

语法:

class base:
    """父类"""
    pass

class Test01(base):
    """子类"""
    pass

一个类可以继承多个类,称为多继承,使用时尽量单继承

语法:

class base01:
    """父类1"""
    pass

class base02:
    """父类2"""
    pass

class Test01(base01,base02):
    """子类"""
    pass

调用

子类可以调用父类的方法与类变量,并且可以调用祖先(父类的父类)的方法与类变量

class base:
    a = "1"

    def base_test01(self):
        print("test")

class Test01(base):

    def test01(self):
        print(self.a)
        print(self.base_test01())

重写父类方法

子类可以重写父类的方法

class base:
    a = "1"

    def base_test01(self):
        print("test")

class Test01(base):

    def base_test01(self):
        print("test01")

继承实现接口

在python中,是没有interface的,实现接口,可以使用abc模块实现,例

import abc

class base(metaclass = abc.ABCMeta):

    @abc.abstractmethod
    def base_test01(self):
        pass

class Test01(base):

    def base_test01(self):
        print("test")

@abc.abstractmethod定义该方法为抽象方法,metaclass = abc.ABCMeta定义该类为抽象基类

若继承的接口类没有实现base_test01,则报错:

TypeError: Can't instantiate abstract class Test01 with abstract methods base_test01

在继承抽象类的过程中,应该尽量避免多继承;而在继承接口的时候,反而鼓励多继承接口。

在抽象类中,可以对一些抽象方法做出基础实现;而在接口类中,任何方法都只是一种规范,具体的功能需要子类实现。

反射

反射(Reflection) 允许运行中的 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性和方法。反射的具体作用如下:

  • 反射让开发人员可以通过外部类的全路径名创建对象,并使用这些类,实现一些扩展的功能。
  • 反射让开发人员可以枚举出类的全部成员,包括构造函数、属性、方法。以帮助开发者写出正确的代码。
  • 测试时可以利用反射 API 访问类的私有成员,以保证测试代码覆盖率。

也就是说,利用反射,我们可以获取以下程序:

  • Class 对象
  • 类中的所有字段
  • 类中的所有构造方法
  • 类中的所有非构造方法

反射看起来像是破坏了封装性,但是反射是可以作为一个工具,用来帮助程序员实现本不可能实现的功能(perform operations which would otherwise be impossible)。很多程序架构,尤其是三方框架,无法保证自己的封装是完美的。如果没有反射,对于外部类的私有成员,我们将一筹莫展,所以我们有了反射这一后门,为程序设计提供了更大的灵活性。工具本身并没有错,关键在于如何正确地使用。

新建一个类,该类为测试python反射的对象:

class Student:
    id = 1
    name = "123"

    def havePencil(self):
        print("He has a pencil")

判断属性或方法是否存在

调用内置函数,返回值为bool(若存在则返回True):

hasattr(object,'attrName')

形参说明:

  • object:对象,可以是实例化对象
  • attrName:字符串,用于判断对象是否存在该属性或者方法

例子:

from Student import Student

# student = Student()
has_bool = hasattr(Student,"id") # 是否存在该属性
has_bool = hasattr(Student,"havePencil") # 是否存在该方法
print(has_bool)

添加/设置属性

调用内置函数:

setattr(object,'attrName',value)

形参说明:

  • object:对象,可以是实例化对象
  • attrName:字符串,对象的属性
  • value:对象属性的值

object中,传入的对象是具体的实例化对象,则改变的是该对象的属性,否则会改变整体的对象属性

例子:

from Student import Student

student1 = Student()
student2 = Student()

print(student2.id)
setattr(student2,'id',2) # 改变student2对象中的id属性
print(student2.id)

print(student1.id)
setattr(Student,'id',3) # 改变全部Student对象中的id属性
print(student1.id)
print(student2.id)

获取属性或方法

调用内置函数:

getattr(object,'attrName')

形参说明:

  • object:对象,可以是实例化对象
  • attrName:字符串,用于获取该对象的属性或者方法

例子:

from types import FunctionType
from Student import Student

id = getattr(Student, "id") # 获取对象的属性
print(id)

havePencil = getattr(Student, "havePencil") # 获取对象的方法,返回FunctionType类型
print(havePencil(Student())) # 调用时加()并传入对象
print(type(havePencil) is FunctionType)

删除属性或方法

调用内置函数:

delattr(object,'attrName')

形参说明:

  • object:对象,可以是实例化对象
  • attrName:字符串,用于删除该对象的属性或者方法

例子:

from Student import Student

student1 = Student()

print(student1.id)
delattr(student2,'id') # 删除student1对象中的id属性
print(student1.id)

文件操作

Open

如果想用python读取文件,第一步要用open函数打开文件。open()是python的内置函数,它会返回一个文件对象,这个文件对象拥有read、readline、write、close等方法。

open函数有两个参数:

open('file','mode')

其中,file为需要打开的文件路径,mode为打开文件的模式,如只读、追加、写入等

mode常用的模式:

  • r:表示文件只能读取
  • w:表示文件只能写入,若文件不存在会创建一个
  • a:表示打开文件,在原有内容的基础上追加内容,在末尾写入
  • w+:表示可以对文件进行读写双重操作

mode参数可以省略不填,默认模式为r;mode参数还可以指定以什么样的编码方式读写文本,默认情况下open是以文本形式打开文件的,比如上面的四种mode模式。

当你需要以字节(二进制)形式读写文件时,只需要在mode参数中追加’b’即可:

  • rb:以二进制格式打开一个文件,用于只读
  • wb:以二进制格式打开一个文件,用于只写
  • ab:以二进制格式打开一个文件,用于追加
  • wb+:以二进制格式打开一个文件,用于读写

with关键字

在打开文件时,很多人通常直接用open(‘file’)。在文件读写时可以使用 with 关键字。优点是当子句体结束后文件会正确关闭,即使在某个时刻引发了异常。

with open('workfile') as f:
    for i in range(0,3):
    	read_data = f.write("test")
	f.closed

close

打开文件并处理完毕后,需要关闭文件,这里用到close方法。

f.close() 用来关闭文件并立即释放它使用的所有系统资源。如果没有显式地关闭文件,Python的垃圾回收器最终将销毁该对象并关闭打开的文件,但这个文件可能会保持打开状态一段时间。

应该要养成使用close()的习惯。使用方法很简单:

f = open(file) # 打开文件
f.close() # 关闭文件

read

当使用open函数打开文件后,就可以使用该文件对象的各种方法了,read就是其中一种。

read()会读取一些数据并将其作为字符串(在文本模式下)或字节对象(在二进制模式下)返回。

read方法有一个参数:

f.read(size) # f为文件对象

参数size(可选)为数字,表示从已打开文件中读取的字节计数,默认情况下为读取全部。

假设有一个文件sample1.txt,内容如下:

This is python big data analysis!

现在读取该文件:

with  open('sample1.txt') as f:
content = f.read()
    print(content)
    f.close()

readline

readline方法从文件中读取整行,包括换行符’\n’。

换行符(\n)留在字符串的末尾,如果文件不以换行符结尾,则在文件的最后一行省略,这使得返回值明确无误。

如果 f.readline() 返回一个空的字符串,则表示已经到达了文件末尾,而空行使用 ‘\n’ 表示,该字符串只包含一个换行符。

f.readline()有一个参数:

f.readline(size)

参数size表示从文件读取的字节数。

假设有一个文件sample2.txt,共三行,内容如下:

hello,my friends!
This is python big data analysis,
let's study.

用readline函数读取该文件:

with open('a.txt') as f:
    print(f.readline())
    print(f.readline(5))
    f.close()

readline方法会记住上一个readline函数读取的位置,接着读取下一行。

readlines

readlines方法和readline方法长得像,但功能不一样,前面说过readline方法只读取一行,readlines方法则是读取所有行,返回的是所有行组成的列表。

readlines方法没有参数,使用更加简单。依旧以sample2.txt为例:

with open('a.txt') as f:
    print(f.readlines())
    f.close()

write

write方法顾名思义,就是将字符串写入到文件里。

它只有一个参数:

f.write([str]) # f为文件对象

参数[str]代表要写入的字符串

使用起来也很简单,比如将下面字符串(注意里面的转行符’\n’)

'hello,my friends!\nthis is python big data analysis'

写入到文件sample3.txt里。

with open('sample3.txt','w') as f:
    f.write('hello,my friends!\nthis is python big data analysis')
    f.close()

OS

引入

import os

删除文件

os.remove(path)  # path是文件的路径,如果这个路径是一个文件夹,则会抛出OSError的错误,这时需用用rmdir()来删除
os.rmdir(path)  # path是文件夹路径,注意文件夹需要时空的才能被删除
os.unlink('F:\新建文本文档.txt')  # unlink的功能和remove一样是删除一个文件,但是删除一个删除一个正在使用的文件会报错。

判断是否存在该文件

使用os.path.exists判断某个文件是否存在

is_exists = os.path.exists("test.png")
print(is_exists)

创建文件夹

os.mkdir('d:\hello') # 在一级目录中创建
os.makedirs('d:\hello\world\123') # 创建多级目录

获取某文件的绝对路径

abs_path = os.path.abspath("test.png") # 返回test.png的绝对路径
py_abs_path = os.path.abspath(os.path.dirname(__file__)) # 返回当前py文件下的绝对路径
print(abs_path)
print(py_abs_path)

检索目录下的文件

path = 'd:\hello'
# 遍历指定目录下所有文件和子文件夹文件
for root,dirs,files in os.walk(path):
    print(files)
  • root:根目录
  • dirs:根目录包含的子文件夹
  • files:根目录包含的子文件

改变当前工作目录到指定的路径

os.chdir(path)

shutil

引入

import shutil

移动文件

shutil.move(src = "./test.txt",dst = "./test") # src为源文件,dst为要移动过去的目标文件夹

复制文件

shutil.copy(src="./test/test.txt",dst="./") # src为源文件,dst为要复制过去的目标文件夹

相对路径解决办法

python操作文件的时候,相对路径是把运行的当前的.py文件作为基准的

假设当前的目录为:

  • Test
  • test.py
  • image
  • test.png
  • main.py

当运行main.py操作test.png这个文件的时候,相对路径则是./image/test.png

但是,当运行test.py操作test.png这个文件的时候,相对路径则是../image/test.png

因为这个,可能在编写代码,进行代码单元测试时可能正常,结果到运行整个项目的时候,就报错了,但是发现错误时,需要将代码里的所有的路径全部改一遍,如果代码量多,则增加工作量,显然不是明智之举。而在开发的时候,由于思维惯性,不可避免会发生这种错误。以下提供解决办法

默认

在开发的时候根据启动类,调整开发思维,将所有的相对路径以启动类为基准进行编写

该方法强烈不推荐,对某个模块进行测试的时候会非常麻烦

动态获取绝对路径

思路:

  1. 在父类中获取改py文件的绝对路径
  2. 通过字符串搜索项目所在根目录,返回路径
  3. 将路径定义为类变量(或全局变量),子类应用即可
import os

abs_path = os.path.abspath(os.path.dirname(__file__)) # 返回当前py文件下的绝对路径
root_path = abs_path[0:abs_path.find("Test")] # 返回根目录
print(root_path) # 子类用self.root_path即可

动态切换当前工作目录

思路

  1. 动态获取当前绝对路径abs_path
  2. 每个类调用os.chdir(abs_path),动态切换当前工作目录到该路径中
abs_path = os.path.abspath(os.path.dirname(__file__))
os.chdir(abs_path)