Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Go Mongox 开源库设计分享:简化 MongoDB 开发的最佳实践

Go Mongox 开源库设计分享:简化 MongoDB 开发的最佳实践

原创
作者头像
陈明勇
修改于 2024-11-28 02:36:51
修改于 2024-11-28 02:36:51
4590
举报

文章:求求测试们了,发现BUG后要这么提 评语:这篇文章以实用性和清晰性为核心,从开发视角出发,为测试人员提供了规范提交BUG的详细指南,旨在减少沟通成本、提升效率,是一篇针对实际问题的实战手册。

前言

在使用 Go 语言操作 MongoDB 时,Go 开发者的首选库通常是由 MongoDB 官方团队推出的 mongo-go-driver。这个库是专为 Go 语言开发者打造的,支持 MongoDB 的主要功能,并与最新版本的 MongoDB 兼容。通过 mongo-go-driverGo 开发者可以便捷地连接数据库,并且能对集合进行查询、插入、更新、删除的操作。

尽管 mongo-go-driver 功能强大,但通过进一步封装,可以在实际开发中显著提升开发效率,特别是在复杂场景下减少代码冗余和提升可读性方面。封装后,可以有效解决以下常见的问题:

  • 繁琐的 BSON 数据编写:构建查询条件、更新文档或聚合管道时,往往需要编写大量 BSON 数据结构。简单格式的 BSON 数据较易编写,但面对复杂多层嵌套的文档时,不仅耗时,还容易出错。即便是一个小的疏漏,也可能导致结果偏离预期,增加了调试难度。
  • 重复的反序列化代码:在查询不同集合的数据时,常常需要编写重复的反序列化代码,不仅增加了代码冗余,也提升了维护成本。
  • 聚合管道操作不够友好:在进行聚合操作时,缺少对聚合管道的直观支持。开发者需要手动编写复杂的 BSON 文档来定义管道各个阶段,这增加了复杂性。

因此,我开发了 go mongox 库并针对这些场景进行了优化,利用 Go 语言的泛型特性绑定结构体,同时引入模块化的 CreatorUpdaterDeleterFinderAggregator 等功能,分别简化插入、更新、删除、查询和聚合操作。此外,go mongox 还提供了查询、更新和聚合语句的构建器,以减少代码冗余,提高开发效率,帮助开发者更专注于业务逻辑的实现。

本文将深入解析 go mongox 开源库的设计思路与实践经验。

准备好了吗?准备一杯你最喜欢的咖啡或茶,随着本文一探究竟吧。

仓库地址:https://github.com/chenmingyong0423/go-mongox 官方文档:https://go-mongox.dev

go mongox 简介

go mongox 是一个基于泛型的库,扩展了 MongoDB 的官方框架。通过泛型技术,它实现了结构体与 MongoDB 集合的绑定,旨在提供类型安全和简化的数据操作。go mongox 还引入链式调用,让文档操作更流畅,并且提供了丰富的 BSON 构建器和内置函数,简化了 BSON 数据的构建。此外,它还支持插件化编程和内置多种钩子函数,为数据库操作前后的自定义逻辑提供灵活性,增强了应用的可扩展性和可维护性。

功能特性

  • 泛型的 MongoDB 集合
  • 文档的 CRUD 操作
  • 聚合操作
  • 内置基本的 Model 结构体,自动化更新默认的 field 字段
  • 支持 BSON 数据的构建
  • 支持结构体 tag 校验
  • 内置 Hooks
  • 支持插件化编程

泛型的 Collection

为了将结构体与 MongoDB 的集合进行绑定,mongox 定义了一个泛型 Collection 结构体。通过泛型参数 T any,它提供了类型安全的 MongoDB 集合操作,同时保留了对原始 *mongo.Collection 的访问。

代码语言:go
AI代码解释
复制
type Collection[T any] struct {
	collection *mongo.Collection
}

func (c *Collection[T]) Collection() *mongo.Collection {
	return c.collection
}

func NewCollection[T any](collection *mongo.Collection) *Collection[T] {
	return &Collection[T]{collection: collection}
}

