java 和 python中参数在函数体中的改变对参数本身的影响

最近几天在看python , 看到函数这一段的时候 , 突然发现一个问题 , 字符串在函数体中重新赋值 , 不会对函数体外 , 该字符串本身的值产生影响 .
例如 :

def changestr (str):
    str = "inside" 
    print("这是function中 , 值为:",str)
mystr = "outside"
changestr(mystr)
print("这是函数外边 , 值为:",mystr)

运行结果为 :

这是function中 , 值为: inside
这是函数外边 , 值为: outside

考虑到字符串不可变的特性 (python的六种标准类型 , 其中有三种是不可变的类型 , 即 : Number ,String , Tuple) , 我分别测试了Number和Tuple , 发现同以上结果是一样的 , 因为这三种类型只能通过重新赋值来改变对象的值 , 另外三种类型(List , Set , Dictionary) 是可以改变内部的元素 , 于是又测试了这三种seq类型 , 第一次测试如下 :

def change(mylist):
    mylist.append([1,2,3,4])
mylist = ["aa",21]
print(mylist)
change(mylist)
print(mylist)

结果如下:

['aa', 21]
['aa', 21, [1, 2, 3, 4]]

发现在函数体中的修改 , 对对象本身的值发生了改变 , 在函数之外 , 该列表的内容依然发生了改变 , 这是事先就能猜测到的结果 , 因为python中的参数 , 传入的是变量引用的副本 , 它与变量指向同一个值.
鉴于前三种类型的参数是直接重新赋值的 , 于是继续下一步测试 :

def change2(list):
    list = [1,2,3,4]
mylist = ["aa",21]
print(mylist)
change2(mylist)
print(mylist)

结果如下:

['aa', 21]
['aa', 21]

有些意外 , 出现了和三种不可变类型参数一样的情况 , 在函数体中的重新赋值 , 没有对外部变量的值产生影响 , 不过仔细一想 , 却又在情理之中 .
我对python还不够熟悉 , 但是从近两天的学习中发现 , 其存储模型与java相似 , 即变量中存储的是引用 , 是指向真正内容的内存地址(当然 ,java中的八大基本数据类型 , 变量名和值都是存储在堆栈中的 ) , 对变量重新赋值 , 相当于修改了变量副本存储的内存地址 , 而这时的变量已经和函数体外的变量不是同一个了, 在函数体之外的变量 , 依旧存储的是原本的内存地址 , 其值自然没有发生改变 .

简单来说 :
- 函数体传入的参数 , 为函数体外变量引用的副本 .
- 在函数体中改变变量指向的堆中的值 , 对函数外变量有效.
- 在函数体中改变变量的引用 , 对函数外变量无效

大致图如下 :(红色线代表重新赋值动作)
这里写图片描述

当然 , 测试时不能少的 , 我在java中也做了相应的测试 , 结果与猜想一致 , 测试代码如下:

import java.util.ArrayList;
import java.util.List;

/**
 * Created by dell on 2017/3/27.
 *
 * @author dell
 * @date 2017/03/27
 */
public class DemoScope {


    public static void main(String[] args) {
        {
            String str1 = "aaa";
            testStr(str1);
            System.out.println("方法外:"+str1);
        }
        {
            int a = 5;
            testNumber(a);
            System.out.println("方法外:"+a);
        }
        {
            List list = new ArrayList();
            list.add("a");
            list.add("b");
            testList(list);
            System.out.println("方法外:"+list.toString());
        }
        {
            char a = 'a';
            testChar(a);
            System.out.println("方法外:"+a);
        }
        {
            List list = new ArrayList();
            list.add("a");
            list.add("b");
            testList2(list);
            System.out.println("方法外:"+list.toString());
        }
        {
            boolean fl = true;
            testBoolean(fl);
            System.out.println("方法外:"+fl);
        }
        {
            Tree tree = new Tree(50 , "银杏");
            testObject(tree);
            System.out.println("方法外:"+tree.toString());
        }
        {
            Tree tree = new Tree(50 , "银杏");
            testObject2(tree);
            System.out.println("方法外:"+tree.toString());
        }

    }


    static class Tree{
        int height;
        String type;

        Tree(int height, String type){
            this.height = height;
            this.type = type;
        }

        @Override
        public String toString() {
            return "Tree{" +
                    "height=" + height +
                    ", type='" + type + '\'' +
                    '}';
        }
    }


    private static void testStr(String str){
        System.out.println("1.这是function中,str="+str);
        str = "新的值";
        System.out.println("2.这是function中,str="+str);
    }

    private static void testNumber(int num ){
        System.out.println("重新赋值前:"+num);
        num = 10;
        System.out.println("重新赋值后:"+num);
    }

