Python进阶

devtools/2024/10/23 3:15:37/

面向对象编程(OOP)

1.1 类和对象
  • 是一个模板,用来描述一类对象的属性和行为。通过定义类,你可以创建对象(也称为类的实例)。
  • 对象 是类的实例,通过类创建的具体实例对象。
示例:
python"># 定义一个类
class Dog:# 类的初始化方法def __init__(self, name, age):self.name = name  # 实例属性self.age = age# 类的方法def bark(self):print(f"{self.name} 叫了,汪汪!")# 创建对象(实例)
my_dog = Dog("Lucky", 3)
print(my_dog.name)  # 输出:Lucky
my_dog.bark()  # 输出:Lucky 叫了,汪汪!
1.2 类属性和实例属性
  • 类属性 是属于类的属性,由所有对象共享。
  • 实例属性 是属于对象的属性,由每个对象独立拥有。
示例:
python">class Dog:species = "Canine"  # 类属性def __init__(self, name):self.name = name  # 实例属性# 访问类属性
print(Dog.species)  # 输出:Canine# 访问实例属性
dog1 = Dog("Buddy")
dog2 = Dog("Max")
print(dog1.name)  # 输出:Buddy
print(dog2.name)  # 输出:Max
1.3 子类重写 __init__ 方法
  • 重写 __init__ 方法:子类可以重写父类的 __init__ 方法,从而增加新的实例属性或修改父类已有的属性。在重写时,可以使用 super() 函数调用父类的 __init__ 方法,以确保继承父类的属性。
示例:
python">class Animal:def __init__(self, name):self.name = nameclass Dog(Animal):def __init__(self, name, breed):super().__init__(name)  # 调用父类的 __init__ 方法self.breed = breed  # 新增子类特有的属性my_dog = Dog("Lucky", "Golden Retriever")
print(my_dog.name)  # 输出:Lucky
print(my_dog.breed)  # 输出:Golden Retriever
  • 在这个例子中,Dog 类重写了 __init__ 方法,并使用 super().__init__(name) 调用了父类的 __init__ 方法,继承了 name 属性,同时新增了 breed 属性。
1.4 子类和父类的类属性相互作用
  • 类属性 是属于类本身的属性,由所有对象共享。子类可以继承父类的类属性,同时也可以修改或定义自己的类属性。
  • 如果子类修改父类的类属性,它会在子类中创建一个新的属性,而不会影响父类的属性。类属性是相对独立的,只有当通过父类访问时,才会保持一致。
示例:
python">class Animal:species = "Animal"class Dog(Animal):species = "Canine"print(Animal.species)  # 输出:Animal
print(Dog.species)  # 输出:Caninemy_dog = Dog()
print(my_dog.species)  # 输出:Canine
  • 在这个例子中,Dog 类的 species 属性独立于 Animal 类的 species,子类可以拥有自己的类属性,不会影响父类。
1.5 私有属性
  • 在类中,属性名前加 __(双下划线)可以将属性设为私有,仅能在类内部访问。私有属性不会被子类继承。
示例:
python">class Animal:def __init__(self, name):self.__name = name  # 私有属性def get_name(self):return self.__nameanimal = Animal("Lucky")
print(animal.get_name())  # 输出:Lucky
# print(animal.__name)  # 会报错,无法直接访问私有属性
1.6 方法重载(Python中的变通方式)
  • 方法重载 是指同一个类中可以有多个同名方法,根据参数的不同执行不同的逻辑。然而,Python 不直接支持传统的函数重载,因为在Python中,函数名相同的后定义的会覆盖先定义的。可以通过可变参数*args**kwargs)来实现类似重载的行为。
示例:
python">class MathOperations:def add(self, *args):if len(args) == 1:return args[0] + 10elif len(args) == 2:return args[0] + args[1]else:return "参数数量不正确"math = MathOperations()
print(math.add(5))         # 输出:15
print(math.add(5, 10))     # 输出:15
print(math.add(1, 2, 3))   # 输出:参数数量不正确
  • 这里,add 方法通过检查参数的数量来执行不同的逻辑,从而实现类似重载的效果。

2. 迭代器与生成器

2.1 next(iterator) vs iterator.next()
  • 在Python 3中,迭代器使用 next() 函数来获取下一个元素,而不使用 iterator.next()。这是因为 next() 是一种全局函数,适用于任何实现了 __next__() 方法的对象,而 iterator.next() 形式只存在于 Python 2 中。
  • 在Python 3中,迭代器对象的 __next__() 方法已经被封装在全局的 next() 函数中,所以推荐使用 next(iterator)
2.2 生成器的暂停与继续
  • 生成器 是一种特殊的迭代器,由函数生成,并使用 yield 语句来产生值和暂停执行。当你调用 next() 时,生成器会从上次暂停的地方继续运行。
  • 当生成器遇到 yield,它会返回 yield 后的值,并暂停执行函数体。下次调用 next() 时,它会从暂停的地方继续执行,直到再次遇到 yield 或函数结束。
