Python 面向对象编程 (OOP)中的高级特性

VOL.238272 views

1

Mar. 2024

无论你是初级 Python开发人员,还是经验丰富的高级程序员,本文都可以给你带来一定的帮助。这可能会是一个系列文章,我将分章来讲解,包括 Magic 方法,__slots__,类方法以及属性装饰器几个部分。

Magic 方法

Magic 方法以双下划线开头和结尾的特殊方法(__method__),它可以制止运算符重载以及其他 Python 内建功能的自定义。

对象创建和初始化

  • __new__(cls, ...):
    调用以创建新实例。此方法是唯一的,在__init__方法之前调用,负责返回类的新实例。它在创建不可变类型和元编程中特别有用。
  • __init__(self, ...):
    在调用__new__创建实例后调用,这个方法用于初始化对象。
class Example:
    def __new__(cls):
        print("Creating Instance")
        return super(Example, cls).__new__(cls)
    
    def __init__(self):
        print("Initializing Instance")


# 使用方法
ex = Example()

# Output: Creating Instance
#         Initializing Instance

对象表示

  • __repr__(self):返回对象的明确字符串表示形式,最好是可用于重新创建对象的字符串表示形式。
  • __str__(self):返回对象的用户友好的字符串表示形式。
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f"{self.name}, aged {self.age}"

    def __repr__(self):
        return f"Person('{self.name}', {self.age})"


# Usage
p = Person("Alice", 30)
print(str(p))  # Output: Alice, aged 30
print(repr(p)) # Output: Person('Alice', 30)

比较 Magic 方法

  • __eq__(self, other):相等 (==)。
  • __ne__(self, other):不相等 ( !=)。
  • __lt__(self, other):少于 (<)。
  • __le__(self, other):小于或等于( <=)。
  • __gt__(self, other):大于 (>)。
  • __ge__(self, other):大于或等于( >=)。
class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author

    def __eq__(self, other):
        return self.title == other.title and self.author == other.author


# Usage
book1 = Book("1984", "George Orwell")
book2 = Book("1984", "George Orwell")
print(book1 == book2)  # Output: True

算术运算和位运算的 Magic 方法

  • __add__(self, other):加法 (+)。
  • __sub__(self, other):减法(-)。
  • __mul__(self, other):乘法 ( *)。
  • __truediv__(self, other):除法 (/)。
  • __floordiv__(self, other):整除(//)。
  • __mod__(self, other):取余 ( %)。
  • __pow__(self, other[, modulo]):幂运算 (**)。
  • __and__(self, other):与运算符 ( &)
  • __invert__(self):按位取反。
  • __or__(self, other): 或运算符( or)
  • __xor__(self, other):异或运算符( ^)
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)


# Usage
v1 = Vector(2, 4)
v2 = Vector(1, 3)
v3 = v1 + v2
print(v3.x, v3.y)  # Output: 3 7

数值类型转换

__int__(self)__float__(self)__complex__(self)等,用于类型转换。

属性访问和描述符方法

  • __getattr__(self, name)__setattr__(self, name, value)__delattr__(self, name):自定义属性访问。
  • __getattribute__(self, name):无条件调用,实现属性访问。
  • __get__(self, instance, owner), __set__(self, instance, value), __delete__(self, instance):
    实现描述符协议。
class ProtectedAttributes:
    def __init__(self):
        self._protected = "This is protected"

    def __getattr__(self, name):
        if name == "secret":
            raise AttributeError("Access Denied")
        return self.__dict__.get(name, f"{name} not found")

    def __setattr__(self, name, value):
        if name == "secret":
            raise AttributeError("Cannot modify secret")
        self.__dict__[name] = value

    def __delattr__(self, name):
        if name == "secret":
            raise AttributeError("Cannot delete secret")
        del self.__dict__[name]


# Usage
obj = ProtectedAttributes()
print(obj._protected)  # Access allowed
print(obj.missing)     # Outputs "missing not found"
# obj.secret            # Raises AttributeError: Access Denied
# obj.secret = "New"    # Raises AttributeError: Cannot modify secret

容器 Magic 方法

  • __len__(self):返回容器的长度。序列和映射协议的一部分。
  • __getitem__(self, key):访问 ( obj[key]) 的行为。
  • __setitem__(self, key, value):赋值obj[key] = value。
  • __delitem__(self, key):删除 ( del obj[key])。
  • __iter__(self):返回容器的迭代器。
  • __contains__(self, item):检查容器是否包含item.
class Library:
    def __init__(self, books):
        self.books = books

    def __len__(self):
        return len(self.books)

    def __getitem__(self, index):
        return self.books[index]


# Usage
library = Library(["Book1", "Book2", "Book3"])
print(len(library))        # Output: 3
print(library[1])          # Output: Book2

上下文管理器

  • __enter__(self)( __aenter__(self)):你可以在代码块的开头使用 with 关键词。这样你就可以使用 as 关键词得到一个包含上下文的块。

  • __exit__(self, exc_type, exc_val, exc_tb)( __aexit__(self, exc_type, exc_val, exc_tv)):在 with 代码块之后调用,它用于结束上下文的一些处理。例如关闭文件或释放锁。此方法接收三个参数(exc_type、exc_val、exc_tb),它们用于管理with块内引发的异常。

class AsyncFileHandler:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
        self.file = None

    async def __aenter__(self):
        self.file = await aiofiles.open(self.filename, self.mode)
        return self.file

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        await self.file.close()


# Usage with asyncio and aiofiles
import asyncio
import aiofiles


async def main():
    async with AsyncFileHandler('example.txt', 'w') as f:
        await f.write('Hello, async world!')


asyncio.run(main())

可调用对象

  • __call__(self, [...]):允许将类的实例作为函数调用 ( def/ async def)。
import asyncio


class AsyncAdder:
    def __init__(self, value):
        self.value = value

    async def __call__(self, x):
        await asyncio.sleep(1)  # Simulate an async operation
        return self.value + x


# Usage in an async context
async def main():
    add_ten = AsyncAdder(10)
    result = await add_ten(20)  # Awaits the __call__ method
    print(result)  # Output: 30


asyncio.run(main())

一元运算及其他

  • __neg__(self):取反 (-obj)。
  • __pos__(self): 加1 ( +obj)。
  • __abs__(self):绝对值 (abs(obj))。