2016-11-08 12 views
11

Tôi vừa vấp vào một cách thú vị (?) Để ẩn mật khẩu (và các dữ liệu cá nhân khác) từ đầu ra chung từ màn hình sang logfiles.Nội bộ của Pythons str.join() là gì? (Ẩn mật khẩu từ đầu ra)

Trong cuốn sách How to make mistakes in Python Mike Pirnat gợi ý triển khai lớp học cho các chuỗi nhạy cảm và quá tải __str__ - và __repr__ -methods của chúng tôi.

tôi đã thử nghiệm với điều đó và nhận điều này: (. Tôi biết rằng việc sử dụng len cung cấp thông tin về nội dung để ẩn Nó chỉ là để thử nghiệm.)

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] 

Nó hoạt động tốt trong trường hợp này:

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 

Tuy nhiên điều này không hoạt động:

print(" ".join(["The", "password", "is", pwd])) # The password is nothidden 

Vì vậy, str.join() hoạt động như thế nào? Phương pháp nào tôi sẽ phải quá tải để che khuất chuỗi?

Trả lời

5

Vấn đề là bạn đang kế thừa từ str, có khả năng triển khai __new__ có nghĩa là mặc dù bạn tránh gọi hàm khởi tạo gốc trong lớp của bạn, đối tượng C bên dưới vẫn được khởi tạo với nó.

Bây giờ join có lẽ là kiểm tra nếu nó có một lớp con str và đang được triển khai trong C, nó truy cập trực tiếp cơ bản cấu trúc C, hoặc sử dụng một str chức năng -related khác mà bỏ qua __str____repr__ (suy nghĩ về nó: nếu ? giá trị là một chuỗi hoặc một chuỗi phân lớp, tại sao đoạn code gọi __str__ hoặc __repr__ để có được giá trị của nó Nó chỉ truy cập vào mảng nhân vật tiềm ẩn một cách nào đó)

để khắc phục điều này: làm không kế thừa từ str! Thật không may điều này có nghĩa là bạn sẽ không thể sử dụng đối tượng đó giống hệt như một chuỗi trong một số trường hợp, nhưng điều đó là không thể tránh khỏi.


Một thay thế có thể làm việc là thực hiện __new__ và thức ăn một giá trị khác nhau để __new__ phương pháp str 's:

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) 

mà kết quả trong:

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 

Tuy nhiên tôi không thực sự thấy điều này hữu ích như thế nào. Ý tôi là: mục đích của lớp này là để tránh các lỗi lập trình mà kết thúc hiển thị thông tin nhạy cảm? Nhưng sau đó có một ngoại lệ được kích hoạt là tốt hơn để bạn có thể xác định các lỗi! Vì điều đó có lẽ là tốt nhất để raise NotImplementedError bên trong __str____repr__ thay vì âm thầm cung cấp một giá trị vô dụng ... chắc chắn bạn không bị rò rỉ bí mật nhưng việc tìm lỗi trở nên thực sự khó khăn.

+1

Loại tác phẩm này. 'print (" ".join ([" The "," password "," is ", pwd]))' sẽ tạo ra một traceback, nhưng gói 'pwd' trong' str() 'sẽ tạo ra kết quả mong muốn. Tất nhiên, điều đó cũng sẽ sửa chữa phiên bản gốc. Tôi đoán đây là một chút an toàn hơn, sản xuất một traceback thay vì in chuỗi ẩn. – TigerhawkT3

+0

@ TigerhawkT3 Tôi đã cung cấp triển khai hoạt động như bạn mong đợi và thêm ghi chú về lý do tại sao điều này không thực sự hữu ích ... nếu bạn không muốn hiển thị nội dung nào đó, tôi sẽ không * triển khai một số phương pháp hoặc tăng ngoại lệ khi chúng được gọi. – Bakuriu

+0

Nó không phải là nhiều về lập trình * lỗi * nhưng về tiện lợi khi, nói, đăng nhập một truy vấn REST hoặc tương tự, vì vậy bạn không phải che khuất nó cho mình mọi lúc. Và đối với phần quan trọng nhất đó là sự tò mò. Nhưng có lẽ bạn đang đúng, có những cách tốt hơn để tránh in dữ liệu hợp lý. –

Các vấn đề liên quan