设计特点与优势

  • 类型安全
    • 通过泛型,Collection[T] 可以直接操作不同的数据模型类型 T,避免了传统方法中的类型断言和转换,提高了代码安全性和可读性。
  • 代码复用性
    • 泛型支持高度通用的逻辑封装,使得 CRUD 方法只需实现一次,即可适配所有数据模型类型。这种复用性显著减少了开发和维护成本。
  • 兼容性
    • Collection() 方法允许用户直接访问底层的 *mongo.Collection,保留了原始功能,兼容复杂的 MongoDB 操作需求。

CRUD 操作器

mongox 内置了五个独立的操作器类型:FinderCreatorUpdaterDeleterAggregator,分别负责集合的 查找创建更新删除聚合 操作。这些操作器实例通过 Collection[T] 对象提供,且每个操作器聚焦于一个具体的集合操作。

代码语言:go
AI代码解释
复制
func (c *Collection[T]) Finder() *finder.Finder[T] {
	return finder.NewFinder[T](c.collection)
}

func (c *Collection[T]) Creator() *creator.Creator[T] {
	return creator.NewCreator[T](c.collection)
}

func (c *Collection[T]) Updater() *updater.Updater[T] {
	return updater.NewUpdater[T](c.collection)
}

func (c *Collection[T]) Deleter() *deleter.Deleter[T] {
	return deleter.NewDeleter[T](c.collection)
}
func (c *Collection[T]) Aggregator() *aggregator.Aggregator[T] {
	return aggregator.NewAggregator[T](c.collection)
}
代码语言:go
AI代码解释
复制
// 省略细节代码

type Finder[T any] struct {}

type Creator[T any] struct {}

type Updater[T any] struct {}

type Deleter[T any] struct {}

type Aggregator[T any] struct {}

设计特点与优势:

  • 单一职责
    • 每个操作器聚焦于特定的集合操作,符合单一职责原则(SRP)。通过划分不同的操作器模块,降低了功能间的耦合度。
  • 扩展性强
    • 每个操作器独立实现其功能逻辑,便于扩展。例如:如果需要新增批量更新功能,只需扩展 Updater 类型的功能。新增的功能模块不会影响其他模块的稳定性。
  • 链式调用支持
    • 操作器支持链式调用,便于组合复杂的集合操作,让集合操作的代码写起来更加丝滑。

使用示例

  • Finder
代码语言:go
AI代码解释
复制
user, err := userColl.Finder().
    Filter(query.Id("60e96214a21b1b0001c3d69e")).
    FindOne(context.Background())
  • Creator
代码语言:go
AI代码解释
复制
insertOneResult, err := userColl.Creator().
    InsertOne(context.Background(), &User{Name: "Mingyong Chen", Age: 18})
  • Updater
代码语言:go
AI代码解释
复制
updateResult, err := userColl.Updater().
		Filter(query.Id("60e96214a21b1b0001c3d69e")).
		Updates(update.Set("name", "Mingyong Chen")).
		UpdateOne(context.Background())
  • Deleter
代码语言:go
AI代码解释
复制
deleteResult, err := userColl.Deleter().
    Filter(query.Id("60e96214a21b1b0001c3d69e")).
    DeleteOne(context.Background())
  • Aggregator
代码语言:go
AI代码解释
复制
// 忽略年龄字段,只查询名字
users, err := userColl.Aggregator().
    Pipeline(aggregation.NewStageBuilder().Project(bsonx.M("age", 0)).Build()).
    Aggregate(context.Background())

链式调用

在设计支持链式调用的操作器结构体时,需要明确结构体的职责和需要传递的参数。操作器支持链式调用的本质是 逐步构建操作所需的参数,最终在调用执行方法时将参数完整地传递并执行操作。

Updater 为例,它专注于 更新 操作,在这一场景中,链式调用的目标是通过连续调用方法来逐步完成以下任务:

  • 设置查询条件filter):指定需要更新的文档范围。
  • 定义更新内容updates):明确如何修改文档的字段。
  • 执行更新操作:将构建好的参数应用到数据库的更新方法中。

以下是 Updater 的实现:

代码语言:go
AI代码解释
复制
type Updater[T any] struct {
	collection  *mongo.Collection
	filter      any
	updates     any
}

func (u *Updater[T]) Filter(filter any) *Updater[T] {
	u.filter = filter
	return u
}

func (u *Updater[T]) Updates(updates any) *Updater[T] {
	u.updates = updates
	return u
}

func (u *Updater[T]) UpdateOne(ctx context.Context, opts ...options.Lister[options.UpdateOptions]) (*mongo.UpdateResult, error) {
  // 忽略细节代码
}

