首页 > Python资料 博客日记

Python魔法之旅-魔法方法(07)

2024-06-04 02:00:04Python资料围观146

本篇文章分享Python魔法之旅-魔法方法(07),对你有帮助的话记得收藏一下,看Python资料网收获更多编程知识

目录

一、概述

1、定义

2、作用

二、应用场景

1、构造和析构

2、操作符重载

3、字符串和表示

4、容器管理

5、可调用对象

6、上下文管理

7、属性访问和描述符

8、迭代器和生成器

9、数值类型

10、复制和序列化

11、自定义元类行为

12、自定义类行为

13、类型检查和转换

14、自定义异常

三、学习方法

1、理解基础

2、查阅文档

3、编写示例

4、实践应用

5、阅读他人代码

6、参加社区讨论

7、持续学习

8、练习与总结

9、注意兼容性

10、避免过度使用

四、魔法方法

23、__getattribute__方法

23-1、语法

23-2、参数

23-3、功能

23-4、返回值

23-5、说明

23-6、用法

24、__getitem__方法

24-1、语法

24-2、参数

24-3、功能

24-4、返回值

24-5、说明

24-6、用法

25、__getnewargs__方法

25-1、语法

25-2、参数

25-3、功能

25-4、返回值

25-5、说明

25-6、用法

五、推荐阅读

1、Python筑基之旅

2、Python函数之旅

3、Python算法之旅

4、博客个人主页

一、概述

1、定义

        魔法方法(Magic Methods/Special Methods,也称特殊方法或双下划线方法)是Python中一类具有特殊命名规则的方法,它们的名称通常以双下划线(`__`)开头和结尾

        魔法方法用于在特定情况下自动被Python解释器调用,而不需要显式地调用它们,它们提供了一种机制,让你可以定义自定义类时具有与内置类型相似的行为。

2、作用

        魔法方法允许开发者重载Python中的一些内置操作或函数的行为,从而为自定义的类添加特殊的功能

二、应用场景

1、构造和析构

1-1、__init__(self, [args...]):在创建对象时初始化属性。
1-2、__new__(cls, [args...]):在创建对象时控制实例的创建过程(通常与元类一起使用)。
1-3、__del__(self):在对象被销毁前执行清理操作,如关闭文件或释放资源。

2、操作符重载

2-1、__add__(self, other)、__sub__(self, other)、__mul__(self, other)等:自定义对象之间的算术运算。
2-2、__eq__(self, other)、__ne__(self, other)、__lt__(self, other)等:定义对象之间的比较操作。

3、字符串和表示

3-1、__str__(self):定义对象的字符串表示,常用于print()函数。
3-2、__repr__(self):定义对象的官方字符串表示,用于repr()函数和交互式解释器。

4、容器管理

4-1、__getitem__(self, key)、__setitem__(self, key, value)、__delitem__(self, key):用于实现类似列表或字典的索引访问、设置和删除操作。
4-2、__len__(self):返回对象的长度或元素个数。

5、可调用对象

5-1、__call__(self, [args...]):允许对象像函数一样被调用。

6、上下文管理

6-1、__enter__(self)、__exit__(self, exc_type, exc_val, exc_tb):用于实现上下文管理器,如with语句中的对象。

7、属性访问和描述符

7-1、__getattr__, __setattr__, __delattr__:这些方法允许对象在访问或修改不存在的属性时执行自定义操作。
7-2、描述符(Descriptors)是实现了__get__, __set__, 和__delete__方法的对象,它们可以控制对另一个对象属性的访问。

8、迭代器和生成器

8-1、__iter__和__next__:这些方法允许对象支持迭代操作,如使用for循环遍历对象。
8-2、__aiter__, __anext__:这些是异步迭代器的魔法方法,用于支持异步迭代。

9、数值类型

9-1、__int__(self)、__float__(self)、__complex__(self):定义对象到数值类型的转换。
9-2、__index__(self):定义对象用于切片时的整数转换。

10、复制和序列化

10-1、__copy__和__deepcopy__:允许对象支持浅复制和深复制操作。
10-2、__getstate__和__setstate__:用于自定义对象的序列化和反序列化过程。

11、自定义元类行为

11-1、__metaclass__(Python 2)或元类本身(Python 3):允许自定义类的创建过程,如动态创建类、修改类的定义等。

12、自定义类行为

12-1、__init__和__new__:用于初始化对象或控制对象的创建过程。
12-2、__init_subclass__:在子类被创建时调用,允许在子类中执行一些额外的操作。

