Python语法

 
 
 

一、vscode插件

1、Todo Tree待做事情的标记,在需要添加代做事情项之后添加 // TODO: 这样的注释代码,然后就可以在 Todo Tree 中快速定位到这行注释。

2、Draw.io 画流程图,安装完成后,新建一个文件xxxxxx.drawio就可以打开了!!

3、Python Preview 展示Python中内置变量的值,可视化你的代码结果,方便调试

4、Git Graph通过这个扩展,可以清楚地看见当前分支的commit记录和变化,可以通过按钮的方式轻易地创建、切换分支、cherry pick、merge等
操作。对比分支、查看未提交的修改……还有许多可定制的扩展设置。
5、SQLTools — Database tools通过 VSCode 管理数据库的工具。它支持许多驱动程序,你可以使用它来做很多事情,例如连接资源管
理器、查询运行程序、智能感知、书签、查询历史记录。
6、Code Runner 快速地书写代码并且执行,而无需设置环境配置工程之类的。 7、vscode-icons 让 vscode 资源树目录加上图标 8、Office Viewer 9、Browser Preview 用于预览html文件 10、Postcode 11、Rest Client 使用 REST API 的时候,经常需要发送一些样例数据对 API 进行测试,使用 Rest Client插件直接在编辑器里发送 REST 请求。 12、Jupyter 通过在 VS 代码中预览 Jupyter 笔记本来为数据科学工作流增压的扩展。 13、LiveCode for python我们不需要执行Python脚本,该插件会实时展示你的每一个变量值,且能够识别print()并自动打印,是不是看上去很
舒服,这种交互式的体验对于刚接触Python的同学将会更加友好!
14、Partial Diff---文件比较是一种即常用有实用的一项功能,例如,我们想查看哪里修改了代码、查看输出的日志信息有什么区别等等,如果用
肉眼逐个词的去分辨,显然是无法承受的。
15、Python Environment Manager---python虚拟环境管理工具 16、CodeGeeX CodeGeeX是开源的,除了常规的根据上下文和提示生成代码的功能以外,CodeGeeX还特别地具有代码跨语言翻译功能,譬如将python翻译为js

 

二、常用第三方包

Psutil---是用来获取操作系统监控以及进程管理的

Fabric---在paramiko的基础上做了更高一层的封装,操作起来更加简单。windows向windows连接(文件传发)以及,linux向windows连接(文件传发)

fabric连接windows出现无法连接时,先检查windows上是否安装好了ssh

Watchdog------监视文件系统改动


======================================================================

loguru---日志

re---正则

Pytest--测试框架

pretty_errors---更好的错误输出,使用时只需导入即可,无需再做其它操作,通过这条命令你可以安装它$ pip install pretty_errors

pyecharts---可视化图表设计,用于数据可视化的Python库

Pandas----在数据操作和数据分析方面Pandas绝无敌手,Pandas是用Python语言编写的,主要用于数据操作和数据分析。
openpyxl---用于读取/写入 Excel 2010 xlsx/xlsm/xltx/xltm 文件。

NumPy(Numerical Python)---是一个用于科学计算的强大 Python 库,专注于高效处理多维数组和矩阵运算。它提供了丰富的数学函数、随机数生成、线性代数、傅里叶变换等功能,广泛应用于数据科学、机器学习和科学研究。