func (u *Updater[T]) UpdateMany(ctx context.Context, opts ...options.Lister[options.UpdateOptions]) (*mongo.UpdateResult, error) {
  // 忽略细节代码
}

func (u *Updater[T]) Upsert(ctx context.Context, opts ...options.Lister[options.UpdateOptions]) (*mongo.UpdateResult, error) {
  // 忽略细节代码
}

设计特点与优势

  • 简洁流畅的参数构建
    • 每个链式方法负责构建单一的操作参数(如 Filter 构建查询条件,Updates 构建更新内容),通过链式调用逐步完成复杂操作的参数准备,简化了方法的使用。
  • 符合直觉的调用方式
    • 链式调用的代码逻辑接近自然语言表达。例如:
代码语言:go
AI代码解释
复制
updateResult, err := userColl.Updater().
		Filter(query.Id("60e96214a21b1b0001c3d69e")).
		Updates(update.Set("name", "Mingyong Chen")).
		UpdateOne(context.Background())
  • 高扩展性与一致性
    • 链式方法具有一致的设计风格,新增功能时只需扩展现有链式方法,无需改动底层实现。例如,可以轻松为 Updater 增加 Hook 或日志功能。

对于其他操作器,例如 Creator Finder 等,其设计理念也是类似的。

BSON 构建

mongox 库提供了强大的 BSON 数据构建功能,帮助开发者简化与 MongoDB 交互时复杂 BSON 数据的构建。为了解决开发中常见的构建复杂查询、更新内容以及聚合管道时的繁琐问题,mongox 将功能划分为以下几个包:

  • query
    • 专用于构建查询条件的 BSON 数据。
    • 提供了一系列链式构建器和函数,支持条件拼接($and$or)、范围查询($gt$lt)等复杂查询。
  • update 模块
    • 专注于构建更新操作的 BSON 数据,例如 $set$inc 等。
    • 通过清晰的链式操作,帮助开发者快速构建更新内容。
  • aggregation 模块
    • 专注于构建 MongoDB 的聚合管道(pipeline)。
    • 提供了分步构建复杂聚合管道的工具,支持 $match$group$project 等。
  • bsonx 模块
    • 提供了一系列便捷函数和通用构建器,用于快速构建各种 BSON 数据,覆盖查询、更新和聚合之外的常见需求。

query 包

为了支持简单构建和复杂构建,query 包提供两种构建模式:直接函数构建和构建器构建。

为了支持简单查询语句和复杂查询语句的构建,query 包提供了两种灵活的构建模式:直接函数构建构建器构建。这两种方式的结合满足了从快速构建到复杂逻辑表达的多种需求。

直接函数构建

通过提供简单的函数,开发者可以快速构建包含单个操作符的 BSON 查询条件。这种方式适用于无需组合逻辑的简单查询。

代码语言:go
AI代码解释
复制
func Eq(key string, value any) bson.D {
	return bson.D{bson.E{Key: key, Value: bson.D{{Key: "$eq", Value: value}}}}
}

func Lt(key string, value any) bson.D {
	return bson.D{bson.E{Key: key, Value: bson.D{{Key: "$lt", Value: value}}}}
}

// 忽略其他函数实现

使用示例:

代码语言:go
AI代码解释
复制
// {
//   "name": "陈明勇"	
// }
eq := query.Eq("name", "陈明勇")

构建器构建

对于复杂查询逻辑的构建,mongox 提供了功能强大的 Builder 构建器,通过链式调用的方式逐步构建复杂的 BSON 数据。

代码语言:go
AI代码解释
复制
func NewBuilder() *Builder {
	query := &Builder{
		data: bson.D{},
		err:  make([]error, 0),
	}
	query.comparisonQueryBuilder = comparisonQueryBuilder{parent: query}
	query.logicalQueryBuilder = logicalQueryBuilder{parent: query}
	query.elementQueryBuilder = elementQueryBuilder{parent: query}
	query.arrayQueryBuilder = arrayQueryBuilder{parent: query}
	query.evaluationQueryBuilder = evaluationQueryBuilder{parent: query}
	query.projectionQueryBuilder = projectionQueryBuilder{parent: query}
	return query
}

type Builder struct {
	data bson.D
	comparisonQueryBuilder
	logicalQueryBuilder
	elementQueryBuilder
	arrayQueryBuilder
	evaluationQueryBuilder
	projectionQueryBuilder
}