示例解释:
python">def count_up_to(max):count = 1while count <= max:yield count  # 暂停并返回当前值count += 1counter = count_up_to(3)
print(next(counter))  # 输出:1
print(next(counter))  # 输出:2
print(next(counter))  # 输出:3
  • 在第一次调用 next(counter) 时,生成器运行到 yield count 处,返回 count 的值并暂停执行。
  • 第二次调用 next(counter) 时,生成器从暂停的地方继续执行,将 count 增加 1,然后再次遇到 yield,返回新的 count 值。
  • 这个过程一直持续到生成器函数执行完毕或不再遇到 yield 为止。

3. 模块与包细化

3.1 模块的导入与实例化
  • 当你使用 import mymodule 时,Python解释器会将 mymodule.py 文件中的代码执行一次,并将模块作为对象实例加载到当前作用域中。此后,你可以使用 mymodule 访问模块中的属性和方法,就像访问对象的属性和方法一样。
示例:
python">import mymodule  # 导入时执行模块中的代码
mymodule.greet("Alice")  # 调用模块中的函数
  • 这意味着模块在被导入后,成为当前程序中的一个对象,可以通过 . 访问其中的内容。
3.2 包结构与 my_package/
  • 是一个包含多个模块的目录,通常是一个文件夹,并且必须包含一个 __init__.py 文件,用于标识该目录是一个包。my_package/ 表示包的目录名称,目录中可以包含其他模块和子包。
示例:
my_package/       # 包目录__init__.py   # 包初始化文件module1.py    # 包含的模块module2.py
  • __init__.py 是必要的,它告诉Python该目录是一个包。目录的名字(即 my_package/)是你用来导入包时使用的名称。包的结构可以自由组织,但必须有清晰的层次,方便导入和管理模块。
3.3 目录名字和结构的影响
  • 目录名字决定了导入包时的路径,例如,from my_package import module1 中,my_package 就是包的名字。
  • 如果目录结构混乱,或者 __init__.py 文件缺失,Python可能无法正确识别和导入包中的模块。

4. 文件操作的细化

4.1 文件对象的特性
  • 文件对象 是通过 open() 函数返回的对象,具有多种方法和属性:
    • read(size):读取文件内容,size 是可选参数,表示读取的字节数。
    • readline():读取一行内容。
    • readlines():读取所有行并返回一个列表,每一行作为列表的一个元素。
    • write(content):将字符串写入文件。
    • close():关闭文件,释放资源。
    • seek(offset):移动文件指针到指定位置,offset 表示字节数。
    • tell():返回文件指针当前位置。
    • mode:文件的打开模式,例如 'r''w''rb' 等。
    • name:文件的名称。
4.2 line 对象和 strip() 方法
  • 在文件操作中,line 是一个字符串对象,表示文件中的一行。每一行通常以换行符 \n 结尾。
  • strip() 方法:用于移除字符串开头和结尾的空白字符(包括空格、换行符、制表符等)。
示例:
python">with open("example.txt", "r") as file:for line in file:print(line.strip())  # 移除每一行末尾的换行符
  • 这里,strip() 移除了每一行末尾的换行符,使得输出更加整洁。

附录

1. 装饰器和语法糖详解

1.1 什么是语法糖?

  • 语法糖 是指编程语言中提供的特定语法,用来使代码更加易读和简洁,而不引入新的功能。语法糖的存在是为了让程序员更轻松地编写代码。装饰器的 @ 就是一种语法糖,它可以简化函数包装的过程。

1.2 装饰器详解

  • 装饰器 是一种设计模式,用来为函数或方法添加新的功能,而不修改其原始代码。它本质上是一个高阶函数,接收一个函数作为参数并返回一个新的函数。
1.2.1 装饰器的工作原理
  • 装饰器的作用是“包裹”目标函数,添加一些在目标函数执行前后要完成的操作。通常通过在目标函数上方添加 @decorator_name 的方式来应用装饰器。
示例1:最简单的装饰器
python">def simple_decorator(func):def wrapper():print("在执行函数之前")func()print("在执行函数之后")return wrapper@simple_decorator
def say_hello():print("Hello, World!")say_hello()
  • 解析
    1. 定义了一个装饰器函数 simple_decorator(func),它接受一个函数作为参数,并返回一个新函数 wrapper()
    2. wrapper() 函数在执行目标函数前后分别添加了打印操作。
    3. 使用 @simple_decorator 应用装饰器,相当于将 say_hello 函数传递给 simple_decorator,然后用 wrapper 替换原始的 say_hello 函数。
    4. say_hello() 被调用时,实际执行的是 wrapper() 函数,添加了额外的逻辑。