Plotly---是一个开源的交互式和Python图形库,可以创建能在仪表板或网站中使用的交互式图表(可以将它们保存为html文件或静态图像)。Plotly基于plotly.js,Plotly的强项是制作交互式图 ,有超过30种图表类型, 提供了一些
在大多数库中没有的图表 ,如等高线图、树状图、科学图表、统计图表、3D图表、金融图表等。plotly绘制的图能直接在jupyter中查看,也能保存为离线网页 Pyecharts
---是基于 Echarts 开发的,是一个用于生成 Echarts 图表的类库。Echarts 是百度开源的一个数据可视化 JS 库,凭借着良好的交互性,精巧的图表设计,得到了众多开发者的认可。更重要的是,该库的文档全部由中文撰写, 对英文不是很好的开发者尤其友好。而Pyecharts,实际上就是 Echarts 与 Python 的对接。 Pillow Pillow是基于PIL模块 fork 的一个派生分支,PIL是一个强大的、方便的 python 图像处理库,功能非常强大,不过 Python 2.7 以后不再支持。 但如今Pillow已经发展成为比PIL本身更具活力的图像处理库。pip install pillow OpenCV--通过cv2 与 NumPy 模块进行的图像处理。opencv读入的图片已经是一个numpy矩阵了。在图像操作与处理上比Pillow更先进.pip install opencv-python EasyOCR--- 是一个功能强大且开源、易于使用的 OCR 库,适用于各种文字识别任务,包括文档扫描、图像处理、自然语言处理等。它可以帮助开发者快速实现文字 识别功能,并应用于各种应用领域。 yagmail---如果使用yagmail,发送一个带附件的邮件,只需要2行代码: Beautiful Soup---可以从HTML或XML文件中提取数据,可为被解析的页面创建解析树,从而用于从web页面中提取数据。

Crawl4AI 是一款专为AI开发者设计的网页爬虫工具它不仅速度快、功能强大,还支持灵活的部署方式,是开发者们的理想选择。pip install -U crawl4ai 如果遇到浏览器相关问题,可
以手动安装Playwright:python -m playwright install --with-deps chromium Scrapy
---可有效用于网页抓取的Python库。它是一个开源的协作框架,用于从网站中提取所需数据。使用起来快捷简单。 arrow--- 更好的 Python 日期时间操作类库 Streamlit---是一个神器,它仅仅用几行代码就实现了前后端的交互,把Python程序轻松的展现到前端web页面上。 Tenacity---Python中最强大的错误重试库 APScheduler----是一个Python库,支持对任务的增删改查(持久化),也能很好地支撑定时任务的执行。它相对来说比较轻量,不像celery那么复杂,也不 像schedule那么简陋。ApScheduler算得上是咱们执行定时任务的不二之选了。 pyyaml ---操作yaml配置文件 pandas_alive---Pandas_Alive,它以 matplotlib 绘图为后端,不仅可以创建出令人惊叹的数据动画可视化,而且使用方法非常简单。 Pyautogui---Pyautogui是能够支持多个平台。Pyautogui学习起来比较简单,完全模拟鼠标键盘的行为;但是采用 xy 轴的方式定位桌面元素。 PyTorch ----深度学习框架,研究人员正逐渐放弃TensorFlow,PyTorch类似于numpy,非常Python化,很容易就能与Python生态系统的其余部分集成。 polars----优势是运行速度快,尤其是百万级以上数据,其他场景还是pandas有优势。 Lxml---比BeautifulSoup快8倍!高性能解析库 LangExtract---使用大语言模型从非结构化文本中提取结构化信息的 Python 库,具备精确的源定位和交互式可视化功能。 pip install langextract Pyobjus---由Kivy社区维护,对那些希望利用Python的简洁性来操控Objective-C的强大功能的人们。它基于MIT许可协议发布,允许你在遵守简单条款的前提下自由地使 用、修改和分发这个库。Pyobjus让你能够轻松调用Objective-C框架中的方法,大大扩展了Python的应用场景到iOS和macOS原生API的世界。 PyJNIus---由Kivy社区维护,对那些希望利用Python的简洁性来操控Java本地接口将Java类作为Python类访问的Python模块。大大扩展了Python的应用场景到Android的世界。 PyCGraph 搭建一个非常简单的 pipeline 流程 line_profile--能对函数逐行分析,是最强大性能分析工具之一。 分为三个步骤: import line_profiler 给函数加 上 @profile 这个装饰器 在命令行里面输入 kernprof -v -l xxx.py

 

三、关键字

查看所有的关键字: help("keywords")
查看系统中所有的模块(包括自带和第三方):help('modules')
查看某模块说明: help("XXX")
查看某模块的属性和方法: dir(XXX)
查看系统内置内的属性和方法: dir(__builtins__) / dir(builtins)

