diff --git a/src/content/posts/Python/Python面向对象快速入门.md b/src/content/posts/Python/Python面向对象快速入门.md new file mode 100644 index 0000000..33f4261 --- /dev/null +++ b/src/content/posts/Python/Python面向对象快速入门.md @@ -0,0 +1,171 @@ +--- +title: Python面向对象快速入门 +published: 2026-01-19T22:53:40 +description: '一篇关于 Python 面向对象编程(OOP)的快速入门指南,涵盖类、对象、封装、继承和多态等核心概念。' +image: '' +draft: false +lang: '' +category: Python +tags: + - Python + - OOP + - 编程基础 +--- + +面向对象编程(Object-Oriented Programming,简称 OOP)是一种程序设计思想。在 Python 中,一切皆对象。掌握 OOP 是进阶 Python 编程的关键一步。 + +本文将带你快速理解 Python 面向对象的核心概念。 + +## 1. 类 (Class) 与 对象 (Object) + +**类**是创建对象的蓝图(模板),**对象**是类的具体实例。 + +比喻: +- **类**:汽车的设计图纸。 +- **对象**:根据图纸制造出来的具体的一辆辆汽车(如你的宝马、他的奔驰)。 + +### 定义类与创建对象 + +```python +# 定义一个类 +class Dog: + pass + +# 创建对象(实例化) +dog1 = Dog() +dog2 = Dog() + +print(dog1) # <__main__.Dog object at ...> +print(dog1 == dog2) # False,它们是两个不同的对象 +``` + +## 2. 构造方法与属性 + +在类中,我们可以定义属性(变量)来描述对象的特征。 + +### `__init__` 方法 + +`__init__` 是一个特殊方法(构造方法),在创建对象时自动调用,用于初始化对象的属性。 + +- `self`:代表类的实例(对象)本身。在定义类的方法时,第一个参数通常是 `self`。 + +```python +class Cat: + def __init__(self, name, age): + self.name = name # 实例属性 + self.age = age # 实例属性 + +# 创建对象时传入参数 +tom = Cat("Tom", 3) +jerry = Cat("Jerry", 2) + +print(f"{tom.name} is {tom.age} years old.") +# 输出: Tom is 3 years old. +``` + +## 3. 方法 (Methods) + +方法就是定义在类内部的函数,用来描述对象的行为。 + +```python +class Person: + def __init__(self, name): + self.name = name + + def say_hello(self): + print(f"Hello, my name is {self.name}.") + +p = Person("Alice") +p.say_hello() +# 输出: Hello, my name is Alice. +``` + +## 4. 封装 (Encapsulation) + +封装是指将数据(属性)和操作数据的方法绑定在一起,并隐藏对象的内部实现细节。 + +在 Python 中,通过在属性名前加双下划线 `__` 将其变为私有属性(Private),外部无法直接访问。 + +```python +class BankAccount: + def __init__(self, balance): + self.__balance = balance # 私有属性 + + def deposit(self, amount): + if amount > 0: + self.__balance += amount + print(f"Deposited {amount}") + + def get_balance(self): + return self.__balance + +account = BankAccount(100) +account.deposit(50) +print(account.get_balance()) # 输出: 150 + +# print(account.__balance) # 报错!无法直接访问私有属性 +``` + +## 5. 继承 (Inheritance) + +继承允许我们创建一个新类(子类),从现有的类(父类)继承属性和方法。这提高了代码的复用性。 + +```python +# 父类 +class Animal: + def speak(self): + print("Animal speaks") + +# 子类继承父类 +class Dog(Animal): + def speak(self): + print("Woof!") # 重写父类方法 + +class Cat(Animal): + pass + +dog = Dog() +dog.speak() # 输出: Woof! + +cat = Cat() +cat.speak() # 输出: Animal speaks (直接继承父类方法) +``` + +### `super()` 函数 + +子类可以使用 `super()` 调用父类的方法,常用于扩展父类的 `__init__` 方法。 + +```python +class Bird(Animal): + def __init__(self, name, can_fly): + super().__init__() # 调用父类构造方法(如果有的话) + self.name = name + self.can_fly = can_fly +``` + +## 6. 多态 (Polymorphism) + +多态指“多种形态”。不同的子类对象调用相同的方法,产生不同的行为。 + +上面的 `Dog` 和 `Cat` 都继承自 `Animal` 并调用 `speak()` 方法,但表现不同,这就是多态。 + +```python +def animal_sound(animal): + animal.speak() + +dog = Dog() +cat = Cat() + +animal_sound(dog) # 输出: Woof! +animal_sound(cat) # 输出: Animal speaks +``` + +## 总结 + +- **类**是模板,**对象**是实例。 +- **属性**描述特征,**方法**描述行为。 +- **封装**保护数据安全。 +- **继承**实现代码复用。 +- **多态**提供灵活的接口。 + +掌握这些概念,你就迈入了 Python 面向对象编程的大门! diff --git a/src/content/posts/Python/Python面向对象深度解析.md b/src/content/posts/Python/Python面向对象深度解析.md new file mode 100644 index 0000000..9c67912 --- /dev/null +++ b/src/content/posts/Python/Python面向对象深度解析.md @@ -0,0 +1,350 @@ +--- +title: Python面向对象编程终极指南:原理、进阶与元编程 +published: 2026-01-19T22:53:40 +description: '一篇涵盖 Python 面向对象编程(OOP)所有核心细节的终极指南。从底层的对象模型、内存管理,到进阶的描述符、MRO 算法、元类编程及设计模式。' +image: '' +draft: false +lang: '' +category: Python +tags: + - Python + - OOP + - 核心原理 + - 元编程 + - 深度好文 +--- + +这是一篇旨在彻底讲透 Python 面向对象编程(OOP)的终极指南。我们将不再局限于基础语法,而是深入到 Python 的对象模型底层,探讨**元类**、**描述符**、**方法解析顺序 (MRO)** 以及**内存管理**等高级话题。 + +## 目录 + +1. **对象模型底层**:`__new__` vs `__init__` +2. **深入属性系统**:`__slots__` 与 描述符协议 +3. **继承的奥秘**:多重继承、Mixin 与 C3 算法 +4. **接口与约束**:抽象基类 (ABC) 与 协议 (Protocol) +5. **元编程 (Metaprogramming)**:动态创建类与元类 +6. **魔术方法大全**:模拟 Python 内置行为 +7. **内存管理与垃圾回收** + +--- + +## 1. 对象模型底层:`__new__` vs `__init__` + +很多人认为 `__init__` 是构造函数,其实不然。对象的创建过程分为两步: + +1. **构造 (Construction)**:`__new__` 分配内存,创建对象实例。 +2. **初始化 (Initialization)**:`__init__` 给这个已经创建好的实例设置初始值。 + +### 1.1 `__new__` 方法 + +`__new__` 是一个静态方法(虽然不需要写 `@staticmethod`),它的第一个参数是 `cls`。它**必须**返回一个实例。 + +**应用场景**: +* **不可变对象 (Immutable Objects)**:继承自 `str`, `int`, `tuple` 的子类,因为它们一旦创建就无法修改,所以必须在 `__new__` 中定制。 +* **单例模式 (Singleton)**:控制只创建一个实例。 +* **元类编程**。 + +```python +class UpperStr(str): + def __new__(cls, value): + # 在对象创建前拦截,强制转换为大写 + return super().__new__(cls, value.upper()) + +s = UpperStr("hello") +print(s) # HELLO (str 是不可变的,必须在 __new__ 处理) +``` + +### 1.2 单例模式实现 + +```python +class Singleton: + _instance = None + + def __new__(cls, *args, **kwargs): + if cls._instance is None: + # 只有第一次调用时才真正创建对象 + cls._instance = super().__new__(cls) + return cls._instance + +a = Singleton() +b = Singleton() +print(a is b) # True +``` + +--- + +## 2. 深入属性系统:`__slots__` 与 描述符 + +### 2.1 `__slots__`:内存优化 + +默认情况下,Python 对象使用字典 (`__dict__`) 存储属性。这提供了极大的灵活性,但对于创建数百万个小对象的场景,内存消耗巨大。 + +`__slots__` 告诉 Python:“这个类只有这些属性,不要创建 `__dict__`”。 + +```python +class Pixel: + __slots__ = ('x', 'y') # 锁定属性,禁止动态添加其他属性 + + def __init__(self, x, y): + self.x = x + self.y = y + +p = Pixel(10, 20) +# p.z = 30 # AttributeError: 'Pixel' object has no attribute 'z' +``` + +**副作用**: +* 对象不再有 `__dict__`。 +* 无法动态添加新属性。 +* 继承时如果不重复定义 `__slots__`,子类依然会有 `__dict__`。 + +### 2.2 描述符 (Descriptors) + +这是 Python 属性魔法的**核心**。`@property`、类方法、静态方法,底层全都是描述符。 + +一个实现了 `__get__`, `__set__`, 或 `__delete__` 方法的**类**,就是一个描述符。 + +```python +class Integer: + """数据描述符:强制属性必须是整数""" + def __init__(self, name): + self.name = name + + def __get__(self, instance, owner): + if instance is None: + return self + return instance.__dict__.get(self.name) + + def __set__(self, instance, value): + if not isinstance(value, int): + raise ValueError(f"{self.name} must be an integer") + instance.__dict__[self.name] = value + +class Point: + x = Integer("x") # 描述符实例作为类属性 + y = Integer("y") + + def __init__(self, x, y): + self.x = x # 触发 Integer.__set__ + self.y = y + +p = Point(1, 2) +# p.x = "hello" # ValueError: x must be an integer +``` + +--- + +## 3. 继承的奥秘:多重继承、Mixin 与 MRO + +### 3.1 多重继承与菱形问题 + +Python 支持多重继承。当一个类继承多个父类时,如果父类中有同名方法,Python 如何决定调用哪一个? + +Python 2.3 之后引入了 **C3 线性化算法** 来计算 **MRO (Method Resolution Order)**。 + +```python +class A: + def say(self): print("A") + +class B(A): + def say(self): print("B") + +class C(A): + def say(self): print("C") + +class D(B, C): + pass + +d = D() +d.say() # 输出 B +print(D.mro()) +# [, , , , ] +``` + +**原则**: +1. 子类优先于父类。 +2. 多个父类按照从左到右的顺序检查。 +3. 如果出现菱形继承(如上图,B和C都继承A),确保公共基类(A)最后被检查(但在 `object` 之前)。 + +### 3.2 Mixin 模式 + +Mixin(混入)是一种设计模式,利用多重继承给类添加单一功能的“插件”,而不需要建立严格的父子关系。 + +```python +class JsonSerializableMixin: + def to_json(self): + import json + return json.dumps(self.__dict__) + +class User(JsonSerializableMixin): + def __init__(self, name): + self.name = name + +u = User("Alice") +print(u.to_json()) # {"name": "Alice"} +``` + +--- + +## 4. 接口与约束:ABC 与 Protocol + +Python 是动态语言,通常不强制类型。但为了大型项目的健壮性,我们需要接口约束。 + +### 4.1 抽象基类 (Abstract Base Classes) + +使用 `abc` 模块定义抽象基类,强制子类实现特定方法。 + +```python +from abc import ABC, abstractmethod + +class Shape(ABC): + @abstractmethod + def area(self): + pass + +class Circle(Shape): + def __init__(self, r): + self.r = r + + def area(self): + return 3.14 * self.r ** 2 + +# s = Shape() # TypeError: Can't instantiate abstract class +c = Circle(5) # OK +``` + +### 4.2 Protocol (鸭子类型的静态检查) + +Python 3.8 引入了 `typing.Protocol`。它不需要继承,只要类实现了协议规定的方法,类型检查器(如 MyPy)就认为它符合要求。 + +```python +from typing import Protocol + +class Flyer(Protocol): + def fly(self) -> None: + ... + +class Bird: + def fly(self): print("Bird flying") + +class Plane: + def fly(self): print("Plane flying") + +def lift_off(obj: Flyer): + obj.fly() + +# Bird 和 Plane 不需要显式继承 Flyer +lift_off(Bird()) +lift_off(Plane()) +``` + +--- + +## 5. 元编程 (Metaprogramming) + +元编程是“编写写代码的代码”。在 Python 中,类也是对象,**元类 (Metaclass)** 就是用来创建类的类。 + +默认情况下,`type` 是所有类的元类。 + +`class` 关键字背后的逻辑: +```python +# class MyClass: pass +# 等价于: +MyClass = type('MyClass', (), {}) +``` + +### 自定义元类 + +自定义元类通常继承自 `type`,并重写 `__new__` 或 `__init__`。可以在类创建时修改类的定义(自动添加方法、验证属性等)。 + +```python +class AutoDebugMeta(type): + """自动给类中的所有方法添加打印调试信息的元类""" + def __new__(mcs, name, bases, attrs): + new_attrs = {} + for key, value in attrs.items(): + if callable(value) and not key.startswith("__"): + # 包装函数 + def wrapper(*args, **kwargs): + print(f"Calling {key}...") + return value(*args, **kwargs) + new_attrs[key] = wrapper + else: + new_attrs[key] = value + + return super().__new__(mcs, name, bases, new_attrs) + +class MyService(metaclass=AutoDebugMeta): + def process(self): + print("Processing...") + +s = MyService() +s.process() +# 输出: +# Calling process... +# Processing... +``` + +--- + +## 6. 魔术方法大全 + +除了常见的 `__init__`, `__str__`,Python 提供了极其丰富的魔术方法。 + +### 属性访问控制 +* `__getattr__(self, name)`: 访问**不存在**的属性时调用(兜底)。 +* `__getattribute__(self, name)`: 访问**任何**属性时都会调用(拦截所有访问,慎用,易递归)。 +* `__setattr__(self, name, value)`: 设置属性时调用。 + +### 容器模拟 +* `__len__(self)` +* `__getitem__(self, key)` +* `__setitem__(self, key, value)` +* `__delitem__(self, key)` +* `__iter__(self)` +* `__contains__(self, item)`: `in` 操作符。 + +### 上下文管理 +* `__enter__`, `__exit__`: `with` 语句支持。 + +### 调用 +* `__call__`: 让实例像函数一样被调用 `instance()`。 + +--- + +## 7. 内存管理与垃圾回收 + +Python 使用**引用计数 (Reference Counting)** 为主,**标记-清除 (Mark and Sweep)** 和 **分代回收 (Generational Collection)** 为辅的垃圾回收机制。 + +### 7.1 `__del__` 析构方法 + +当对象的引用计数降为 0 时,`__del__` 会被调用。 + +**警告**:尽量不要依赖 `__del__` 来进行资源释放(如关闭文件),因为在循环引用等复杂情况下,它可能不会被立即调用,甚至不会被调用。应使用上下文管理器 (`with`)。 + +### 7.2 弱引用 (Weak Reference) + +`weakref` 模块允许创建不增加引用计数的引用。常用于缓存实现,避免对象无法被回收。 + +```python +import weakref + +class Data: + def __del__(self): + print("Data died") + +d = Data() +r = weakref.ref(d) # 创建弱引用 + +print(r()) # 获取对象: <__main__.Data object ...> +del d # 删除唯一强引用,对象立即被回收,输出 "Data died" +print(r()) # None +``` + +--- + +## 结语 + +Python 的面向对象远比表面看起来深奥。从简单的 `class` 定义,到背后的元类机制、描述符协议以及 C3 算法,Python 提供了一套逻辑自洽且极具扩展性的对象模型。 + +掌握这些细节,不仅能让你写出更高效、更健壮的代码,更能让你在阅读 Django, SQLAlchemy 等顶级框架源码时游刃有余。 diff --git a/src/content/posts/Python/Python面向对象进阶.md b/src/content/posts/Python/Python面向对象进阶.md new file mode 100644 index 0000000..f10131f --- /dev/null +++ b/src/content/posts/Python/Python面向对象进阶.md @@ -0,0 +1,226 @@ +--- +title: Python面向对象进阶:属性管理与魔术方法 +published: 2026-01-19T22:53:40 +description: '深入探讨 Python 面向对象编程中的进阶话题,包括类属性与实例属性的区别、三种方法类型(实例/类/静态)、@property 封装以及常用的魔术方法。' +image: '' +draft: false +lang: '' +category: Python +tags: + - Python + - OOP + - 进阶教程 +--- + +在掌握了 Python 面向对象的基础之后,我们需要进一步了解如何编写更“Pythonic”的类。本文将涵盖属性管理、方法类型以及强大的魔术方法。 + +## 1. 属性与方法的进阶 + +### 1.1 类属性 vs 实例属性 + +这是新手最容易混淆的地方。 + +* **实例属性**:定义在 `__init__` 或其他方法中,使用 `self.variable`。属于**单个对象**。 +* **类属性**:直接定义在类体中。属于**类本身**,所有实例共享。 + +```python +class Dog: + species = "Canis" # 类属性:所有狗都是犬科 + + def __init__(self, name): + self.name = name # 实例属性:每只狗名字不同 + +d1 = Dog("Buddy") +d2 = Dog("Charlie") + +# 访问类属性 +print(d1.species) # Canis (通过实例访问) +print(Dog.species) # Canis (推荐:通过类名访问) + +# 修改类属性 +Dog.species = "Wolf" +print(d1.species) # Wolf (所有实例感知变化) + +# 【坑点预警】通过实例修改类属性 +d1.species = "Cat" +# 这一步并没有修改类属性!而是在 d1 对象上创建了一个同名的实例属性 'species' +# 屏蔽了对类属性的访问。 + +print(d1.species) # Cat (d1 的实例属性) +print(d2.species) # Wolf (依然是类属性) +print(Dog.species) # Wolf (类属性未变) +``` + +### 1.2 三种方法类型 + +Python 的类中可以定义三种方法: + +1. **实例方法 (Instance Method)**: + * 第一个参数是 `self`。 + * 可以访问实例属性和类属性。 + * 最常用。 + +2. **类方法 (Class Method)**: + * 使用 `@classmethod` 装饰器。 + * 第一个参数是 `cls`(代表类本身)。 + * **不能**访问实例属性,只能访问类属性。 + * **用途**:常用于实现“工厂模式”或修改类状态。 + +3. **静态方法 (Static Method)**: + * 使用 `@staticmethod` 装饰器。 + * 不需要 `self` 或 `cls` 参数。 + * 就像一个普通函数放在了类里面,逻辑上属于这个类,但在运行时与类/实例无关。 + * **用途**:工具函数。 + +```python +class Date: + def __init__(self, year, month, day): + self.year = year + self.month = month + self.day = day + + # 实例方法 + def format(self): + return f"{self.year}-{self.month}-{self.day}" + + # 类方法:作为构造函数的一种替代(工厂模式) + @classmethod + def from_string(cls, date_str): + # date_str 格式 "2023-10-01" + year, month, day = map(int, date_str.split('-')) + return cls(year, month, day) # 返回一个新的实例 + + # 静态方法:不需要访问类或实例的数据 + @staticmethod + def is_valid(date_str): + return '-' in date_str + +# 使用 +d1 = Date(2023, 10, 1) +d2 = Date.from_string("2023-12-25") # 调用类方法 +print(d2.format()) + +print(Date.is_valid("2023-10-1")) # True +``` + +--- + +## 2. 封装与访问控制 + +### 2.1 私有属性与名称改写 + +Python 没有像 Java 那样严格的 `private` 关键字。它通过**命名约定**来实现封装。 + +* `public`:`self.name`,公有,随处可访问。 +* `protected`:`self._age`(单下划线),**约定**视为内部使用,但解释器不强制限制。 +* `private`:`self.__money`(双下划线),解释器会进行**名称改写 (Name Mangling)**,防止子类意外覆盖或外部直接访问。 + +```python +class Account: + def __init__(self, balance): + self.__balance = balance # 私有属性 + + def get_balance(self): + return self.__balance + +acc = Account(100) +# print(acc.__balance) # AttributeError +print(acc.get_balance()) # 100 + +# 强行访问(不推荐,除非调试) +print(acc._Account__balance) # 100 (Python 将其改名为 _ClassName__variable) +``` + +### 2.2 使用 `@property` 装饰器 + +`@property` 是 Pythonic 的封装方式。它允许你像访问属性一样调用方法,实现对属性的**获取**、**设置**和**删除**的控制。 + +```python +class Person: + def __init__(self, name): + self._name = name + + # Getter + @property + def name(self): + return self._name + + # Setter + @name.setter + def name(self, value): + if not isinstance(value, str): + raise ValueError("Name must be a string") + self._name = value + + # Deleter + @name.deleter + def name(self): + print("Deleting name...") + del self._name + +p = Person("Alice") +print(p.name) # 自动调用 getter +p.name = "Bob" # 自动调用 setter +# p.name = 123 # 抛出 ValueError +``` + +--- + +## 3. 魔术方法 (Magic Methods) + +魔术方法(Dunder Methods,双下划线方法)允许你的对象模拟内置类型的行为(如算术运算、长度获取、索引访问等)。 + +### 3.1 字符串表示:`__str__` vs `__repr__` + +* `__str__`:面向用户,打印时 (`print()`) 调用,力求可读性。 +* `__repr__`:面向开发者,调试时 (`repl` 环境) 调用,力求准确性(最好能用来重建对象)。 + +```python +class Vector: + def __init__(self, x, y): + self.x = x + self.y = y + + def __str__(self): + return f"Vector({self.x}, {self.y})" + + def __repr__(self): + return f"Vector(x={self.x}, y={self.y})" + +v = Vector(1, 2) +print(v) # 调用 __str__ +print([v]) # 列表内的元素会调用 __repr__ +``` + +### 3.2 运算符重载 + +让你的对象支持 `+`, `-`, `*` 等操作。 + +```python + # 接上面的 Vector 类 + def __add__(self, other): + if isinstance(other, Vector): + return Vector(self.x + other.x, self.y + other.y) + return NotImplemented + +v1 = Vector(1, 2) +v2 = Vector(3, 4) +v3 = v1 + v2 # 自动调用 v1.__add__(v2) +print(v3) # Vector(4, 6) +``` + +### 3.3 其他常用魔术方法 + +* `__len__(self)`: `len(obj)` 时调用。 +* `__getitem__(self, key)`: `obj[key]` 时调用,实现索引或切片访问。 +* `__call__(self)`: 让对象像函数一样被调用 `obj()`。 +* `__enter__` / `__exit__`: 实现上下文管理器(`with` 语句)。 + +## 总结 + +Python 的 OOP 既简洁又强大。 + +1. **区分清楚**类属性与实例属性,防止数据污染。 +2. **善用** `@property` 和魔法方法,写出 Pythonic 的代码。 +3. **理解**鸭子类型,不要过分纠结于类型检查,而要关注行为(接口)。 +4. **掌握** `super()`,为编写可维护的继承结构打好基础。 diff --git a/src/content/posts/开发日记/scoop配置国内源.md b/src/content/posts/开发日记/scoop配置国内源.md new file mode 100644 index 0000000..3a5fcde --- /dev/null +++ b/src/content/posts/开发日记/scoop配置国内源.md @@ -0,0 +1,23 @@ +--- +title: scoop配置国内源 +published: 2026-01-19T20:49:49 +description: 'scoop配置国内源' +image: '' +category: 开发日记 +draft: false +lang: '' +--- + +# 更换scoop主仓库 +``` +# 南京大学 +scoop config SCOOP_REPO "https://mirrors.nju.edu.cn/git/scoop-installer/Scoop.git" + + + +# 添加南京大学extras仓库 +scoop bucket add extras https://mirrors.nju.edu.cn/git/scoop-extras.git + +``` + +