13、类型检查和转换

13-1、__instancecheck__和__subclasscheck__:用于自定义isinstance()和issubclass()函数的行为。

14、自定义异常

14-1、你可以通过继承内置的Exception类来创建自定义的异常类,并定义其特定的行为。

三、学习方法

        要学好Python的魔法方法,你可以遵循以下方法及步骤:

1、理解基础

        首先确保你对Python的基本语法、数据类型、类和对象等概念有深入的理解,这些是理解魔法方法的基础。

2、查阅文档

        仔细阅读Python官方文档中关于魔法方法的部分,文档会详细解释每个魔法方法的作用、参数和返回值。你可以通过访问Python的官方网站或使用help()函数在Python解释器中查看文档。

3、编写示例

        为每个魔法方法编写简单的示例代码,以便更好地理解其用法和效果,通过实际编写和运行代码,你可以更直观地感受到魔法方法如何改变对象的行为。

4、实践应用

        在实际项目中尝试使用魔法方法。如,你可以创建一个自定义的集合类,使用__getitem__、__setitem__和__delitem__方法来实现索引操作。只有通过实践应用,你才能更深入地理解魔法方法的用途和重要性。

5、阅读他人代码

        阅读开源项目或他人编写的代码,特别是那些使用了魔法方法的代码,这可以帮助你学习如何在实际项目中使用魔法方法。通过分析他人代码中的魔法方法使用方式,你可以学习到一些新的技巧和最佳实践。

6、参加社区讨论

        参与Python社区的讨论,与其他开发者交流关于魔法方法的使用经验和技巧,在社区中提问或回答关于魔法方法的问题,这可以帮助你更深入地理解魔法方法并发现新的应用场景。

7、持续学习

        Python语言和其生态系统不断发展,新的魔法方法和功能可能会不断被引入,保持对Python社区的关注,及时学习新的魔法方法和最佳实践。

8、练习与总结

        多做练习,通过编写各种使用魔法方法的代码来巩固你的理解,定期总结你学到的知识和经验,形成自己的知识体系。

9、注意兼容性

        在使用魔法方法时,要注意不同Python版本之间的兼容性差异,确保你的代码在不同版本的Python中都能正常工作。

10、避免过度使用

        虽然魔法方法非常强大,但过度使用可能会导致代码难以理解和维护,在编写代码时,要权衡使用魔法方法的利弊,避免滥用。

        总之,学好Python的魔法方法需要不断地学习、实践和总结,只有通过不断地练习和积累经验,你才能更好地掌握这些强大的工具,并在实际项目中灵活运用它们。

四、魔法方法

23、__getattribute__方法

23-1、语法
__getattribute__(self, name, /)
    Return getattr(self, name)
23-2、参数

23-2-1、self(必须)一个对实例对象本身的引用,在类的所有方法中都会自动传递。 

23-2-2、name(必须)一个字符串,表示你尝试访问的属性的名称。

23-2-3、/(可选)这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。

23-3、功能

        用于拦截对对象属性的访问。

23-4、返回值

        返回值是被访问属性的值,这可以是任何类型的值,包括整数、浮点数、字符串、列表、字典等或者甚至是另一个对象

23-5、说明

        如果 __getattribute__ 方法没有返回任何值(即没有return语句),那么它实际上会返回None,但这通常是不希望的,因为它可能会掩盖其他潜在的问题。

        由于__getattribute__方法拦截所有属性访问,包括对象自身的属性和继承自基类的属性,因此在使用时需要特别小心,以避免无限递归或其他意外行为

23-6、用法
# 023、__getattribute__方法:
# 1、基本访问控制
class AccessControl:
    def __init__(self, data):
        self._data = data
    def __getattribute__(self, name):
        if name == '_data':
            raise AttributeError("Direct access to _data is not allowed")
        return super().__getattribute__(name)
if __name__ == '__main__':
    ac = AccessControl({'secret': 'value'})
    # ac._data  # 这会引发AttributeError: Direct access to _data is not allowed

# 2、属性惰性加载
class LazyLoad:
    def __init__(self):
        self._loaded = False
    def load_data(self):
        print("Loading data...")
        self._data = "Loaded data"
        self._loaded = True
    def __getattribute__(self, name):
        if name == '_data' and not self._loaded:
            self.load_data()
        return super().__getattribute__(name)
if __name__ == '__main__':
    ll = LazyLoad()
    print(ll._data)  # 第一次会加载数据并输出
    print(ll._data)  # 第二次不会再次加载