用双下划线开头且结尾的变量,在 Python 中被称为内置变量,常见的有如下:
__file__ 获取当前运行的py文件所在的目录
__doc__ 函数、或者文档的注释
__package__ 输出对应函数属于哪个包 . admin.__package__
__name____若是在当前文件,__name__ 是__main__。若是导入的文件,__name__是模块名。
__all__ 结果是一个列表,存储的是当前模块中一些成员(变量、函数或者类)的名称。
没有括号的就是返回了对函数fun的引用, 带括号的fun() 指的是对函数求值的结果
Python对大小写十分敏感,如果大小写错误,会报错
break意思为结束整个循环
continue意思为结束当前循环进入下一个循环
return 结束程序

四、python包

1、pip

从指定源安装:pip install 模块名 -i https://pypi.douban.com/simple (注意后面要有/simple目录)

pip install cchardet #不指定版本号,安装可用的最新版本(版本范围符号:==、>=、<=、>、<。)
pip install -v requests==2.7 #指定版本号2.7
pip install -v requests>2.0,<3.0 #(2.0,3.0)之间的最新版本

显示安装包信息:pip show 模块名
显示安装包信息:pip show -f 包名
列出已安装的包:pip list
搜索包:pip search 模块名
卸载包:pip uninstall 模块名
查看可升级的包:pip list -o
升级包:pip install --U 模块名
升级所有包:pip-review --local --interactive (借助模块pip-review pip install pip-review)

2、依赖包清单

使用pipreqs为当前的Python项目生成所有依赖包的清单requirements .txt
# 安装
pip install pipreqs

#装好之后cmd到项目路径下,在项目根目录下执行
pipreqs ./ --encoding=utf8 --force     #--encoding=utf8 为使用utf8编码,不然可能会报错。--force 强制执行,当生成目录下的requirements.txt存在时覆盖。

或者直接用python生成。  generate_lib.py

import os

new_path=os.path.dirname(__file__)
os.chdir(new_path)

os.system(f'pipreqs ./ --encoding=utf8 --force')

使用requirements.txt安装依赖的方式:pip install -r requirements.txt

也可以用python安装。install_lib.py

import os

new_path=os.path.dirname(__file__)
os.chdir(new_path)

#指定阿里源进行安装
os.system('pip install -r requirements.txt -i  https://mirrors.aliyun.com/pypi/simple')

批量卸载安装包

pip uninstall -y -r requirements.txt   #批量静默卸载,即不用回答yes

 

五、库(模块)调用

在程序的开发过程中,随着程序代码越写越多,在一个文件里代码会越来越不容易维护。为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少。在Python中一个.py文件就称之为一个模块(Module)。模块也被叫做库。模块用来从逻辑上组织Python代码,是.py结尾的python文件。包用来从逻辑上组织模块的,包和一般的文件夹没什么区别,关键是包文件夹下必须包含一个__init__.py,表明这是一个包。包的命名规范与模块相同。

 函数---->类---->模块(.py文件)---->包

1、模块的安装

方法1:单文件模块

直接把文件拷贝到 $python_dir/Lib

方法2:多文件模块,带setup.py

下载模块包进行解压,进入模块文件夹,执行:
python setup.py install

setup.py文件的编写(setup.py中主要执行一个 setup函数。可网上查找。)

2、导入模块

1)、python调用模块的步骤:

1) 检索可用路径

2)根据路径的优先级来查找模块,其中当前路径的优先级最高

由此可知要使我们的模块可以被python检索到,模块就必须放在可用路径内

1)\lib\site-packages为标准化的第三方模块存放路径。

2)可将将自己写的exp.py 文件放到sys.path列表中的目录里(如site-packages目录),使用时采用 import exp 导入。

2)、导入

import module 导入模块,推荐import来去导入因为这样可以使你的程序更加易读,也可以避免名称的冲突
import module1,module2 导入多个模块
from module import * 从模块导入所有方法,采用该方式则可在代码中直接使用方法名。
from packs import hello 从包中导入模块

3)、同级目录下的调用

--file
   |--test1.py
   |--test2.py

若在程序test2.py中导入模块test1, 则直接使用

