[TOC] #### 1. 面向对象 --- 掌握 Python 的面向对象编程(OOP)是从 “写脚本” 迈向 “构建复杂工程” 的必经之路 面向对象编程是一种以 “实体交互” 为核心的编程范式,它将数据(属性)和操作数据的逻辑(方法)绑定成一个独立的对象,从而让代码更加模块化、可维护且易于扩展 ```python # 所有的类名要求首字母大写,多个单词使用驼峰式命名 class Phone: brand = 'huawei' print(Phone) # <class '__main__.Phone'> # 使用类创建对象 yp = Phone() print(yp) # <__main__.Phone object at 0x102ccd550> print(yp.brand) # huawei ``` 核心概念:类与对象 + 类(Class):相当于创建对象的 “图纸” 或 “模板”,它定义了对象将包含的数据和行为 + 对象(Object):根据图纸建造出的 “具体实例”。同一个类可以实例化出无数个对象,每个对象拥有独立的数据空间 基础用法示例: ```python class Dog: # 类属性:所有实例共享 species = "Canis familiaris" # 初始化方法(构造函数):用于初始化对象的属性 def __init__(self, name, age): self.name = name self.age = age # 实例方法:定义对象的行为 def bark(self): return f"{self.name} says woof!" # 创建对象(实例化) my_dog = Dog("Buddy", 3) print(my_dog.name) # 输出: Buddy print(my_dog.bark()) # 输出: Buddy says woof! ``` 类中的四种方法:普通方法、魔术方法、类方法、静态方法 + 类方法:定义需要依赖装饰器 `@classmethod`,类方法参数的不是对象,而是当前类 + 静态方法:定义需要依赖装饰器 `@staticmethod`,静态方法无需传递参数 ```python class User: # 类属性 gender = '男' # 魔术方法(构造函数) def __init__(self, name, age): self.name = name self.age = age # 普通方法 def show(self): print(self.name, self.age) # 类方法: # 1.使用依赖修饰器 @classmethod 定义 # 2.类方法中参数不是一个对象,而是当前类(下方的 cls 参数) # 3.类方法中只可以使用类属性 # 4.类方法中可否使用普通方法?答案:不能 # 类方法作用:因为只能访问类属性和类方法,所以可以在对象创建之前,如果需要完成一些功能 @classmethod def test(cls): print(cls) # <class '__main__.User'> print(cls.gender) # 可以访问类属性 # name 属性在对象中,不在类中 # print(cls.name) # 报错:AttributeError: type object 'User' has no attribute 'name' # print(self.name) # 无法访问对象的属性,会报错 # 静态方法 # 1.使用依赖装饰器 @staticmethod 定义 # 2.静态方法是无需传递参数(cls,self) # 3.同类方法也只能访问类的属性和方法,对象是无法访问的 # 4.加载时机同类方法 @staticmethod def say(): print('这是静态方法') print(User.gender) # 可以访问 u1 = User('liang', 20) u1.show() # 调用类方法 u1.test() User.test() # 调用静态方法 User.say() ``` 类方法和静态方法的区别 不同点: + 装饰器不同 + 类方法是有参数的,静态方法没有参数 相同点: + 只能访问类的属性和方法,对象的属性和方法是无法访问的 + 都可以通过类名调用访问,并且都可以在创建对象之前使用,因为它们不依赖于对象 普通方法与两者区别(不同点): + 普通方法没有装饰器 + 普通方法依赖于对象,因为每个普通方法都有一个 self + 只有创建了对象才可以调用普通方法,否则无法调用 #### 2. 模块的导入和使用 --- 在 Python 中,模块是代码组织的一种方式,把功能相近的函数或类放到一个文件中,一个文件(.py)就是一个模块 这样做的好处: + 提高代码的可复用、可维护性。一个模块编写完毕后,可以很方便的在其它项目中导入 + 解决了命名冲突,不同模块中相同的命名不会冲突 自定义模块,创建文件 `calculate.py`,文件内容: ```python # 限制 from calculate import * 可以导入的成员 __all__ = ['number', 'User'] number = 100 def add(*args): if len(args) > 1: sum = 0 for arg in args: sum += arg return sum else: print('至少传入两个参数') class User: @staticmethod def show(): print('这是 User 类的 show 方法') print('--- 打印数字 ---') if __name__ == '__main__': print(number) print(number) print(number) print('--- 打印数字 / ---') ``` 同级目录下,创建用于测试的文件: ```python ''' 导入模块: 1. import 模块名 模块名.函数 2. from 模块名 import 变量|函数|类 from calculate import number 导入一个模块成员 from calculate import number, User 导入多个模块成员 在代码中可以直接使用模块成员(变量,函数、类) 3. from 模块名 import * 直接导入该模块中的所有成员,在代码中可以直接使用 如果想要限制获取的成员,可以在模块中使用 __all__=[使用*可以访问到的内容] 4. 无论是 import 还是 from 的形式,都会将模块内容进行加载 如果不希望其进行调用,就会用到 __name__ 在自己的模块里面 __name__ 的值是 __main__,如果在其它模块中通过导入的方式调用的话,值为 __模块名__ ''' import calculate from calculate import * from calculate import number, User # 直接使用模块成员 print(User) print(number) list1 = [1, 3, 5] # 使用模块中的内容 # 模块名.函数 sum = calculate.add(*list1) print(sum) # 模块名.变量 print(calculate.number) # 模块名.类 calculate.User.show() ``` #### 3. 包的导入和使用 --- 通过代码示例查看包的导入和使用,目录结构如下: + 目录中创建一个 `__init__.py` 文件(不需要写任何内容),表示当前目录是一个包 ```plaintext ├── article │ ├── __init__.py │ └── models.py ├── user │ ├── __init__.py │ ├── models.py │ └── test.py ├── calculate.py ├── package.py ``` article/models.py ```python class Article: def __init__(self, name, author): self.name = name self.author = author def show(self): print('发表文章名字:《{}》的作者是:{}'.format(self.name, self.author)) ``` user/models.py ```python __all__=['User'] # 只是针对 from 包.模块 import * class User: def __init__(self, username, password): self.username = username self.password = password def login(self, username, password): if self.username == username and self.password == password: print('login success') else: print('login failed') def publish_article(self, article): print(self.username, '发表文章: ', article.name) def show(self): print(self.username) print(self.password) if __name__ == '__name__': # 只有直接运行当前模块才会执行,导入使用不执行 pass ``` user/test.py ```python # 如果想要导入同级目录下的 models 模块中的 User 应该怎么写 ? # 首先,你应该会尝试直接导入 # 这种写法在某些情况下可以运行,但它是极其脆弱且不规范的,有时能成功,有时报错,原因在于:sys.path # import models from user.models import User # from .models import User # 当前目录下的 models 里面的 User 类,这种写法不太推荐 from article.models import Article # 通过导入的 User 类创建的 u = User('admin', '123123') u.show() # 使用其它包的模块 article = Article('人生苦短,我用 Python', 'liang') u.publish_article(article) list1 = [1, 3, 5, 7] from calculate import add print(add(*list1)) ``` calculate.py ```python def add(*args): if len(args) > 1: sum = 0 for arg in args: sum += arg return sum else: print('至少传入两个参数') ``` package.py ```python # 一个包中可以存放多个模块 # 项目 > 包 > 模块 > 类/函数/变量 # 项目中可以有多个包,包中可以有多个模块,模块中可以有多个类/函数/变量 # 1.导入 user 包中的 models 模块 from user import models u = models.User('admin', 123456) u.show() # 2.直接导入 user 包中的 models 模块中的 User 类 from user.models import User u2 = User('liang', 'abcdef') u2.show() # 3.还可以使用 * 将模块中的所有成员导入进来 # 同时也支持在该模块中使用 __all__=[] 限制可使用 * 导入的成员 from user.models import * ``` #### 4. 包的 \_\_init\_\_.py 与 sys 模块 --- 当导入包的时候,默认调用 `__init_.py` 文件,作用: + 当导入包的时候,把一些初始化的函数,变量,类定义在 `__init_.py` 文件中 + 此文件中函数,变量等的访问,只需要通过 `包名.函数` + 结合 `__all__=[通过*可以访问的模块]` 在 `user/__init__.py` 编写以下内容: ```python __all__ = ['models'] print(' user 包的 __init__ 文件') def create_app(): print('create_app 执行') def printA(): print('printA 执行') ``` 在 `user` 包的同级目录创建 `package_init.py`,文件内容如下: ```python # 当导入包的时候,默认调用 __init_.py 文件(以下两种导入方式都会调用 __init_.py) import user from user.models import User # from 模块 import * # 1.表示可以使用模块里面的所有内容 # 2.如果没有定义 __all__ 表示所有的内容都可以访问;如果定义了 __all__ 表示列表中的内容才可以访问 # from 包名 import * # 表示该包中内容(模块)默认不能访问,需要在 __init_.py 中定义 __all__ 暴露的模块 from user import * u = models.User('admin', '123456') u.show() ``` 循环导入:大型的 Python 项目中,需要很多 python 文件,由于架构不当,可能会出现模块之间的相互导入 ```plaintext A 模块: def test(): f() B 模块: def f(): test() ``` 新建两个文件演示循环导入的问题: `loop1.py`: ```python from loop2 import func def task1(): print('01 --- task1') def task2(): print('01 --- task2') func() task2() ``` `loop2.py`: ```python from loop1 import task1 def func(): print('--- 循环导入2里面的func') task1() ``` 解决循环导入问题: + 重新架构(大型项目可能改动较大) + 将导入的语句放到函数里面或模块最后 ```python # 修改 loop2.py,将导入语句放到函数中 def func(): from loop1 import task1 print('--- 循环导入2里面的func') task1() ``` 当你导入一个模块,Python 解析器对模块位置的搜索顺序是: + 当前目录 + 如果不在当前目录,Python 则搜索在 Shell 变量 PYTHONPATH 下的每个目录 + 如果都找不到,Python 会查看默认路径。unix 下,默认路径一般为 `/usr/local/lib/python/` 模块搜索路径存储在 system 模块的 sys.path 变量中,变量里包含当前目录,PYTHONPATH 和由安装过程决定的默认目录 ```python import sys # 查看导入模块时搜索目录路径 print(sys.path) # ['/Users/liang/PyCharmMiscProject/循环导入', ...] print(sys.version) # python 版本 print(sys.modules) # 查看系统模块列表 # 运行命令: python 文件名.py a b print(sys.argv) # 获取执行 python 解释器时传递的参数 ``` #### 5. time 模块和 datetime 模块 --- `time` 模块的常见用法: ```python # 系统内置 time 模块 import time print(time) # 1.获取时间戳 t = time.time() print(t) # 1782739130.504458 # time.sleep(3) # 睡眠3秒 print(time.time()) # 1782739133.508399 # 2.时间戳转为其它形式 # 将时间戳转为字符串 s = time.ctime(t) # Mon Jun 29 21:20:54 2026 print(s) # 将时间戳转为元组 t2 = time.localtime(t) print(t2) # time.struct_time(tm_year=2026, tm_mon=6, tm_mday=29, tm_hour=21, tm_min=22, tm_sec=3, tm_wday=0, tm_yday=180, tm_isdst=0) print(t2.tm_year) # 2026 print(t2.tm_mon) # 6 # 3.元组转为其它形式 # 将元组转为时间戳(秒的格式) t3 = time.mktime(t2) print(t3) # 1782739437.0 # 将元组转为字符串 t4 = time.strftime('%Y-%m-%d %H:%M:%S', t2) print(t4) # 2026-06-29 21:26:49 print(time.strftime('%Y-%m-%d %H:%M:%S')) # 第二个参数不传,默认就是当前时间 # 4.将字符串转为元组形式 t5 = time.strptime(t4, '%Y-%m-%d %H:%M:%S') print(t5) # time.struct_time(tm_year=2026, tm_mon=6, tm_mday=29, tm_hour=21, tm_min=32, tm_sec=17, tm_wday=0, tm_yday=180, tm_isdst=-1) ``` `datetime` 模块的常见用法: ```python # datetime 模块其实就是 time 模块的升级版 ''' datetime 模块: time 时间 date 日期 datetime 日期时间 now() timedelta 时间差 timedelta=(days=3,hours=2) ''' import time import datetime print(datetime.time.hour) # 打印发现是一个对象 print(time.localtime().tm_hour) # 打印是数字,当前小时 print(datetime.date.day) # 打印发现也是一个对象 print(datetime.date.year) # 打印发现也是一个对象 # 因为 date 是类,所以需要创建对象,然后再访问 d = datetime.date(2018, 3, 21) print(d) # 2018-03-21 print(d.day) # 21 print(d.year) # 2018 print(datetime.date.ctime(d)) # Wed Mar 21 00:00:00 2018 print(datetime.date.today()) # 2026-06-29 # timedelta 时间差 t1 = datetime.timedelta(hours=2) print(t1) # 2:00:00 now = datetime.datetime.now() print(now) # 2026-06-29 21:53:25.176799 print(now - t1) # 2026-06-29 19:53:25.176799 ``` #### 6. random 模块与 hashlib 模块 ---