# 3、属性访问记录
class AccessLogger:
    def __init__(self):
        self._access_log = []
        self._methods = {}  # 用于存储占位符方法的字典
    def __getattr__(self, name):
        if name not in self._methods:
            # 创建一个新的占位符方法,并存储到字典中
            def placeholder(*args, **kwargs):
                self._access_log.append(name)
                raise AttributeError(f"AccessLogger has no attribute or method '{name}'")
            self._methods[name] = placeholder
        return self._methods[name]
    def log(self):
        return self._access_log
if __name__ == '__main__':
    al = AccessLogger()
    try:
        al.method1()  # 这会触发占位符方法并记录 'method1'
        al.method2()  # 这会触发占位符方法并记录 'method2'
    except AttributeError as e:
        print(e)  # 输出:AccessLogger has no attribute or method 'method1'
        print(e)  # 输出:AccessLogger has no attribute or method 'method2'
    print(al.log())  # 输出 ['method1']

# 4、只读属性
class ReadOnly:
    def __init__(self, value):
        self._value = value

    def __getattribute__(self, name):
        if name == '_value':
            return super().__getattribute__(name)
        if name.startswith('read_'):
            return super().__getattribute__(name)
        if name == 'value':
            raise AttributeError("value is read-only")
    def read_value(self):
        return self._value
if __name__ == '__main__':
    ro = ReadOnly(10)
    print(ro.read_value())  # 输出 10
    # ro.value = 20  # 这会引发 AttributeError

# 5、动态属性
class DynamicProps:
    def __getattribute__(self, name):
        if name == 'dynamic_prop':
            return f"This is a {name} with value generated on the fly."
        return super().__getattribute__(name)
if __name__ == '__main__':
    dp = DynamicProps()
    print(dp.dynamic_prop)  # 输出 "This is a dynamic_prop with value generated on the fly."

# 6、属性验证
class Validated:
    def __setattr__(self, name, value):
        if name == 'value' and not isinstance(value, int):
            raise ValueError("value must be an integer")
        super().__setattr__(name, value)
    def __getattribute__(self, name):
        attr = super().__getattribute__(name)
        if name == 'value' and not isinstance(attr, int):
            raise AttributeError("value has been corrupted")
        return attr
if __name__ == '__main__':
    v = Validated()
    v.value = 10
    # v.value = "ten"  # 这会引发ValueError: value must be an integer

# 7、属性别名
class Alias:
    def __init__(self, data):
        self._data = data
    def __getattribute__(self, name):
        if name == 'alias_data':
            return super().__getattribute__('_data')
        return super().__getattribute__(name)
if __name__ == '__main__':
    a = Alias('some data')
    print(a.alias_data)  # 输出 'some data'

# 8、条件性访问
class ConditionalAccess:
    def __init__(self, data, condition):
        self._data = data
        self._access_condition = condition
    def __getattribute__(self, name):
        # 调用内置的__getattribute__方法来避免无限递归
        # 但我们先检查是否是我们想要控制的属性
        if name == '_data' and not object.__getattribute__(self, '_access_condition'):
            raise AttributeError("Access to _data is not allowed under current condition")
        # 对于其他属性,正常返回
        return object.__getattribute__(self, name)
    @property
    def access_condition(self):
        return object.__getattribute__(self, '_access_condition')
    @access_condition.setter
    def access_condition(self, value):
        object.__setattr__(self, '_access_condition', value)
if __name__ == '__main__':
    ca = ConditionalAccess('sensitive data', False)
    # 尝试访问 _data 会引发 AttributeError
    try:
        print(ca._data)
    except AttributeError as e:
        print(e)
    # 允许访问 _data
    ca.access_condition = True
    print(ca._data)  # 现在可以访问 _data,因为 access_condition 为 True

24、__getitem__方法

24-1、语法
__getitem__(self, key, /)
    return self.__getitem__(key) <==> self[key]
24-2、参数

24-2-1、self(必须)一个对实例对象本身的引用,在类的所有方法中都会自动传递。 

24-2-2、key(必须)一个用于索引或切片对象的值。

24-2-3、/(可选)这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。

24-3、功能

        用于实现对象的索引和切片功能。

24-4、返回值

        返回被索引或切片访问的元素的值。

24-5、说明

        如果key是整数,则执行索引访问;如果key是slice对象,则执行切片访问。对于无效的索引(例如,超出范围的整数索引或不支持的索引类型),__getitem__方法应该抛出相应的异常。