    private static void testList(List list){
        System.out.println("重新赋值前:"+ list.toString());
        list.set(0, "A");
    }

    private static void testList2(List list){
        System.out.println("重新赋值前:"+ list.toString());
        list = new ArrayList();
        list.add("A");
        System.out.println("重新赋值后:"+list.toString());
    }


    private static void testChar(char a){
        System.out.println("重新赋值前:"+ a);
        a = 'A';
        System.out.println("重新赋值后:"+a);
    }


    private static void testBoolean(boolean flag){
        System.out.println("重新赋值前:"+ flag);
        flag = false;
        System.out.println("重新赋值后:"+flag);
    }

    private static void testObject(Tree obj){
        System.out.println("重新赋值前:"+obj.toString());
        obj.height = 100 ;
        System.out.println("重新赋值后:"+obj.toString());
    }

    private static void testObject2(Tree obj){
        System.out.println("重新赋值前:"+obj.toString());
        obj = new Tree(100 , "琵琶") ;
        System.out.println("重新赋值后:"+obj.toString());
    }
}
<think>我们正在处理一个关于在连接参数更新请求中设置或修改Identifier值的问题。根据用户提供的引用,特别是引用[4]引用[5],我们可以得知Identifier(或类似概念)在系统中的作用以及如何修改。引用[4]提到:>SigBmp是个关键信号量参数,当相应的位为1时,提供了一个信号量,用来触发车辆或设备执行后续相应的动作,这个参数包含在AUTH1Response中由设备返回给车辆。车辆可通过Exchange指令来修改这个参数。引用[5]提到:>parameters参数constUF_BREP_topology_t*body_toposInputTopologyentityforwhichtoreturnanidentifier.要为其返回标识符的拓扑实体。int*identifierOutputUniqueforallothertopologyidentifierswithinthesamebody.对于同一主体内的所有其他拓扑标识符是唯一的。此外,引用[3]中提到了使用隐藏域来传递标识符(如cust_id)的方法:>添加隐藏域根据这些信息,我们可以总结出以下几点:1.**Identifier的作用**:Identifier(标识符)用于唯一标识某个实体(如拓扑实体、客户ID等),在参数更新请求中,通常需要指定要更新的对象的标识符。2.**如何设置Identifier**:-在Web应用中,通常通过隐藏表单域(hiddeninputfield)来传递标识符,如引用[3]所示。这样在提交表单时,标识符会作为请求参数发送到服务器,但用户不可见。-在API或指令调用中,可能需要通过特定的参数(如Exchange指令)来修改标识符相关的参数,如引用[4]提到的SigBmp参数。3.**如何修改Identifier**:-修改操作通常需要先获取到要修改的对象的标识符,然后通过特定的指令或函数进行修改。例如,引用[4]提到车辆可以通过Exchange指令修改SigBmp参数。-在编程中,可能需要先通过标识符查询出该对象,然后修改其属性,最后更新整个对象(如引用[1]所述的方法),而不是直接更新标识符本身。因为标识符通常是唯一且不可变的,如果需要改变标识符,可能需要创建一个新对象并删除旧对象。具体到用户的问题“如何在连接参数更新请求中正确设置或修改Identifier值”,我们可以给出以下步骤:###设置Identifier值(在更新请求中指定要更新的对象)1.**从客户端传递标识符**:在请求中,需要包含要更新的对象的标识符。这可以通过以下方式实现:-在表单中使用隐藏域(例如HTML中的`<inputtype="hidden"name="id"value="123">`),如引用[3]所示。-在API请求的URL路径(如RESTfulAPI中的`/resource/{id}`)或请求体(JSON/XML中的id字段)中包含标识符。2.**服务器端处理**:-服务器接收到请求后,首先从请求参数中提取标识符(如`id`)。-然后根据该标识符从数据库或存储中查询出对应的对象。-将请求中的其他参数更新到查询出的对象上(注意:不要直接更新标识符字段,除非有特殊需求且确保唯一性)。-保存更新后的对象。###修改Identifier值(改变对象的标识符)注意:通常不建议修改标识符,因为标识符的唯一性是其核心特性。如果确实需要修改,可以按照以下步骤:1.**创建新对象**:使用新的标识符创建一个新对象,并将原对象的其他属性复制到新对象。2.**更新关联对象**:如果有其他对象引用了原标识符,需要将这些引用更新到新标识符。3.**删除原对象**:删除原标识符对应的对象。如果系统支持直接修改标识符(如通过特定的指令),则按照系统提供的接口进行修改。例如引用[4]中提到的Exchange指令,可能允许修改SigBmp参数(该参数可能包含标识符信息)。具体操作需要参考系统文档。###代码示例假设我们有一个Web应用,需要更新客户信息,其中客户标识符(cust_id)通过隐藏域传递:```html<formaction="/customer_update.action"method="post"><inputtype="hidden"name="cust_id"value="1001">客户姓名:<inputtype="text"name="cust_name"value="张三"><inputtype="submit"value="更新"></form>```在服务器端(以Java为例),处理更新请求:```javapublicvoidupdateCustomer(CustomerupdatedCustomer){//首先从updatedCustomer中获取idLongid=updatedCustomer.getCust_id();//根据id从数据库查询出原始客户对象Customeroriginal=customerRepository.findById(id);//将更新后的属性设置到原始对象(注意:不修改id)original.setCust_name(updatedCustomer.getCust_name());//保存原始对象customerRepository.save(original);}```###注意事项-**唯一性约束**:修改标识符时必须确保新标识符的唯一性,否则会导致数据不一致。-**关联对象更新**:修改标识符可能会影响其他关联对象,需要谨慎处理。-**事务处理**:在修改标识符或更新对象时,使用事务来保证数据一致性。###相关问题1.在Web应用中,如何安全地传递标识符以防止恶意修改?2.如果标识符需要全局唯一,有哪些生成方法?3.修改数据库主键(标识符)有哪些风险?</think>### 连接参数更新请求中 Identifier 值的设置与修改方法 在连接参数更新请求中,`Identifier` 值通常用于唯一标识目标对象(如设备、实体或资源)。正确设置或修改该值需遵循以下步骤: --- #### 一、核心设置原则 1. **唯一性要求** `Identifier` 必须在同一主体(如设备、数据库实体)内保持唯一性,用于精准定位更新对象[^5]。 2. **传递方式** - **隐藏域传递**(Web 应用场景) 通过隐藏表单字段传递标识符,确保请求中包含目标对象的原始 ID: ```html <form action="/update_action" method="post"> <input type="hidden" name="identifier" value="OBJ-12345"> <!-- 引用[3] --> <!-- 其他可修改参数 --> </form> ``` - **API/指令参数**(系统交互场景) 使用专用指令(如 `Exchange` 指令)修改标识符关联参数: ```bash exchange --identifier "DEV-2024" --param signal_bitmap=0x1A # 引用[4] ``` --- #### 二、修改流程与最佳实践 1. **安全更新流程** ```mermaid graph LR A[获取请求中的原始 Identifier] --> B[根据 Identifier 查询目标对象] B --> C[修改对象属性值] C --> D[更新对象至数据库] ``` - **关键操作**:始终通过原始 `Identifier` 查询对象,而非直接修改请求参数中的对象[^1]。 2. **避免直接修改 Identifier** - 若需变更标识符本身(如更换设备 ID),应创建新对象并迁移数据,而非直接修改原值[^5]。 - 示例代码(伪代码): ```python # 查询原始对象 original = db.query("SELECT * FROM devices WHERE id = :old_id", old_id=request.identifier) # 创建新对象并继承属性 new_device = Device(id="NEW-ID", attributes=original.attributes) db.save(new_device) # 删除或归档旧对象 db.delete(original) ``` --- #### 三、常见问题解决 1. **标识符冲突** - **场景**:新 `Identifier` 与现有值重复。 - **方案**:采用全局唯一算法(如 UUID)生成新标识符: ```java String newIdentifier = UUID.randomUUID().toString(); // 示例: "3fa85f64-5717-4562-b3fc-2c963f66afa6" ``` 2. **信号量参数关联修改** - 当 `Identifier` 关联信号量(如 `SigBmp`)时,需通过专用指令同步更新: ```c // 伪代码:通过 Exchange 指令更新信号量 send_command("EXCHANGE", identifier="DEV-001", sigbmp=0xFFFF); // 引用[4] ``` 3. **批量更新中的标识符处理** - 使用参数化构建工具(如 Jenkins)批量处理: ```bash # Jenkins 参数化构建示例(引用[2]) xcodebuild update_params \ -identifier $BUILD_IDENTIFIER \ -new_version $CUSTOM_VERSION ``` --- ### 相关问题 1. 如何确保分布式系统中 `Identifier` 的全局唯一性? 2. 修改 `Identifier` 时如何避免关联数据断裂? 3. 哪些场景下必须保留原始 `Identifier` 而非创建新值? [^1]: 更新操作需通过原始 ID 查询对象再修改属性 [^2]: 参数化构建支持动态传递标识符 [^3]: 隐藏域确保标识符随请求提交 [^4]: 专用指令修改标识符关联参数 [^5]: 标识符在同一主体内需保持唯一性
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值