1.2.2 装饰器的等价写法
  • 使用 @decorator_name 只是一个语法糖,等价于以下写法:
python">def say_hello():print("Hello, World!")say_hello = simple_decorator(say_hello)
say_hello()

1.3 带参数的装饰器

  • 有时我们希望装饰器本身能够接受参数。这时可以通过在装饰器外再定义一层包装函数来实现。
示例2:带参数的装饰器
python">def repeat(num_times):def decorator(func):def wrapper(*args, **kwargs):for _ in range(num_times):func(*args, **kwargs)return wrapperreturn decorator@repeat(3)
def greet(name):print(f"Hello, {name}!")greet("Alice")
  • 解析
    1. repeat(num_times) 是一个工厂函数,返回真正的装饰器 decorator
    2. decorator(func) 是接收函数并返回包装函数 wrapper 的实际装饰器。
    3. wrapper(*args, **kwargs) 可以接收任意数量和类型的参数,重复执行目标函数 num_times 次。

1.4 装饰器与函数参数(*args**kwargs

  • 在示例2中,*args**kwargs 用于接收目标函数的所有参数。*args 接收任意数量的非关键字参数,**kwargs 接收任意数量的关键字参数。这使得装饰器更通用,可以适用于各种函数。

2. 可变参数(*args**kwargs

2.1 *args 的用法

  • *args 用于接收不定数量的位置参数,生成一个元组。可以在函数定义中使用 *args 来允许传递任意数量的参数。
示例1:使用 *args 的函数
python">def sum_numbers(*args):total = 0for num in args:total += numreturn totalprint(sum_numbers(1, 2, 3))  # 输出:6
print(sum_numbers(4, 5, 6, 7))  # 输出:22
  • 解析*args 将传递给 sum_numbers 的所有参数收集成一个元组 (1, 2, 3)(4, 5, 6, 7)

2.2 **kwargs 的用法

  • **kwargs 用于接收不定数量的关键字参数,生成一个字典。可以在函数定义中使用 **kwargs 来接收任意数量的关键字参数。
示例2:使用 **kwargs 的函数
python">def print_info(**kwargs):for key, value in kwargs.items():print(f"{key}: {value}")print_info(name="Alice", age=30, job="Engineer")
  • 解析**kwargs 将传递给 print_info 的关键字参数收集成一个字典 {'name': 'Alice', 'age': 30, 'job': 'Engineer'}

2.3 同时使用 *args**kwargs

  • 可以同时使用 *args**kwargs 来接收位置参数和关键字参数。
示例3:混合使用
python">def display(*args, **kwargs):print("位置参数:", args)print("关键字参数:", kwargs)display(1, 2, 3, name="Alice", age=30)
  • 解析*args 接收位置参数 (1, 2, 3)**kwargs 接收关键字参数 {'name': 'Alice', 'age': 30}

3. 包目录的名字和结构

3.1 包目录的命名规则

  • 包目录 是包含多个模块的文件夹。包目录通常由用户自由命名,但必须包含一个 __init__.py 文件来告诉Python解释器该目录是一个包。
  • 目录名称:目录名称决定了导入包的路径。例如,目录名为 my_package/,则导入时应使用 import my_package

3.2 包的结构和影响

  • 包结构 决定了模块的组织方式。良好的包结构能方便代码的维护和模块的调用。如果包结构混乱,导入模块时可能会产生错误。
示例1:包的标准结构
my_package/           # 包目录__init__.py       # 包初始化文件module1.py        # 模块1module2.py        # 模块2
  • 可以通过以下方式导入模块:
python">from my_package import module1
import my_package.module2
示例2:子包的嵌套结构
my_package/           # 包目录__init__.py       # 包初始化文件sub_package/      # 子包__init__.py   # 子包初始化文件module3.py    # 模块3
  • 可以通过以下方式导入子包中的模块:
python">from my_package.sub_package import module3

3.3 my_package/ 是否必要

  • 包目录(如 my_package/)并非必须命名为 “my_package”,但该目录的名字决定了导入时使用的路径。例如,目录名为 utilities/,则导入时应使用 import utilities
  • 如果缺少 __init__.py 文件,Python会无法识别该目录为包,导致导入失败。

4. __init__.py 文件的作用

4.1 __init__.py 的作用

  • __init__.py 是一个特殊的文件,用来标识某个目录是Python包。没有这个文件,Python解释器就不会将该目录识别为包。它还可以用于定义包的公共接口,允许导入特定模块和属性。
  • 在Python 3.3之后,__init__.py 文件已经不是严格必须的,但为了明确结构、维护兼容性和定义包的行为,通常仍会包含此文件。

4.2 __init__.py 文件的内容

  • __init__.py 文件可以是空文件,也可以包含初始化代码,或者定义需要导入的模块。它的内容可以根据需要自由定制,通常用于:
    • 导入包中的模块。
    • 初始化包的环境(例如设置变量、执行启动逻辑)。
    • 定义包的公共接口。
示例1:空的 __init__.py
python"># my_package/__init__.py
  • 这是一个空的 __init__.py 文件。它的存在只是为了告诉Python解释器,这个目录是一个包。这样,my_package 目录中的模块可以被导入。
示例2:带有初始化代码的 __init__.py
python"># my_package/__init__.py
print("my_package 被导入")
  • 这种写法可以让你在导入包时自动执行某些初始化操作。当使用 import my_package 时,会输出 my_package 被导入
示例3:导入包中的模块
  • __init__.py 文件还可以用于控制包中的模块被导入时的行为。例如,在 __init__.py 中指定哪些模块可以被导入:
python"># my_package/__init__.py
from .module1 import function1
from .module2 import function2
  • 这样,在外部使用 from my_package import * 时,就可以直接使用 function1function2,而不需要单独导入 module1module2
示例4:定义包的公共接口
  • 通过在 __init__.py 中定义 __all__ 列表,可以控制包被导入时的公共接口:
python"># my_package/__init__.py
__all__ = ['module1', 'module2']
  • 这样,from my_package import * 只会导入 module1module2,其他模块不会被导入。

4.3 总结

  • __init__.py 文件主要用于:
    1. 标识目录是Python包。
    2. 控制包的初始化行为。
    3. 定义包的公共接口。
  • 虽然在Python 3.3之后,__init__.py 文件不是必须的,但它仍然是组织和管理包的最佳实践。

http://www.ppmy.cn/devtools/128031.html

相关文章

基于Springboot在线视频网站的设计与实现

基于Springboot视频网站的设计与实现 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;idea 源码获取&#xff1a;https://do…

架构设计笔记-21-案例分析

1.遗留系统策略 / 数据迁移 / REST和RPC风格 2.分布式系统 / 分布式对象调用 3.开放式架构 / GOA 4.ESB 5.FMEA故障分析 6. 加密 / 公钥体系机制 / 加解密API和透明加密 7.嵌入式系统故障 / 故障滤波算法 / 容错算法 8.开源框架struts / spring / Hibenate 9.企业应用集成 10.T…

西门子嵌入式面试题及参考答案(万字长文)

RAM 和 ROM 的各种总线协议 RAM(随机存取存储器)和 ROM(只读存储器)在嵌入式系统中起着重要的作用,它们通常使用不同的总线协议与其他设备进行通信。 一、RAM 的常见总线协议 SRAM(静态随机存取存储器)常用的总线协议有异步 SRAM 协议和同步 SRAM 协议。 异步 SRAM 协议…

2024软考网络工程师笔记 - 第10章.组网技术

文章目录 交换机基础1️⃣交换机分类2️⃣其他分类方式3️⃣级联和堆叠4️⃣堆叠优劣势5️⃣交换机性能参数 &#x1f551;路由器基础1️⃣路由器接口2️⃣交换机路由器管理方式2️⃣交换机路由器管理方式 交换机基础 1️⃣交换机分类 1.根据交换方式分 存储转发式交换(Store…

【MySQL】InnoDB存储引擎中的锁

实现事务隔离级别的过程中用到了锁&#xff0c;所谓锁就是在事务A修改某些数据时&#xff0c;对这些数据加一把锁&#xff0c;防止其他事务同时对这些数据执行修改操作;当事务A完成修改操作后&#xff0c;释放当前持有的锁&#xff0c;以便其他事务再次上锁执行对应的操作。不同…

【三】企业级JavaScript开发之手册与规范

规范 ECMA-262 规范 包含了大部分深入的、详细的、规范化的关于 JavaScript 的信息。这份规范明确地定义了这门语言。 但正因其规范化&#xff0c;对于新手来说难以理解。所以&#xff0c;如果你需要关于这门语言细节最权威的信息来源&#xff0c;这份规范就很适合你&#xf…

WSL2配置代理解决git网络不通畅的问题

简述 书接上文&#xff0c;在WSL2下使用CrossSim&#xff0c;git的时候网络很差&#xff0c;通过代理解决这个问题。 旧版的解决方案一般是通过cat /etc/resolv.conf获取IP然后配置主机的端口&#xff0c;这样有时候并不能访问&#xff0c;并且一般会出现该问题&#xff1a;ws…

数字IC后端实现Innovus |给各种IP子模块添加port buffer和antenna diode万能脚本

我们之前分享过在hierarchical flow后端实现中为了确保顶层flatten时timing signoff和physical signoff看到的情况和模块级看到的情况一致&#xff0c;我们会在模块io port添加io port buffer&#xff08;主要是timing&#xff0c;antenna一致性&#xff09;。实际上在芯片级我…