24-6、用法
# 024、__getitem__方法:
# 1、简单的列表包装类
class MyList:
    def __init__(self, data):
        self.data = data
    def __getitem__(self, index):
        return self.data[index]
if __name__ == '__main__':
    my_list = MyList([1, 2, 3, 4])
    print(my_list[1])  # 输出 2

# 2、字典的键访问
class MyDict:
    def __init__(self, data):
        self.data = data
    def __getitem__(self, key):
        return self.data[key]
if __name__ == '__main__':
    my_dict = MyDict({'a': 1, 'b': 2})
    print(my_dict['a'])  # 输出 1

# 3、字符串索引(仅支持正索引)
class MyString:
    def __init__(self, string):
        self.string = string
    def __getitem__(self, index):
        if index < 0:
            raise IndexError("Negative indices are not supported")
        return self.string[index]
if __name__ == '__main__':
    my_string = MyString("hello")
    print(my_string[1])  # 输出 'e'

# 4、范围对象(步长访问)
class MyRange:
    def __init__(self, start, end, step=1):
        self.start = start
        self.end = end
        self.step = step
    def __getitem__(self, index):
        if index < 0:
            raise IndexError("Negative indices are not supported")
        return self.start + (index * self.step) if self.start + (index * self.step) < self.end else None
if __name__ == '__main__':
    my_range = MyRange(0, 10, 2)
    print(my_range[2])  # 输出 4

# 5、矩阵索引(二维数组)
class Matrix:
    def __init__(self, data):
        self.data = data
    def __getitem__(self, index):
        return self.data[index]
if __name__ == '__main__':
    # 假设有一个二维列表作为矩阵数据
    matrix = Matrix([[1, 2], [3, 4], [5, 6]])
    print(matrix[1][0])  # 输出 3,但注意这里第一个 __getitem__ 返回的是行,第二个是 Python 内置的列表索引

# 6、自定义文件读取(按行索引)
class MyFile:
    def __init__(self, filename):
        self.filename = filename
        self.lines = []
        with open(self.filename, 'r') as file:
            for line in file:
                self.lines.append(line.strip())
    def __getitem__(self, index):
        return self.lines[index]
if __name__ == '__main__':
    my_file = MyFile('test.txt')
    print(my_file[0])  # 输出文件的第一行内容

# 7、自定义日期范围(按日期索引)
from datetime import datetime, timedelta
class DateRange:
    def __init__(self, start_date, end_date):
        self.start_date = start_date
        self.end_date = end_date
        self.current_date = start_date
    def __getitem__(self, index):
        self.current_date += timedelta(days=index)
        if self.current_date > self.end_date:
            raise IndexError("Index out of range")
        return self.current_date.date()
if __name__ == '__main__':
    start = datetime(2024, 3, 13)
    end = datetime(2024, 5, 31)
    date_range = DateRange(start, end)
    print(date_range[2].strftime('%Y-%m-%d'))  # 输出 '2024-03-15'
    # 注意:这个示例中的__getitem__改变了内部状态,通常不建议这样做,除非有明确的需求。

# 8、自定义字典,通过属性名访问值
class AttributeDict:
    def __init__(self, *args, **kwargs):
        self.__dict__.update(*args, **kwargs)
    def __getitem__(self, key):
        return getattr(self, key)
if __name__ == '__main__':
    attr_dict = AttributeDict(a=1, b=2)
    print(attr_dict['a'])  # 输出 1

# 9、自定义树形结构,通过路径访问节点
class TreeNode:
    def __init__(self, value, children=None):
        self.value = value
        self.children = children if children is not None else {}
    def __getitem__(self, key):
        if key in self.children:
            return self.children[key]
        raise KeyError(f"No child node with key: {key}")
if __name__ == '__main__':
    # 示例树形结构
    root = TreeNode("root", {
        "child1": TreeNode("child1"),
        "child2": TreeNode("child2", {
            "grandchild": TreeNode("grandchild")
        })
    })
    # 访问节点
    print(root["child2"]["grandchild"].value)  # 输出 'grandchild'

# 10、自定义文件读取,按块(chunk)索引
class ChunkedFileReader:
    def __init__(self, filename, chunk_size):
        self.filename = filename
        self.chunk_size = chunk_size
        self.file_handle = open(filename, 'rb')
    def __getitem__(self, index):
        self.file_handle.seek(index * self.chunk_size)
        data = self.file_handle.read(self.chunk_size)
        if not data:
            raise IndexError("Index out of range")
        return data
    def __del__(self):
        self.file_handle.close()
