本篇目录
一、类的创建
定义:类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。
1.1 类创建
- 代码示例
#类名第一个字母大写 class Person: """此处放置该类的介绍和描述, print(Person.__doc__)查看""" # 属性:用名词 # private变量:双下划线,仅当前类方法可调用 __name = 'chuck' # protect变量:仅子类与当前类方法可调用 _weight = 80 # public变量:公用,对象.变量名 即可调用 height = 176 #类内方法:用动词 # 实例初始化:python内建魔法函数,双侧双下划线,见后续解释 # self:若需用本类方法或变量,需传入self def __init__(self , name): # __init__方法不能包含return语句 self.__name = name # private方法:仅当前类可调用,双下划线 def __checkSth(): # pass:若需要暂时搁置细化函数逻辑功能,可只写此关键字 print("checkSth is called") # protect方法:仅当前类和派生类可调用,单下划线,实际跟public方法 # 无使用功能差别,只给编程提供标识的吧 def _checkSmb(): print("_checkSmb is called") # public方法:调用无限制,若需用本类方法或变量,需传入self def showDetails(self): print('name is',self.__name,'hight is',self.height)
1.2 类的实例化
- 代码示例
# 创建实例p:数据类型为class Person, # 自动调用魔法方法__init__方法初始化类对象 # __init__方法隐含调用__new__方法 p = Person('duke') # 调用类的方法 p.showDetails() >>>'name is duke height is 176' # 可见protect并不能约束类外调用 p._checkSth() >>> checkSth is called p.__checkSmb() >>> AttributeError: 'Person' object has no attribute '__checkSth' # 类外使用类内的public变量:建议还是通过类内方法修改 print(p.height) >>>176 # 修改实例属性:仅此实例变化,其他实例及类本身不变 p.height = 180 print(p.height) >>>180 # 删除实例属性,类的属性就恢复了 del p.height print(p.height) >>>176 # 可见protect并不能约束类外调用 print(p._weight) >>> 80 # 私有变量调用报错 print(p.__name) >>> AttributeError: 'Person' object has no attribute '__name'
二、类继承
2.1 继承
- 继承规则:派生类与基类同名方法,派生类覆盖基类
- 继承写法
class A: def __init__(self): print("INIT A") class B(A): def __init__(self, y): print("INIT B y is " + y) # 调用基类方法:此处调用A的初始化函数 # super方法隐含参数:super(B, self) super().__init__() class C(B): def __init__(self, x, y): print("INIT C x is " + x + ", y is " + y) # 调用B的初始化函数 # super方法隐含参数:super(C, self) super().__init__(y) p = C("A", "B") >>> INIT C x is A, y is B >>> INIT B y is B >>> INIT A
- 判断类关系
# 判断前者是否为后者的派生类 issubclass(B, A) >>> True # 判断实例是否属于某个类 p = B() isinstance(p, A) >>> True isinstance(p, B) >>> True
2.2 类魔法函数
- 概述:写法
__方法名__
,Python的类里提供的,魔法方法会在恰当的时候自动被调用执行,名字固定 - 类魔法函数列表
dir(__build_class__) ['__call__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', \ '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', \ '__init_subclass__', '__le__', '__lt__', '__module__', '__name__', '__ne__', \ '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', \ '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__text_signature__']
2.2.1 init、str、call
- 代码示例
class A: # __init__:类初始化函数,其默认调用__new__ # __del__:当对象被销毁时自动调用 def __init__(self, num = 18): self.num = num # 返回字符串:若无此语句,打印对象内存地址 def __str__(self): return '调用__STR__语句' # 回调函数:实例对象后接小括号触发执行,进阶用法见2.2.6节 def __call__(self): print('调用__call__语句') ############################################ # 调用__str__ p = A() print(p) >>> 调用__str__语句 # 调用__call__ p() >>> 调用__call__语句
2.2.2 比较运算符
- 代码示例
class A: def __init__(self, num=18): self.num = num # 若没有比较运算符重载语句,则报错 # ==和!=若无比较运算符重载语句,比较类对象内存地址 def __gt__(self, other): return self.num > other.num ############################################ p1 = A(10) p2 = A(11) print(p1 > p2) >>> False
比较运算符:相等== eq、大于等于>= gt、不等于 != ne、小于等于<= le、大于 > gt、小于< lt
2.2.3 算数运算符
- 代码示例
class A: def __init__(self, num=18): self.num = num # 若没有算数运算符重载语句,则报错 def __add__(self, other): return self.num + other ############################################ p1 = A(10) print(p1 + 1) >>> 11
算数运算符:加+add、减-sub、乘*mul、除/truediv、取余%mod、指数**pow
2.2.4 类型转换运算符
- 代码示例
class A: def __init__(self, num=18): self.num = num def __float__(self): return self.num * 1.0 ############################################ p1 = A(10) print(float(p1))
类型转换运算符:整型int、浮点型float、字符串str、布尔型bool
2.2.5 实例中迭代属性
- 代码示例
class A: def __init__(self, num): self.num = num # 迭代器语句:若有next语句则返回self即可 def __iter__(self): return self # 生成器的next语句 def __next__(self): # 生成器越界语句 if self.num >= 20: raise StopIteration self.num += 1 # 注意返回值 return self.num ############################################ p = A(10) # 使用迭代器详见上一篇 print(list(p)) >>> [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
2.2.6 call实现装饰器
- 装饰器定义及函数装饰器详见上一篇
- 不带参数装饰器
class Decorator: def __init__(self, func): self._func = func def __call__(self, *args, **kwargs): print("此处为新增的逻辑内容") # 被装饰函数 return self._func(*args, **kwargs) ############################################# # 等价于Decorator(test) @Decorator def test(x): print("传入test函数x:", x) if __name__ == '__main__': test(1) >>> 此处为新增的逻辑内容 >>> 传入test函数x: 1
- 带参数装饰器
class Decorator: def __init__(self, state): # 此处接收装饰器传入参数,任何位置都可以使用 self._state = state def __call__(self, func): self.func = func return self.__callback def __callback(self, *args, **kw): print("装饰器传入的参数:", self._state) print("此处为新增的逻辑内容") return self.func(*args, **kw) ################################################### # @行意思:Decrator('execute')(test)(x) @Decorator('execute') def test(x): print("传入test函数x:", x) if __name__ == '__main__': test(1) ################################################### >>> 装饰器传入的参数: execute >>> 此处为新增的逻辑内容 >>> 传入test函数x: 1
三、模块、包
3.1 模块
- 定义:python文件即为模块,如
hello.py
,hello
为模块名,可以在其他程序中导入调用 - 标准写法:hello.py
# 开头两行注释为必要注释: # 首行注释:Linux环境中可使用命令:以 ./程序文件名 的方法执行 # 次行注释:表示.py文件本身编码使用UTF-8 ########################################################## # !/usr/bin/env python3.6 # -*- coding: utf-8 -*- # 显示方法:help(hello)或hello.__doc__显示 ''' 模块的功能及变量说明 ''' # 使用__author__变量把作者写入模块 __author__ = 'duke' # 模块语句(含from...improt、类定义、函数定义、全局变量定义) # 主语句:当模块为程序入口时,其__name__为'__main__' # 否则__name__为模块名,此处为'hello' if __name__=='__main__': # 测试函数,像自动化输入一些参数测试模块 test()
- 导入及调用模块
# 方法1:导入模块,模块名不加后缀,中括号为可选 import 模块名 [as 别名] # 方法2:导入模块中的特定函数、类 from 模块名 import 函数名或类名 # 方法3:相对路径导入,有限制,见3.3节包相对导入 from .. import 模块名 # 调用模块中函数 变量 = 模块名.函数名或类名() #方法 1、3 变量 = 别名.函数名或类名() #方法 1 变量 = 函数名或类名() #方法 2
3.2 模块导入示例
- E:\main\main.py
# 两种写法演示 from three import test import three if __name__ == '__main__': print("main path:" + __file__) print("main name:" + __name__) test()
- E:\main\three.py
def test(): # 显示__file__变量所在模块的绝对路径 # 找模块文件夹用 print("three path:" + __file__) # 显示模块名称 print("three name:" + __name__)
- 输出
# win 10 输出 main path:E:/main/main.py main name:__main__ three path:E:\main\three.py three name:three # centos 输出 main path:main.py main name:__main__ three path:/root/main/three.py three name:three # mac 输出 main path:/main/main.py main name:__main__ three path:/main/three.py three name:three
3.3 包
-
定义:一种管理 Python 模块命名空间的组织形式,目的为了模块管理
-
目录结构示意(蓝色为文件夹)
- __ init__.py:包标识文件,可为空,也可以执行包的初始化代码或设置__all__变量
- all变量:在
__init__.py
中定义列表__all__ = ["函数名", "类名"]
,from 包名 import *
会加载此列表
-
系统路径
In [1]: import sys # 包需要在系统搜索路径下,否则会报错 In [2]: sys.path Out[2]: ['/usr/local/bin', '/usr/lib64/python36.zip', '/usr/lib64/python3.6', '/usr/lib64/python3.6/lib-dynload', # 空路径:代表当前执行的程序的**入口程序文件**的父目录 '', '/usr/local/lib64/python3.6/site-packages', '/usr/local/lib/python3.6/site-packages', '/usr/lib64/python3.6/site-packages', '/usr/lib/python3.6/site-packages', '/usr/local/lib/python3.6/site-packages/IPython/extensions', '/root/.ipython']
-
包调用
# 方法1:指定模块,中括号可选 import 包名.模块名 [as f] # 调用包中的函数 f.函数名() 模块名.函数名() # 调用包中的类 f.类名() 模块名.类名() ############################################ # 方法2:指定到模块中的函数、类 from 包名.模块名 import 函数名1,函数名2,类名1 # 调用包中的函数 函数名1() # 调用包中的类 类名1() ############################################ # 方法3:嵌套包 from 包名.子包名1.模块名 import 函数名1,类名1 # 调用包中的函数 函数名1() # 调用包中的类 c = 类名1() ############################################ # 方法4:相对路径导入,常用于子包中 from ..父包名 import 父包中的模块名
3.4 程序模块组织
- 示例架构
3.4.1 同级独立模块导入
- 代码示例
################################# # main.py文件代码内容 # ################################# # 方法1:直接导入模块 import main_bro # 方法2:使用模块别名 from main_bro import test as main_bro_test # 每个模块都是这个写法,都打印模块名字 def test(): print("this is main") if __name__ == '__main__': test() # 方法1 main_bro.test() # 方法2 main_bro_test() ################################ # 输出 >>> this is main >>> this is main_bro >>> this is main_bro
3.4.2 独立模块导入包内模块
- 代码示例
################################# # main.py文件代码内容 # ################################# from pack02 import module_02 from pack02.module_02 import test as module_02_test def test(): print("this is main") if __name__ == '__main__': test() module_02.test() module_02_test() ################################ >>> this is main >>> this is module_02 >>> this is module_02
3.4.3 异包互导
- 代码示例
################################# # main.py文件代码内容 # ################################# from pack01.pack11.pack111.module_111 import test if __name__ == '__main__': test() ################################# # module_111.py文件代码内容 # ################################# from pack02.module_02 import test if __name__ == '__main__': test() ################################ >>> this is module_02
3.4.4 同包 子 导入 父(推荐)
- 代码示例
################################# # main.py文件代码内容 # ################################# from pack01.pack11.pack111.module_111 import test if __name__ == '__main__': test() ################################# # module_111.py文件代码内容 # ################################# from pack01.module_01 import test if __name__ == '__main__': test() ################################ >>> this is module_01
3.4.5 同包 子 导入 父(相对导入)
- 同包 子包 导入 长辈包(相对导入)
################################# # main.py文件代码内容 # ################################# from pack01.pack11.pack111.module_111 import test if __name__ == '__main__': test() ################################# # module_111.py文件代码内容 # ################################# # 代表: 单点--当前文件的父文件夹(省略) # 双点--当前文件的祖父文件夹 # 三点--当前文件的曾祖父文件夹,以此类推无限点下去 # 注意:模块不是路径没有斜杠‘/’,且点紧贴模块名 # 通常不用记,按照点出来的软件提示选即可 from ..module_11 import test # 相对导入,此语句失效,即本程序文件不可直接运行 if __name__ == '__main__': test() ################################ >>> this is module_11
- 适用环境:三层以下,用3.4.4节,超过三层,最深层的可以考虑用相对导入
- 异常
- 不能直接运行,否则报错:
ImportError: attempted relative import with no known parent package
- 不可越顶级包,否则报错:
ValueError: attempted relative import beyond top-level package
越顶级包:即module_01中
from ..main_bro import test
,引用pack02也同样为越级
- 不能直接运行,否则报错:
3.4.6 总结
- 同级模块导入,直接
import 模块名
- 非同级模块导入:直接
from 包名.包名......包名 import 模块
- 深层包或者偷懒:按提示使用
from ..模块名 import 函数名
,尽量少用