import test1
test1.fun1()
#或
from test1 import fun1
fun1()

4)、调用子目录

--file
    |--top.py
    |--lib
       |--mod1.py

要在top.py中导入模块mod1.py :

from lib import mod1
mod1.fun()

5)、子目录调用

--file
    |--top.py
    |--lib
       |--mod1.py

要在mod1.py 中导入模块top.py的test1 :

import os,sys
sys.path.append(os.path.dirname(os.path.dirname(__file__))) #将上级目录加入
from top import test1

6)、跨目录调用

file0
   |--file1
      |--test1.py
   |--file2
      |--test2.py

现在要在test2.py中导入test1.py的模块,需要增加调用文件的目录,可以是相对路径也可以是绝对路径。

import os,sys
sys.path.append(os.path.dirname(os.path.dirname(__file__))) #将上级目录加入
from file1 import test1

  

六、异常

首先,执行try子句,如果没有异常发生,忽略except子句,try子句执行结束。如果在执行try子句的过程中发生了异常,那么try子句余下的部分将被忽略。如果异常的类型和 except 之后的名称相符,那么对应的except子句将被执行。最后执行 try 语句之后的代码。如果一个异常没有与任何的except匹配,那么这个异常将会传递给上层的try中。

 

七、类概述

面向对象重要的概念就是类(Class)和实例(Instance),类是抽象的模板,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。类可以起到模板的作用,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的init方法,在创建实例的时候,就把属性绑上去。传递给类的函数都是由类的构造函数来处理的。与类和实例无绑定关系的function都属于函数(function);与类和实例有绑定关系的function都属于方法(method)。

(1)、__init__方法的第一参数永远是self,表示创建的类实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。

(2)、有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但self不需要传。这里self就是指类本身。

(3)、和普通数相比,在类中定义的函数第一参数永远是类的本身实例变量self,并且调用时,不用传递该参数。除此之外,类的方法(函数)和普通函数没啥区别。

(4)、如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线,就变成了一个私有变量(private)

class Person():
    def __init__(self):
        self.eyes = "眼睛"
        self.nose = "鼻子"
        self.mouth = "嘴巴"

kele1 = Person()
kele2 = Person()
print(kele1)
print(kele2)
''' <__main__.Person object at 0x0000018E1BBCCE50> <__main__.Person object at 0x0000018E1BC39910> '''

在默认情况下类创建出来的各个对象都是不一样的,如果我们想一个类创建出来的对象都是一样的,那就需用到 new 方法。

class Person():
    instance = None
    def __new__(cls, *args, **kwargs):
        if not cls.instance:
            cls.instance = super(Person, cls).__new__(cls, *args, **kwargs)
        return cls.instance

    def __init__(self):
        self.eyes = "眼睛"
        self.nose = "鼻子"
        self.mouth = "嘴巴"

kele1 = Person()
kele2 = Person()
print(kele1)
print(kele2)
''' <__main__.Person object at 0x000002BFC93E1520> <__main__.Person object at 0x000002BFC93E1520> '''
在 Python 中,类相对于函数有以下好处:
1 代码组织和封装
类可以将数据(属性)和操作数据的方法组合在一起,让代码结构更加清晰有条理。例如,在一个模拟汽车的程序中,汽车的品牌、颜色等属性与
启动、加速、刹车这些方法可以封装在一个 “汽车” 类中,而不是分散的函数。函数主要是执行特定任务的代码块,侧重于操作,但对于相关的数据管理不够方便。
2 状态保持
类的对象可以保存自己的状态。以游戏角色为例,每个角色对象有自己的等级、生命值、经验值等属性,这些属性的值会随着游戏的进行而改变,
通过类可以很方便地管理这些状态。而函数通常在执行完后就结束了,很难持续保存这种变化的状态。
3 继承和复用
类支持继承,能够创建一个新类(子类)从现有类(父类)继承属性和方法。比如,有一个 “动物” 类,“狗” 类和 “猫” 类可以继承 “动物” 类
的属性(如体重、年龄)和方法(如移动),并且还能添加自己特有的属性和方法,这样可以减少代码的重复编写。函数虽然可以在不同的程序中调用,但很难像类一样实现这种层次化的复用。
#####1
class person:
    def __init__(self,name,age):
        self.name=name
        self.age=age
