首页 > 其他分享 >函数中可变参数的应用

函数中可变参数的应用

时间:2023-04-11 09:58:27浏览次数:26  
标签:passengers 函数 self bus1 参数 可变 print def name

背景

在函数或类定义中传入的参数是可变参数,常见的是字典、列表、数组(ndarray),函数内容如果仅仅是引用该这些对象没有什么大问题。但是如果涉及增、删操作,将会发生非常诡异的事情。

下面以《流畅的Python》中定义的一个案例进行介绍:

class HauntedBus:
    def __init__(self, passengers=[]):
        self.passengers = passengers

    def pick(self, name):
        self.passengers.append(name)

    def drop(self, name):
        self.passengers.remove(name)


passengers = ['Alice', 'Bill', 'Carrie', "Dave"]
bus1 = HauntedBus(passengers)
bus1.pick("Charlie")
bus1.drop("Alice")  # Alice下车
print(f"bus1.passengers={bus1.passengers}")  #
print(f"passengers={passengers}")
"""
bus1.passengers=['Bill', 'Carrie', 'Dave', 'Charlie']
passengers=['Bill', 'Carrie', 'Dave', 'Charlie']
"""

类HauntedBus违反了涉及接口的最佳实践,即“最少惊讶原则”。学生从校车中下车后,他的名字就从篮球队消失了。

简单解释就是:实例的修改不能影响其它外部变量。

解决问题

通过python内置的数据结构可知,列表、字典是可变的数据对象.而且赋值是浅拷贝,所在在该模式下修改赋值后的变量也会影响源变量。针对上述问题解决方案就是将对应的变量进行copy。

class HauntedBus:
    def __init__(self, passengers=[]):
        self.passengers = passengers.copy()
        

    def pick(self, name):
        self.passengers.append(name)

    def drop(self, name):
        self.passengers.remove(name)


passengers = ['Alice', 'Bill', 'Carrie', "Dave"]
bus1 = HauntedBus(passengers)
bus1.pick("Charlie")
bus1.drop("Alice")  # Alice下车
print(f"bus1.passengers={bus1.passengers}")  #
print(f"passengers={passengers}")
"""
bus1.passengers=['Bill', 'Carrie', 'Dave', 'Charlie']
passengers=['Alice', 'Bill', 'Carrie', 'Dave']
"""

然而copy并不总是有效,如果当前这个数据对象非常大的情况下,copy将比较耗时,此时比较便捷的方式就是基于目标数据结构进行输出数据重构。

这种情况在输入的参数是字典时(且嵌套层级较多时),尤为明显。

ndarray中类似的问题

import numpy as np

a = np.arange(10)


def func(a):
    """测试,将a的前2个值修改为0"""
    a[:2] = 0
    return True


print(f"before a={a}")
func(a)
print(f"after a={a}")
"""
before a=[0 1 2 3 4 5 6 7 8 9]
after a=[0 0 2 3 4 5 6 7 8 9]
"""

def func2(a):
    """测试,将a的前2个值修改为0"""
    b=a.copy()
    b[:2] = 0
    print(f"b={b}")
    return True

c=np.arange(10)
print(f"before c={c}")
func2(c)
print(f"after c={c}")
"""
before c=[0 1 2 3 4 5 6 7 8 9]
b=[0 0 2 3 4 5 6 7 8 9]
after c=[0 1 2 3 4 5 6 7 8 9]
"""

小结

  • 输入的参数如果是可变对象,若涉及对象修改问题需慎重考虑:
    • 单通道串行:正常操作即可
    • 多通道并行(存在多个对象同时或部分同时应用的情况):
      • 若数据体量较小,可以采用深拷贝或浅拷贝的方式
      • 若数据体量较大,且浅拷贝不足以解决问题时,但一般情况不建议深拷贝。通常基于目标数据格式进行重组。

标签:passengers,函数,self,bus1,参数,可变,print,def,name
From: https://www.cnblogs.com/AzeHan/p/17305093.html

