Pythons str.join()的内部是什么?(隐藏输出密码)

Rob*_*och 11 python

我偶然发现了一种有趣的(?)方式来隐藏密码(和其他个人数据)从屏幕到日志文件的一般输出.

在他的书" 如何在Python中犯错"中, Mike Pirnat建议为敏感字符串实现一个类,并使其__str__- 和 - __repr__方法重载.

我试验过这个并得到了这个:

class secret(str):

    def __init__(self, s):
        self.string = s

    def __repr__(self):
        return "'" + "R"*len(self.string) + "'"

    def __str__(self):
        return "S" * len(self.string)

    def __add__(self, other):
        return str.__add__(self.__str__(), other)

    def __radd__(self, other):
        return str.__add__(other, self.__str__())

    def __getslice__(self, i, j):
        return ("X"*len(self.string))[i:j]
Run Code Online (Sandbox Code Playgroud)

(我知道使用len提供有关要隐藏的内容的信息.它仅用于测试.)

它在这种情况下工作正常:

pwd = secret("nothidden")

print("The passwort is " + pwd)                  # The passwort is SSSSSSSSS
print(pwd + " is the passwort.")                 # SSSSSSSSS is the password.

print("The passwort is {}.".format(pwd))         # The password is SSSSSSSSS.
print(["The", "passwort", "is", pwd])            # ['The', 'password', 'is', 'RRRRRRRRR']
print(pwd[:])                                    # XXXXXXXXX
Run Code Online (Sandbox Code Playgroud)

但是这不起作用:

print(" ".join(["The", "password", "is", pwd]))  # The password is nothidden
Run Code Online (Sandbox Code Playgroud)

那么,str.join()如何在内部工作?我需要重载哪种方法来掩盖字符串?

Bak*_*riu 5

问题在于你是继承的str,这可能是实现的__new__,这意味着即使你避免在你的类中调用父构造函数,底层的C对象仍然用它初始化.

现在join可能是检查,如果它有一个str子类,并在C中实现,但是直接访问底层的C结构,或使用一个其它str-相关函数绕过__str____repr__(想一想:如果该值是一个字符串或字符串的子类,为什么代码会调用__str____repr__获取它的值?它只是以某种方式访问​​底层字符数组!)

为了解决这个问题:那不是继承str!不幸的是,这意味着在某些情况下你将无法像字符串一样使用该对象,但这几乎是不可避免的.


可工作的替代方案是实现__new__和饲料一个不同的值str__new__方法:

class secret(str):
    def __new__(cls, initializer):
        return super(secret, cls).__new__(cls, 'X'*len(initializer))
    def __init__(self, initializer):
        self.text = initializer
    def __repr__(self):
        return "'{}'".format("R"*len(self))
    def __str__(self):
        return "S"*len(self)
    def __add__(self, other):
        return str(self) + other
    def __radd__(self, other):
        return other + str(self)
Run Code Online (Sandbox Code Playgroud)

结果如下:

In [19]: pwd = secret('nothidden')

In [20]: print("The passwort is " + pwd)                  # The passwort is SSSSSSSSS
    ...: print(pwd + " is the passwort.")                 # SSSSSSSSS is the password.
    ...: 
    ...: print("The passwort is {}.".format(pwd))         # The password is SSSSSSSSS.
    ...: print(["The", "passwort", "is", pwd])            # ['The', 'password', 'is', 'RRRRRRRRR']
    ...: print(pwd[:])
The passwort is SSSSSSSSS
SSSSSSSSS is the passwort.
The passwort is SSSSSSSSS.
['The', 'passwort', 'is', 'RRRRRRRRR']
XXXXXXXXX

In [21]: print(" ".join(["The", "password", "is", pwd]))
The password is XXXXXXXXX
Run Code Online (Sandbox Code Playgroud)

但是,我没有真正看到它是如何有用的.我的意思是:这个类的目的是避免编程错误,最终显示敏感信息?但是,触发异常会更好,以便您可以识别错误!为此,它可能最好在raise NotImplementedError内部__str__,__repr__而不是默默地提供一个无用的价值...确保你不泄漏秘密,但发现错误变得非常困难.