lisi=person("lisi",20)
print(lisi)  #<__main__.person object at 0x000001E019714EC0>

#####2
class person:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def print_info(self):
        return f"name:{self.name},age:{self.age}"
lisi=person("lisi",20)
print(lisi.print_info())  #name:lisi,age:20


####3
class person:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __str__(self):
        return f"name:{self.name},age:{self.age}"
lisi=person("lisi",20)
print(lisi)  #name:lisi,age:20

  

八、类的属性

1、直接定义在类体中的属性叫类属性,而在类的方法中定义的属性叫实例属性。
2、类数据属性属于类本身,可以通过类名进行访问/修改;
3、类数据属性也可以被类的所有实例访问/修改;
4、在类定义之后,可以通过类名动态添加类数据属性,新增的类属性也被类和所有实例共有;
5、实例数据属性只能通过实例访问;
6、在实例生成后,还可以动态添加实例数据属性,但是这些实例数据属性只属于该实例

class Student(object):
 
    count = 0
    books = []
    sex = 'man'
 
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def initStuff(self):
        self.x = 88

print(Student.sex) #man  Student可以访问自身属性
Student.sex='women'
print(Student.sex) #women Student可以修改自身属性

print(Student.x)    # Student不能访问和修改name、age、x,他们是实例属性
Student.initStuff() # Student不能访问方法。若要可以访问需方法为类方法,即@classmethod所修饰的方法

#实例1
tester=Student('TTT',23)

print(tester.name)#TTT

tester.sex='none'
print(tester.sex) #none 实例可以访问和修改类属性,但改的不是类属性本身,而是实例属性这个拷贝

tester.name='uuu'
print(tester.name)#uuu

#实例2
dever=Student('SSS',26)
print(dever.sex) #women 实例可以访问和修改类属性

通过内建函数dir(),或者访问类的字典属性__dict__,这两种方式都可以查看类或者实例有哪些属性。

__xxx__ 表示特殊变量,一种约定用来表示Python内部的名字,可以直接访问,我们自己的变量一般不要用这种方式
__xxx 表示是私有变量,外部不能访问
_xxx 表示外部是可以访问,但按照约定俗成的规定应将其视为私有变量,不随意访问,方法或属性不会被 from module import * 导入。

class Student(object):

    def __init__(self, name, score,age):
        self.__name = name
        self.__score = score
        self.age = age

    def print_score(self):
        print(f"{self.__name}:{self.__score}")

student = Student('Hugh', 99,23)
print(student.age) #23 print(student.__name) #__name是私有实例属性,在外部不能访问

如果外部代码要获取或修改name和score怎么办?可以给Student类增加get_name和get_score这样的方法:

class Student(object):

    def __init__(self, name, score,age):
        self.__name = name
        self.__score = score
        self.age = age

    #使外部代码可访问__name
    def get_name(self):
        return self.__name
    
    #使外部代码可访问__score
    def get_score(self):
        return self.__score

    #使外部代码可修改__score
    def set_score(self, score):
        self.__score = score

#实例
student = Student('Hugh', 88,23)
print(student.age) #23 print(student.get_name())#Hugh student.set_score(100) print(student.get_score())#100

九、类的方法

python的面向对象中有3种类型的方法:实例方法、类方法、静态方法。

  • 类方法: 是类对象的方法,在定义时需要在上方使用 @classmethod 进行装饰,形参为cls,指代类本身。该方法的第一个参数是类名,调用时也需要指定类。
  • 实例方法: 是类实例化对象的方法,只有实例对象可以调用,形参为self指代实例本身。在类里每次定义实例方法的时候都需要指定实例(该方法的第一个参数,名字约定成俗为self)。
  • 静态方法: 静态方法通过@staticmethod装饰器定义,主要用于封装与类逻辑相关但不需要访问类或实例状态的功能。静态方法明确表示其不依赖类或实例属性,适合处理与业务逻辑解耦的操作(如数据清洗、格式转换)。不通过self传递。一般如果一个方法不需要用到self,那么它就适合用作静态方法。之所以需要静态方法,是因为有时候需要将一组逻辑上相关的函数放在一个类里面,便于组织代码结构。

