Python:类状态中的可变变量,幕后发生了什么?

标签 python class oop low-level

我目前正在使用 Python 进行 OOP 在线类(class),其中一项技能测试是编写密码生成器类。您将在下面找到推荐的答案。

import re
import random
from string import ascii_letters, punctuation
from copy import copy

class Password:
    
    SAMPLES = {
        "letters": list(ascii_letters),
        "numbers": list(range(10)),
        "punctuation": list(punctuation)
    }
    
    DEFAULT_SETTINGS = {
        "low": 8,
        "mid": 12,
        "high": 16
    }
    
    @classmethod
    def show_input_universe(cls):
        return cls.SAMPLES
    
    
    def _generate_password(self):
        
        population = self.SAMPLES["letters"]
        length = self.length or self.DEFAULT_SETTINGS.get(self.strength)
        
        if self.strength == "high":
            population += self.SAMPLES["numbers"] + self.SAMPLES["punctuation"]
        elif self.strength == "mid":
            population += self.SAMPLES["numbers"]
        else:
            pass
        
        # map(lambda x: str(x), random...)
        self.password = "".join(map(str, random.choices(population, k=int(length))))
    
    
    def __init__(self, strength="mid", length=None): #None so there's no need for a value
        self.strength = strength
        self.length = length
        
        self._generate_password()

当使用该代码创建该类的实例并生成具有高或中安全性的密码时,底层 SAMPLES["letter] 列表会被修改。这会导致低强度密码共享其他密码的所有属性优势。

在调用 show_input_universe 方法时我什至可以看到这种效果。其他列表已添加到原始列表中。

但是这是为什么呢?

据我了解,population = self.SAMPLES["letters"] 创建了population 变量,该变量存储指向 self.SAMPLES["letters"] 列表的指针。

但是串联到底是如何工作的:

if self.strength == "high":
    population += self.SAMPLES["numbers"] + self.SAMPLES["punctuation"]

解决方案如下:

from copy import copy

population = Copy(self.SAMPLES["letters"])

这会创建初始列表的副本,该副本仅在特定实例中进行修改。

最佳答案

人口类型为列表。 List 实现了数据模型钩子(Hook) __iadd__用于就地序列连接。此方法还返回现有实例:

>>> population = [0, 1]
>>> new = population.__iadd__([2, 3])
>>> new is population
True
>>> population
[0, 1, 2, 3]

因此,增强赋值语句 += 改变了原始列表,它是类命名空间中字典的值之一。它位于 Password.SAMPLES 中 - 在所有实例之间共享。 尽管population是方法内的局部变量,但仍然存在共享状态

请注意,如果 list 没有实现 __iadd__,那么您的代码将按您的预期工作,因为增强分配将回退到使用 __add__,连接并返回一个新的实例。将 population += other 替换为 population = Population + other 以查看类似内容。

关于Python:类状态中的可变变量,幕后发生了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75620193/

相关文章:

php - 静态/非静态方法问题

c# - 将输入添加到数组的构造函数

java - 单击按钮并更改另一个按钮的背景颜色

c++ - 多个类文件 C++

PHP/MySql - 查询具有嵌套对象的对象的最佳方式

php - 我应该创建一个对象还是使用数组?

此python3代码的Python2版本用于编码

python - xml.sax 解析器和行号等

python - Pandas:根据某些列的字符串值将数据框拆分为单独的数据框

python - 未将 checkbox-es 保存到 Django 管理数据库