func (b *Builder) Build() bson.D {
	return b.data
}

构建器的核心是通过组合子构建器(如 comparisonQueryBuilder)实现不同操作符的逻辑。每个子构建器提供其专属的链式方法,Builder 通过组合这些方法形成完整的功能集。

子构建器的实现(示例)

代码语言:go
AI代码解释
复制
type comparisonQueryBuilder struct {
	parent *Builder
}

func (b *comparisonQueryBuilder) Eq(key string, value any) *Builder {
	e := bson.E{Key: EqOp, Value: value}
	if !b.parent.tryMergeValue(key, e) {
		b.parent.data = append(b.parent.data, bson.E{Key: key, Value: bson.D{e}})
	}
	return b.parent
}

func (b *comparisonQueryBuilder) Gt(key string, value any) *Builder {
	e := bson.E{Key: GtOp, Value: value}
	if !b.parent.tryMergeValue(key, e) {
		b.parent.data = append(b.parent.data, bson.E{Key: key, Value: bson.D{e}})
	}
	return b.parent
}

func (b *comparisonQueryBuilder) Lt(key string, value any) *Builder {
	e := bson.E{Key: LtOp, Value: value}
	if !b.parent.tryMergeValue(key, e) {
		b.parent.data = append(b.parent.data, bson.E{Key: key, Value: bson.D{e}})
	}
	return b.parent
}

构建器主功能:

  • 链式调用:开发者可以通过连续调用 Builder 提供的方法来逐步构建查询条件。
  • 复杂逻辑管理:不同的查询逻辑(如比较、逻辑、数组操作)由子构建器独立实现,避免了功能混乱。

使用示例:

代码语言:go
AI代码解释
复制
//	{
//		"age": {
//			"$gt": {
//				"$numberInt": "18"
//			},
//			"$lt": {
//				"$numberInt": "30"
//			}
//		}
//	}
query.NewBuilder().Gt("age", 18).Lt("age", 30).Build()

类似于 query 包,mongox 中的其他模块(如 updateaggregationbsonx)也采用了类似的设计模式,提供了直接函数构建和构建器构建两种方式,支持链式调用以简化复杂逻辑的构建。接下来就不对它们多做介绍了。


设计特点与优势

  • 灵活性:
    • 提供两种构建模式,分别满足简单场景和复杂逻辑场景。
    • 直接函数构建模式适合快速开发,构建器模式支持复杂需求。
  • 职责分离:
    • 不同类型的查询操作(如比较、逻辑、数组)由独立的子构建器负责实现,代码结构清晰,易于扩展。
  • 链式调用:
    • 构建器支持链式调用,用户可以直观地通过方法链逐步构建查询条件,语义清晰,代码自然流畅。
  • 复用性与扩展性:
    • 新增操作符只需扩展对应子构建器,而无需改动核心逻辑。
    • 不同子构建器之间可独立维护,降低了代码的耦合度。

插件化编程

mongox 支持插件化编程,它提供了一种灵活的方式在数据库操作的前后插入自定义的逻辑,从而增强应用的可扩展性和可维护性。非常适合用于以下场景:

  • 默认字段填充:填充 _id 和创建时间以及更新时间的字段值。
  • 日志记录:记录操作前后的信息。
  • 数据验证:在插入或更新前检查数据的有效性。
  • 权限校验:根据业务需求在操作前校验用户权限。

核心设计:Callback 结构体

Callbackmongox 插件化编程的核心。它通过一系列钩子属性(如 beforeInsertafterInsert 等)将自定义逻辑绑定到集合操作的特定阶段。

代码语言:go
AI代码解释
复制
// 全局回调管理器
var Callbacks = initializeCallbacks()

// 初始化 Callback
func initializeCallbacks() *Callback {
	return &Callback{
		beforeInsert: make([]callbackHandler, 0),
		afterInsert:  make([]callbackHandler, 0),
		beforeUpdate: make([]callbackHandler, 0),
		afterUpdate:  make([]callbackHandler, 0),
		beforeDelete: make([]callbackHandler, 0),
		afterDelete:  make([]callbackHandler, 0),
		beforeUpsert: make([]callbackHandler, 0),
		afterUpsert:  make([]callbackHandler, 0),
		beforeFind:   make([]callbackHandler, 0),
		afterFind:    make([]callbackHandler, 0),
	}
}