实例可以调用实例方法,类方法,静态方法。
类可以调用类方法,静态方法。
类方法和静态方法只能操作类属性。

class test_2:
    #实例方法
    def m1(self, arg1):
        print(arg1)
 
    #类方法,因为@classmethod已经将m2包装成了类方法,所以m2的第一个self参数将总是代表类名。
    @classmethod
    def m2(self, arg1):
        print(arg1)
 
    #静态方法
    @staticmethod
    def m3(arg1, arg2):
        print(arg1, arg2)
 
c = test_2()
 
# 用实例名来访问。调用实例方法
c.m1("hello m1")  # hello
# 用实例名来访问。调用类方法。
c.m2("hello m2")  # hello
# 用实例名来访问。调用静态方法。
c.m3("hello", "m3")  # hello world
 
# 用类来访问。调用实例方法。
test_2().m1("你好 m1") #你好 m1 不能用类名直接访问,要使用类名加括号
# 用类名来访问。调用类方法。
test_2().m2("你好 m2") #你好 m2  可以用类名直接访问,也可以使用类名加括号
# 用类名来访问。调用静态方法。
test_2().m3("你好","m3") #你好 m3  可以用类名直接访问,也可以使用类名加括号

 

十、类的方法的调用

1.类的内部调用:self.<方法名>(参数列表)。
2.在类的外部调用:<实例名>.<方法名>(参数列表)。
注意:以上两种调用方法中,提供的参数列表中都不用包括self。

第一种:class内部函数与函数之间的调用(a调用b,只需在a中加上 self.b即可)

class Student(object):
    count = 0
    books = []
    sex = 'man'
 
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def chg(self):
        pp=self.sex #调用类属性
        print('函数chg')
        print(pp)

    def prt(self):
        self.chg() #调用类方法

tester=Student('xiaoming',24)
tester.prt() #函数chg  man

第二种:Class之间函数的调用关系

#方法一:在Class B的函数中声明Class A的对象a,然后用对象a来调用Class A的函数a()
class A():  
    def __init__(self,parent):  
        self.parent = parent  
  
    def a(self):  
        print('Class A')

class  B():  
    def fuction(self):  
        a = A(None)  
        a.a()  

if __name__ == '__main__':  
    b = B()  
    b.fuction()   #Class A


#方法二:在Class B的__init__()中将Class A和Class B产生关联。
class A():  
    def __init__(self,parent):  
        self.parent = parent  
  
    def a(self):  
        print("Class A" ) 
  
class B(object):  
    def __init__(self,object):  
        self.object = object  
        self.object.a()  
  
    def b(self):  
        print("Class B" )
  
if __name__ == '__main__':  
    a = A(None)  
    b = B(a)  
    b.b()  #Class A Class B

#方法三: 直接在Class B中声明Class A的对象,该对象是Class B的self.A_object。
class A():  
    def __init__(self,parent):  
        self.parent = parent  

    def a(self):  
        print("Class A" )
  
class B(object):  
    def __init__(self):  
        self.A_object = A(None)  
        self.A_object.a()  
  
    def b(self):  
        print("Class B")
  
if __name__ == '__main__':  
    b = B()  
    b.b()  #Class A  Class B

 

十一、面向对象三大特性(封装,继承,多态)

1)封装:将代码写到类里面即是封装,并且封装还可以给属性或者方法设置权限。在上述代码中已经使用了封装的特性。
2)继承:指的是类当中的从属关系,子类自动拥有父类所有的属性和方法。所有的类都默认继承Object类

#单继承:只继承一个父类。
class Father():
    def __init__(self):
        self.name= "可乐家族"
 
    def get_name(self):
        print(self.name)
 
class Son(Father):
    pass
 
son= Son()
son.get_name()# 可乐家族
 

