class Filename(bytes): def __new__(cls, filename, charset): obj = bytes.__new__(cls, filename) obj.characters = str(filename, charset, "replace") obj.charset = charset return obj def __str__(self): # str(Filename(filename, charset)) -> str(filename, charset, "replace") return self.characters def __add__(self, filename): # Filename(...) + 'text' newname = bytes.__add__(self, filename.encode(self.charset)) return Filename(newname, self.charset) def __radd__(self, filename): # 'text' + Filename(...) newname = bytes.__add__(filename.encode(self.charset), self) return Filename(newname, self.charset) def __contains__(self, pattern): # 'pattern' in Filename(...) pattern = pattern.encode(self.charset) return bytes.__contains__(self, pattern) def startswith(self, pattern): # Filename(...).startswith('pattern') pattern = pattern.encode(self.charset) return bytes.startswith(self, pattern) def endswith(self, pattern): # Filename(...).endswith('pattern') pattern = pattern.encode(self.charset) return bytes.endswith(self, pattern) def index(self, pattern): # Filename(...).index('pattern') # Note: don't support start and end arguments pattern = pattern.encode(self.charset) return bytes.index(self, pattern) def __repr__(self): return "".format(bytes.__repr__(self), self.charset) def test_listdir(path): from os import listdir from sys import getfilesystemencoding charset = getfilesystemencoding() for name in listdir(path): if isinstance(name, bytes): name = Filename(name, charset) yield name if __name__ == "__main__": for name in test_listdir("/tmp/x"): print ("str={0}, repr={0!r}".format(name))