if __name__ == '__main__':
    chunked_reader = ChunkedFileReader('example.bin', 1024)  # 每个块1024字节
    print(chunked_reader[0].hex())  # 输出第一个块的内容的十六进制表示

# 11、自定义颜色查找表(通过颜色名访问RGB值)
class ColorLookup:
    def __init__(self, colors):
        self.colors = colors
    def __getitem__(self, key):
        return self.colors.get(key, "Unknown color")
if __name__ == '__main__':
    colors = ColorLookup({"red": (255, 0, 0), "green": (0, 255, 0), "blue": (0, 0, 255)})
    print(colors['red'])  # 输出 (255, 0, 0)
    print(colors['purple'])  # 输出 'Unknown color'

# 12、自定义二维数组(类似NumPy数组,但简化版)
class Simple2DArray:
    def __init__(self, data):
        self.data = data
    def __getitem__(self, index):
        if isinstance(index, int):
            return [row[index] for row in self.data]
        elif isinstance(index, tuple) and len(index) == 2:
            row, col = index
            return self.data[row][col]
        else:
            raise IndexError("Invalid index")
if __name__ == '__main__':
    array_2d = Simple2DArray([[3, 5, 6], [8, 10, 11], [7, 8, 12]])
    print(array_2d[1])  # 输出 [5, 10, 8]
    print(array_2d[1, 2])  #  输出 11

25、__getnewargs__方法

25-1、语法
__getnewargs__(self, /)
25-2、参数

25-2-1、self(必须)一个对实例对象本身的引用,在类的所有方法中都会自动传递。 

25-2-2、/(可选)这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。

25-3、功能

        用于支持pickle模块的自定义序列化。

25-4、返回值

        返回一个元组,该元组中的元素将作为参数传递给对象的__new__方法来重新创建对象的一个新实例。

25-5、说明

        如果对象不需要额外的参数来重新创建(即,它可以通过默认构造函数重新创建),那么__getnewargs__可以简单地返回一个空元组。

25-6、用法
# 025、__getnewargs__方法:
# 1、自定义整数范围
import pickle
class IntRange:
    def __init__(self, start, end):
        self.start = start
        self.end = end
    def __getnewargs__(self):
        return (self.start, self.end)
if __name__ == '__main__':
    range_obj = IntRange(1, 10)
    pickled = pickle.dumps(range_obj)
    unpickled = pickle.loads(pickled)
    print(unpickled.start, unpickled.end)  # 输出 1 10

# 2、自定义颜色类
import pickle
class Color:
    def __init__(self, r, g, b):
        self.r = r
        self.g = g
        self.b = b
    def __getnewargs__(self):
        return (self.r, self.g, self.b)
if __name__ == '__main__':
    color_obj = Color(255, 0, 0)
    pickled = pickle.dumps(color_obj)
    unpickled = pickle.loads(pickled)
    print(unpickled.r, unpickled.g, unpickled.b)  # 输出 255 0 0

# 3、自定义坐标点
import pickle
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __getnewargs__(self):
        return (self.x, self.y)
if __name__ == '__main__':
    point_obj = Point(10, 20)
    pickled = pickle.dumps(point_obj)
    unpickled = pickle.loads(pickled)
    print(unpickled.x, unpickled.y)  # 输出 10 20

# 4、自定义复数类
import pickle
class ComplexNumber:
    def __init__(self, real, imag):
        self.real = real
        self.imag = imag
    def __getnewargs__(self):
        return (self.real, self.imag)
if __name__ == '__main__':
    complex_obj = ComplexNumber(3, 4)
    pickled = pickle.dumps(complex_obj)
    unpickled = pickle.loads(pickled)
    print(unpickled.real, unpickled.imag)  # 输出 3 4

# 5、自定义日期类
import pickle
from datetime import date
class CustomDate:
    def __init__(self, year, month, day):
        self.date = date(year, month, day)
    def __getnewargs__(self):
        return (self.date.year, self.date.month, self.date.day)
if __name__ == '__main__':
    date_obj = CustomDate(2024, 3, 13)
    pickled = pickle.dumps(date_obj)
    unpickled = pickle.loads(pickled)
    print(unpickled.date)  # 输出类似 '2024-03-13' 的日期

# 6、自定义分数类
import pickle
from fractions import Fraction
class CustomFraction:
    def __init__(self, numerator, denominator):
        self.fraction = Fraction(numerator, denominator)
    def __getnewargs__(self):
        return (self.fraction.numerator, self.fraction.denominator)