#多继承:子类同时继承多个父类。如果继承的父类当中拥有相同的属性或者方法,那么优先继承第一个父类的属性和方法。
class Father():
 
    def __init__(self):
        self.name= "可乐家族"
 
    def get_name(self):
        print(self.name)
 
class Mother():
 
    def __init__(self):
        self.name= "雪碧家族"
 
    def get_name(self):
        print(self.name)
 
class Son(Mother, Father):
    pass
 
son= Son()
son.get_name()# 雪碧家族


#重写父类的方法,继承中支持子类对父类的方法进行重写。子类重写父类方法,但是还需要调用父类的同名方法时,可使用super()去调用父类的方法。
class Father:
    def __init__(self):
        self.name = "可乐家族"

    def get_name(self):
        print(self.name)

class Mother:
    def __init__(self):
        self.name = "雪碧家族"

    def get_name(self):
        print(self.name)

    def add_water(self):
        print("生命之源")


class Son(Mother, Father):
    def get_name(self):
        print("碳酸家族")

    def get_old(self):
        super().get_name()  #必须在子类的定义中才能调用

son = Son()

son.get_name()  # 碳酸家族      重写父类的方法
son.add_water()  # 生命之源     未重写父类方法,可直接调用
son.get_old()  # 雪碧家族
3)多态:多个子类分别重写了父类的某方法,调用这些子类的该方法,有不同的结果。多态可以使得代码变得更加灵活,更适应的业务场景多。
class Person:
    def get_sex(self):
        print("人")
​
class Man(Person):
    def get_sex(self):
        print("男人")
​
class Women(Person):
    def get_sex(self):
        print("女人")
​
man = Man()
women = Women()
man.get_sex() #男人 women.get_sex() #女人
 

十二、类常用装饰器

@dataclass

dataclass是从Python3.7版本开始,作为标准库中的模块被引入,dataclass也逐步发展和完善,为Python开发者提供了更加便捷的数据类创建和管理方式。dataclass的主要功能在于帮助我们简化数据类的定义过程。

from dataclasses import dataclass

@dataclass
class CoinTrans:
    id: str
    symbol: str
    price: float
    is_success: bool
    addrs: list

再次运行:

if __name__ == "__main__":
    coin_trans = CoinTrans("id01", "BTC/USDT", "71000", True, ["0x1111", "0x2222"])
    print(coin_trans)

得到如下结果:

CoinTrans(id='id01', symbol='BTC/USDT', price='71000', is_success=True, addrs=['0x1111', '0x2222'])

不需要__init__,也不需要__str__,只要通过 @dataclass装饰之后,就可以打印出对象的具体内容。

2.1. 默认值

dataclass装饰器的方式来定义类,设置默认值很简单,直接在定义属性时就可以设置。

@dataclass
class CoinTrans:
    id: str = "id01"
    symbol: str = "BTC/USDT"
    price: float = "71000.8"
    is_success: bool = True
    addrs: list[str] = ["0x1111", "0x2222"]

if __name__ == "__main__":
    coin_trans = CoinTrans()
    print(coin_trans)

运行之后发现,在addrs属性那行会报错:

ValueError: mutable default <class 'list'> for field addrs is not allowed: use default_factory

大概的意思就是,list作为一种可变的类型(引用类型,会有被其他对象意外修改的风险),不能直接作为默认值,需要用工厂方法来产生默认值。
其他字符串,数值,布尔类型的数据则没有这个问题。

我们只要定义个函数来产生此默认值即可。

def gen_list():
    return ["0x1111", "0x2222"]

@dataclass
class CoinTrans:
    id: str = "id01"
    symbol: str = "BTC/USDT"
    price: float = "71000.8"
    is_success: bool = True
    addrs: list[str] = field(default_factory=gen_list)

if __name__ == "__main__":
    coin_trans = CoinTrans()
    print(coin_trans)

再次运行,可以正常执行:

CoinTrans(id='id01', symbol='BTC/USDT', price='71000.8', is_success=True, addrs=['0x1111', '0x2222']

2.2. 隐藏敏感信息

我们打印对象信息的时候,有时执行打印其中几个属性的信息,涉及敏感信息的属性不希望打印出来。
比如,上面的对象,如果不想打印出is_successaddrs的信息,可以设置repr=False

@dataclass
class CoinTrans:
    id: str = "id01"
    symbol: str = "BTC/USDT"
    price: float = "71000.8"
    is_success: bool = field(default=True, repr=False)
    addrs: list[str] = field(default_factory=gen_list, repr=False)

再次运行后显示:

CoinTrans(id='id01', symbol='BTC/USDT', price='71000.8')

2.3. 只读对象

数据分析时,大部分下情况下,原始数据读取之后是不能修改的。
这种情况下,我们可以用dataclassfrozen属性来设置数据类只读,防止不小心篡改了数据。

未设置frozen属性之前,可以随意修改对象的属性,比如:

if __name__ == "__main__":
    coin_trans = CoinTrans()
    print(f"修改前: {coin_trans}")
    coin_trans.symbol = "ETH/USDT"
    print(f"修改后: {coin_trans}")

运行结果:

修改前: CoinTrans(id='id01', symbol='BTC/USDT', price='71000.8')
修改后: CoinTrans(id='id01', symbol='ETH/USDT', price='71000.8')

设置frozen属性之后,看看修改属性值会怎么样:

@dataclass(frozen=True)
class CoinTrans:
    id: str = "id01"
    #... 省略 ...

再次运行,会发现修改属性会触发异常。

修改前: CoinTrans(id='id01', symbol='BTC/USDT', price='71000.8')
Traceback (most recent call last):
  File "D:\projects\python\samples\data_classes\main.py", line 66, in <module>
    coin_trans.symbol = "ETH/USDT"
    ^^^^^^^^^^^^^^^^^
  File "<string>", line 4, in __setattr__
dataclasses.FrozenInstanceError: cannot assign to field 'symbol'

2.4. 转化为元组和字典

最后,dataclasses模块还提供了两个函数可以很方便的将数据类转换为元组字典
这在和其他分析程序交互时非常有用,因为和其他程序交互时,参数一般都用元组或者字典这种简单通用的结构,
而不会直接用自己定义的数据类。

from dataclasses import dataclass, field, astuple, asdict

if __name__ == "__main__":
    coin_trans = CoinTrans()
    print(astuple(coin_trans))
    print(asdict(coin_trans))

运行结果:

('id01', 'BTC/USDT', '71000.8', True, ['0x1111', '0x2222'])
{'id': 'id01', 'symbol': 'BTC/USDT', 'price': '71000.8', 'is_success': True, 'addrs': ['0x1111', '0x2222']}
 

@staticmethod
将类中的方法装饰为静态方法,即类不需要创建实例的情况下,可以通过类名直接引用。到达将函数功能与实例解绑的效果。

class TestClass:
    name = "test"
  
    def __init__(self, name):
        self.name = name
  
    @staticmethod
    def fun(self, x, y):
        return  x + y
  
cls = TestClass("felix")
print ("通过实例引用方法")#通过实例引用方法
print(cls.fun(None, 2, 3))# 参数个数必须与定义中的个数保持一致,否则报错   5
  
print("类名直接引用静态方法")  #类名直接引用静态方法
print(TestClass.fun(None, 2, 3)) # 参数个数必须与定义中的个数保持一致,否则报错   5

@classmethod
标示方法为类方法的装饰器,类方法的第一个参数是一个类,是将类本身作为操作的方法。类方法被哪个类调用,就传入哪个类作为第一个参数进行操作。

class Car(object):
    car = "audi"
  
    @classmethod
    def value(self, category): # 可定义多个参数,但第一个参数为类本身
        print("%s car of %s" % (category, self.car))
  
class BMW(Car):
    car = "BMW"
  
class Benz(Car):
    car = "Benz"
  
print ("通过实例调用")
baoma = BMW()
baoma.value("Normal") # 由于第一个参数为类本身,调用时传入的参数对应的是category     Normal car of BMW
  
print ("通过类名直接调用")
Benz.value("SUV")  #SUV car of Benz
 
 
posted @ 2016-07-24 01:14  liangww  阅读(204)  评论(0)    收藏  举报