type Callback struct {
	beforeInsert []callbackHandler
	afterInsert  []callbackHandler
	beforeUpdate []callbackHandler
	afterUpdate  []callbackHandler
	beforeDelete []callbackHandler
	afterDelete  []callbackHandler
	beforeUpsert []callbackHandler
	afterUpsert  []callbackHandler
	beforeFind   []callbackHandler
	afterFind    []callbackHandler
}

type callbackHandler struct {
	name string
	fn   CbFn
}

type CbFn func(ctx context.Context, opCtx *operation.OpContext, opts ...any) error

// operation_type.go
type OpContext struct {
	Col *mongo.Collection `opt:"-"`
	Doc any
	// filter also can be used as query
	Filter       any
	Updates      any
	Replacement  any
	MongoOptions any
	ModelHook    any
}

func (c *Callback) Execute(ctx context.Context, opCtx *operation.OpContext, opType operation.OpType, opts ...any) error {
	switch opType {
	  // 忽略实现细节,根据操作类型 opType 执行对应的回调函数。
	}
	return nil
}
  • 钩子类型:
    • 每个集合操作(如插入、更新、查询等)都有 beforeafter 两种钩子。
    • 钩子以切片形式存储,支持注册多个回调函数,这些函数将按顺序执行。
  • callbackHandler
    • 包含两个属性:
      • name:钩子函数的名称,便于管理和调试。
      • fn:具体的回调函数,实现自定义逻辑。
  • CbFn 回调函数:
    • 定义了统一的函数签名,参数包括:
      • ctx:上下文,用于控制回调的生命周期。
      • opCtx:操作上下文,包含数据库操作相关的参数。
      • opts:可选参数,用于传递额外信息。
  • 回调执行逻辑
    • 通过 Execute 方法,根据操作类型查找对应的钩子列表,并按顺序执行回调。
    • 如果任何一个回调函数返回错误,则中断执行并返回错误信息。

操作上下文:OpContext

OpContext 是回调函数的核心参数,提供了集合操作相关的详细信息,供开发者在回调函数中灵活使用。

代码语言:go
AI代码解释
复制
type OpContext struct {
	Col *mongo.Collection `opt:"-"`  // MongoDB 集合实例
	Doc any                          // 文档
	Filter       any                 // 查询条件
	Updates      any                 // 更新内容
	Replacement  any                 // 替换内容
	MongoOptions any                 // MongoDB 原生选项
	ModelHook    any                 // 用于判断绑定的结构体是否实现 Model Hook
}

核心字段说明:

  • Col:当前操作的集合实例。
  • Doc:文档。
  • Filter:操作的查询条件,如查找、更新或删除时使用。
  • Updates:更新内容。
  • Replacement:替换操作的文档内容。
  • MongoOptions:传递 MongoDB 原生的操作选项。
  • ModelHook:与模型相关的自定义上下文,可扩展使用。

使用示例

  • 注册与删除回调
代码语言:go
AI代码解释
复制
// 注册插件
mongox.RegisterPlugin("after find", func(ctx context.Context, opCtx *operation.OpContext, opts ...any) error {
    if user, ok := opCtx.Doc.(*User); ok {
        fmt.Println(user)
    }
    if users, ok := opCtx.Doc.([]*User); ok {
        fmt.Println(users)
    }
    return nil
}, operation.OpTypeAfterFind)

// 删除插件
mongox.RemovePlugin("after find", operation.OpTypeAfterFind)
  • 执行回调 在实际的集合操作中,调用 Execute 方法以运行注册的回调:
代码语言:go
AI代码解释
复制
err = callback.GetCallback().Execute(ctx, globalOpContext, opType)
if err != nil {
	return
}

设计特点与优势

  • 灵活性: - 每个操作类型支持多个 beforeafter 钩子,开发者可以自由组合和扩展。 可扩展性: - 回调以切片形式存储,允许动态增加、移除或替换钩子函数。
  • 统一性:
    • 回调函数使用统一签名,结合 OpContext 提供全面的操作上下文,便于调试和扩展。
  • 解耦性:
    • 集合操作与业务逻辑分离,回调机制将非核心功能独立实现,保持代码简洁和高可维护性。

小结