if __name__ == '__main__':
    fraction_obj = CustomFraction(1, 3)
    pickled = pickle.dumps(fraction_obj)
    unpickled = pickle.loads(pickled)
    print(unpickled.fraction)  # 输出 1/3

# 7、自定义带版本的类
import pickle
class VersionedClass:
    def __init__(self, data, version):
        self.data = data
        self.version =version
    def __getnewargs__(self):
        return (self.data, self.version)
    def __getstate__(self):
        # 如果需要,可以覆盖此方法以保存额外的状态
        return self.__dict__
    def __setstate__(self, state):
        # 如果需要,可以覆盖此方法以在反序列化时设置状态
        self.__dict__.update(state)
if __name__ == '__main__':
    versioned_obj = VersionedClass("example data", 1)
    pickled = pickle.dumps(versioned_obj)
    unpickled = pickle.loads(pickled)
    print(unpickled.data, unpickled.version) # 输出 example data 1

# 8、自定义具有动态属性的类
import pickle
class DynamicProperties:
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)
    def __getnewargs__(self):
        # 因为属性是动态的,我们可能需要将它们序列化为一个字典
        return (self.__dict__,)
    def __getstate__(self):
        # 返回一个表示对象状态的字典
        return self.__dict__
    def __setstate__(self, state):
        # 设置对象状态
        self.__dict__.update(state)
if __name__ == '__main__':
    dynamic_obj = DynamicProperties(name="Myelsa", age=18, city="Guangzhou")
    pickled = pickle.dumps(dynamic_obj)
    unpickled = pickle.loads(pickled)
    print(unpickled.name, unpickled.age, unpickled.city)  # 输出 Myelsa 18 Guangzhou

# 9、自定义带时间戳的日志条目
import pickle
from datetime import datetime
class LogEntry:
    def __init__(self, message, timestamp=None):
        self.message = message
        self.timestamp = timestamp or datetime.now()
    def __getnewargs__(self):
        # 假设我们想要重新创建日志条目时保留原始的时间戳
        return (self.message, self.timestamp)
if __name__ == '__main__':
    log_entry = LogEntry("System started")
    pickled = pickle.dumps(log_entry)
    unpickled = pickle.loads(pickled)
    print(unpickled.message, unpickled.timestamp)  # 输出类似 "System started 2024-05-31 23:29:16.357606"

# 10. 自定义用户账户类(带密码哈希)
import pickle
from hashlib import sha256
class UserAccount:
    def __init__(self, username, password):
        self.username = username
        self.password_hash = sha256(password.encode()).hexdigest()
    def __getnewargs__(self):
        # 注意:出于安全考虑,我们不会直接序列化密码哈希用于反序列化
        # 这里仅作为示例,通常不会这样做
        return (self.username, self.password_hash)
    # 注意:在真实应用中,密码不应以明文形式存储或传输
if __name__ == '__main__':
    user = UserAccount("Myelsa", "mypassword")
    # 通常,我们不会序列化/反序列化此类对象,因为这涉及安全问题
    # 但为了示例,我们仍然这样做
    pickled = pickle.dumps(user)
    unpickled = pickle.loads(pickled)
    print(unpickled.username, unpickled.password_hash)  # 输出类似 "Myelsa" 和密码哈希值89e01536ac207279409d4de1e5253e01f4a1769e696db0d6062ca9b8f56767c8

# 11、自定义文件路径和打开模式
import pickle
class FilePath:
    def __init__(self, path, mode):
        self.path = path
        self.mode = mode
    def __getnewargs__(self):
        return (self.path, self.mode)
    def open(self):
        return open(self.path, self.mode)
if __name__ == '__main__':
    file_path = FilePath("test.txt", "r")
    pickled = pickle.dumps(file_path)
    unpickled = pickle.loads(pickled)
    with unpickled.open() as f:
        print(f.read())  # 假设文件存在且可读

# 12、自定义带有自定义属性的矩形
import pickle
class Rectangle:
    def __init__(self, width, height, color="red"):
        self.width = width
        self.height = height
        self.color = color
    def __getnewargs__(self):
        return (self.width, self.height, self.color)
if __name__ == '__main__':
    rectangle = Rectangle(10, 5, "blue")
    pickled = pickle.dumps(rectangle)
    unpickled = pickle.loads(pickled)
    print(unpickled.width, unpickled.height, unpickled.color)  # 输出 10 5 blue

五、推荐阅读

1、Python筑基之旅

2、Python函数之旅

3、Python算法之旅

4、博客个人主页


版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