相关文章

  • MySQL函数
    HEX[[email protected]][test]>select16,HEX(16);+----+---------+|16|HEX(16)|+----+---------+|16|10|+----+---------+1rowinset(0.00sec) CAST[[email protected]][test]>createtabletest_col_sort(userchar(10),typeenum(�......
  • Kubernetes 集群 Pod 资源结构定义及常用配置参数(四)
    Pod资源结构一个Pod中会运行一个或多个容器,实际上每一个pod都至少有两个容器,一个是pod根容器,一个是应用容器,应用容器都是建立在根容器之上,根容器上会绑定ip地址,应用容器里面只是提供了业务和开放了端口如果一个pod中有多个容器,他们其实都是共享的根容器的地址,至于每个容......
  • Context响应,重定向,自定义函数,Abort
    前言:Context对象提供了很多内置的响应形式,JSON、HTML、Protobuf、MsgPack、Yaml、String等。它会为每一种形式都单独定制一个渲染器。Context是Gin最重要的部分。它允许我们在中间件之间传递变量,管理流程,验证请求的JSON并呈现JSON响应。正文: content响应字符串,json,及......
  • 57、K8S-监控机制-Prometheus-PromQL基础-运算符、聚合、功能函数
    Kubernetes学习目录1、数据基础1.1、时间序列1.1.1、介绍时间序列数据:按照时间顺序记录系统、设备状态变化的数据,每个数据称为一个样本;数据采集以特定的时间周期进行,因而,随着时间流逝,将这些样本数据记录下来,将生成一个离散的样本数据序列;该序列也称为向量(Vector);而将多个序......
  • 用驼峰的实体类接受命名不规范的响应参数
    参考资料地址:https://blog.csdn.net/qq_41143240/article/details/115671561使用JsonProperty注解importcom.alibaba.fastjson.JSON;importcom.fasterxml.jackson.annotation.JsonProperty;importlombok.Data;importjava.util.HashMap;/***用驼峰的实体类接受命......
  • 视图,触发器,事务,存储过程,内置函数,流程控制,索引
    目录SQL注入问题视图1、什么是视图2、为什么要用视图3、如何用视图触发器为何要用触发器创建触发器语法事务(掌握)什么是事务事务的作用事务的4个属性(ACID)如何用存储过程基本使用三种开发模型第一种第二种第三种创建存储过程如何用存储过程函数流程控制索引b+树聚集索引(primaryk......
  • 定义一个基类Base,有两个公有成员函数fn1,fn2,私有派生出Derived类,如何通过Derived类
    定义一个基类Base,有两个公有成员函数fn1,fn2,私有派生出Derived类,如何通过Derived类的对象调用基类的函数fn1。#include<bits/stdc++.h>usingnamespacestd;classBase{public: intfn1(){return0;} intfn2(){return0;}};classDerived:privateBase{publi......
  • 定义一个基类Object,有数据成员weight及相应的操作函数,由此派生出Box类,增加数据成员hei
    定义一个基类Object,有数据成员weight及相应的操作函数,由此派生出Box类,增加数据成员height和width及相应的操作函数,声明一个Box对象,观察构造函数与析构函数的调用顺序。#include<bits/stdc++.h>usingnamespacestd;classObject{protected: doubleweight;public: Object(......
  • 借用gcc内置函数帮助C来实现函数重载
    借用gcc内置函数__builtin_choose_expr和__builtin_types_compatible_p可以帮助c来实现函数重载。首先对这两个函数功能做下介绍__builtin_choose_expr(expr,expr1,expr2)与c语言:?运算符有些类似,如果expr表达式为真,那么返回expr1,否则返回expr2_builtin_types_compatible_p(ty......
  • JS函数的副作用你了解过吗?
    原文链接:   https://note.noxussj.top/?source=51cto什么是副作用?副作用会让一个函数变的不纯,纯函数是根据相同的输入返回相同的输出,如果函数依赖于外部的状态就无法保证输出相同,就会带来副作用。副作用来源函数依赖外部状态(变量),但是副作用不可能完全禁止,尽可能控制在它们可控范......