本文详细介绍了 go mongox 开源库的设计思路与实践经验,涵盖了多个核心模块的设计与实现,包括以下内容:

  • Collection[T] 的设计与实现:类型安全的集合封装;
  • CRUD 操作器(如 FinderCreatorUpdaterDeleterAggregator):模块化的增删改查设计;
  • 链式调用的实现:简化复杂操作的流畅调用设计;
  • BSON 数据构建包queryupdateaggregate):高效构建查询、更新与聚合相关的 BSON 数据;
  • 插件化编程的设计:通过钩子机制灵活扩展功能。

虽然开发一个功能类似 go mongox 的库并不复杂,但如何通过精心设计实现出色的扩展性、易用性和复用性,才是开发者需要深思的问题。希望这篇文章能为你提供实用的思路与经验。


一起参与贡献吧,让 go mongox 更加实用! 如果有您的加入,go mongox 将会变得更加实用!


你好,我是陈明勇,一名热爱技术、乐于分享的开发者,同时也是开源爱好者。

成功的路上并不拥挤,有没有兴趣结个伴?

关注我,加我好友,一起学习一起进步!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Python深浅拷贝
对于字符串str、整数型int、布尔值bool三种不可变的对象类型,深浅拷贝是一样的,直接在内存中直接开辟空间进行存储。
皮大大
2021/03/02
3830
搞定面试之图解Python深拷贝浅拷贝
「引用」:在 Python 程序中,每个对象都会在内存中申请开辟一块空间来保存该对象,该对象在内存中所在位置的地址被称为引用,使用变量名进行指代。
吾非同
2021/01/06
4200
Python基础 | 深浅拷贝问题、递归函数练习
在实际工作中,经常涉及到数据的传递,在数据传递使用过程中,可能会发生数据被修改的问题。为了防止数据被修改,就需要在传递一个副本,即使副本被修改,也不会影响原数据的使用。为了生成这个副本,就产生了拷贝。下面先了解一下几个概念:对象、可变类型、引用
叶庭云
2021/12/07
4930
Python基础 | 深浅拷贝问题、递归函数练习
python学习笔记:深浅拷贝的使用和原理
在理解深浅拷贝之前,我们先熟悉下变量对象和数据类型 1.变量和对象 变量-引用-对象(可变对象,不可变对象) 在python中一切都是对象,比如[1,2],'hello world',123,{'k1
用户1679793
2018/04/28
7290
python学习笔记:深浅拷贝的使用和原理
python基础之深浅copy
首先在了解python中的深浅拷贝之前,我们先花一点时间来了解一下python内存中变量的存储情况。对于python而言,变量的存储采用了引用语义的方式,存储的只是一个变量值所在的内存地址,而不是这个变量的本身。
天钧
2019/07/26
3840
一、python学习笔记-基本数据类型-深浅拷贝(一)
"""定义 在Python中对象的赋值其实就是对象的引用。当创建一个对象,把它赋值给另一个变量的时候,python并没有拷贝这个对象,只是拷贝了这个对象的引用而已。 浅拷贝:拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已。也就是,把对象复制一遍,但是该对象中引用的其他对象我不复制(快捷方式) 深拷贝:外围和内部元素都进行了拷贝对象本身,而不是引用。也就是,把对象复制一遍,并且该对象中引用的其他对象我也复制。(复制) """ """术语解释 1、变量:是一个系统表的元素,拥有指向对象的连接空间
堕落飞鸟
2022/01/12
2660
​深度解析Python的赋值、浅拷贝、深拷贝
拷贝 就是把原数据复制一份,在复制的数据上随意改动不会影响到其原数据。也就是这里讲的深拷贝。
忆想不到的晖
2021/04/04
5K0
python高级-深浅拷贝(16)
一、浅拷贝 浅拷贝是对一个对象的顶层拷贝,通俗地讲就是:拷贝了引用,并没有拷贝内容。 a = [1,2,3] print(id(a)) b=a print(b) print(id(b)) a.append(4) print(a) print(b) 运行结果为: 1965053928072 [1, 2, 3] 1965053928072 [1, 2, 3, 4] [1, 2, 3, 4] 二、深拷贝 深拷贝是对于一个对象所有层次的拷贝,重新开辟内存地址。 import copy a = [1,2,3] pr
Se7eN_HOU
2019/09/11
3140
Python | Python学习之深浅拷贝
== 是 python 标准操作符中的比较操作符,用来比较判断两个对象的 value(值) 是否相等 。
咸鱼学Python
2019/10/09
4410
Python | Python学习之深浅拷贝
元组、字典、集合的内置方法,散列表、深浅拷贝学习笔记
元组的使用方法(与列表类似):索引取值、索引切片、for循环、成员运算、index获取元素索引、count计数
GH
2022/05/10
3190
元组、字典、集合的内置方法,散列表、深浅拷贝学习笔记
Python深浅拷贝
深浅拷贝分为两部分,一部分是数字和字符串另一部分是列表、元组、字典等其他数据类型。
py3study
2020/01/15
4020
day06(深浅拷贝,元组,字典,集合)
1,今日内容: 1.深浅拷贝:**** 2.元组 - 元组可以存放可变类型 *** 3.字典:***** -- 增删改查 -- 常用方法 4.集合:** -- 集合运算 5.数据类型的相互转化 ******** 6.内存管理 ***** 二,深浅拷贝 ## 拷贝:对值进行复制的过程 # 1,值拷贝:应用场景最多 ls = [1, 'abc', [10]] ls1 = ls # ls1直接将ls中存放的地址拿过来 # ls内部的值发生任何变化,ls1都会随之变化 #2,浅拷贝
py3study
2020/01/16
3750
深拷贝和浅拷贝原来是这样?
为了让读者更好的理解深浅拷贝,在讲深浅拷贝之前要引入基本数据类型 , 引用数据类型 和 数据储存(栈和堆)这几个概念,如果已经理解,可直接跳过这一part。
IT人一直在路上
2019/09/16
4140
由问题入手,步步爬出Python中赋值与拷贝的坑
1、问题的引出 之前遇到了一个求数组中出现次数最多的k个元素的题,我们参照如下的思路进行求解,首先利用一个dict记录所有元素出现的次数,key:value中的key表示元素,value表示元素出现的次数,随后根据元素出现的次数将元素放入对应的桶中,桶是一个二维数组,桶中第一个元素保存出现次数为0的元素,桶中第二个元素保存出现次数为1的元素,依次类推。最后从后往前遍历桶,取出出现次数最多的k个元素即可。 按照这样的思路,我写了如下的代码: class Solution(object): def to
石晓文
2018/04/11
9240
由问题入手,步步爬出Python中赋值与拷贝的坑
JS复习之深浅拷贝
  想掌握JS的深浅拷贝,首先来回顾一下JS的数据类型,JS中数据类型分为基本数据类型和引用数据类型。
huofo
2022/03/18
3980
JS复习之深浅拷贝
js数组的拷贝赋值复制-你真的懂?
在看react-native性能优化的时候,看到如何避免shouldComponentUpdate的异常数据时,脑内一阵风暴,从而牵连出一连串的问题,于是有了这一篇关于js数组的复制(深浅拷贝)与赋值等为何能产生异常数据的文章。 有什么问题欢迎指正 现在进入正题: 首先异常数据的产生在于我们在复制赋值时,会有或没有改变到本身的值。 一、push与concat push的定义是:像数组末尾添加一个或更多元素,并返回新的长度。该方法会改变数组的长度。 concat的定义是:连接两个或更多的数组,并返回结果,该方
IT架构圈
2018/05/31
4.9K0
python学习笔记:第7天 深浅拷贝
join方法是把一个列表中的数据进行拼接,拼接成字符串(与split方法相反,split方法是把一个字符串切割成列表)
py3study
2020/01/20
4160
学习Python一年,这次终于弄懂了浅拷贝和深拷贝
话说,网上已经有很多关于Python浅拷贝和深拷贝的文章了,不过好多文章看起来还是决定似懂非懂,所以决定用自己的理解来写出这样一篇文章。
宇宙之一粟
2020/10/26
6980
学习Python一年,这次终于弄懂了浅拷贝和深拷贝
Python|赋值、浅拷贝与深拷贝
在python中一个变量可以说是内存中一个对象的‘标签’或者‘引用’。假设现在有一个变量a。
算法与编程之美
2019/07/17
7120
Python基础三
不可变的数据类型公用,可变的数据类型重新开辟一个空间,对源数据进行修改,深拷贝的内容不进行改变
changxin7
2019/09/10
1.4K0
相关推荐
Python深浅拷贝
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档