Φαίνεται ότι υπάρχουν δύο διαφορετικοί τρόποι μετατροπής μιας συμβολοσειράς σε bytes, όπως φαίνεται στις απαντήσεις στο https://stackoverflow.com/questions/5471158/typeerror-str-does-not-support-the-buffer-interface.
Ποια από αυτές τις μεθόδους θα ήταν καλύτερη ή πιο πυθωνική; Ή είναι απλά θέμα προσωπικής προτίμησης;
b = bytes(mystring, 'utf-8')
b = mystring.encode('utf-8')
Αν κοιτάξετε τα έγγραφα για το bytes
, σας παραπέμπει στο bytearray
:
bytearray([source[, encoding[, errors]]])
Επιστρέφει έναν νέο πίνακα από bytes. Ο τύπος bytearray είναι μια μεταβλητή ακολουθία ακεραίων αριθμών στην περιοχή 0 <= x < 256. Διαθέτει τις περισσότερες από τις συνήθεις μεθόδους των μεταβλητών ακολουθιών, που περιγράφονται στην ενότητα Τύποι μεταβλητών ακολουθιών, καθώς και τις περισσότερες μεθόδους που διαθέτει ο τύπος bytes, βλέπε Μέθοδοι για Bytes και Byte Array.
Η προαιρετική παράμετρος source μπορεί να χρησιμοποιηθεί για την αρχικοποίηση του πίνακα με μερικούς διαφορετικούς τρόπους:
Αν πρόκειται για συμβολοσειρά, πρέπει επίσης να δώσετε τις παραμέτρους κωδικοποίησης (και προαιρετικά σφάλματα) η bytearray() στη συνέχεια μετατρέπει τη συμβολοσειρά σε bytes χρησιμοποιώντας την str.encode().__
Αν πρόκειται για ακέραιο αριθμό, ο πίνακας θα έχει αυτό το μέγεθος και θα αρχικοποιηθεί με null bytes.
Αν πρόκειται για αντικείμενο που συμμορφώνεται με τη διεπαφή buffer, θα χρησιμοποιηθεί ένας απομονωτής μόνο για ανάγνωση του αντικειμένου για την αρχικοποίηση του πίνακα bytes.
Αν πρόκειται για επαναληπτικό πίνακα, θα πρέπει να είναι ένας επαναληπτικός πίνακας ακεραίων αριθμών στην περιοχή 0 <= x < 256, οι οποίοι χρησιμοποιούνται ως τα αρχικά περιεχόμενα του πίνακα.
Χωρίς όρισμα, δημιουργείται ένας πίνακας μεγέθους 0.
Έτσι το bytes
μπορεί να κάνει πολύ περισσότερα από την απλή κωδικοποίηση μιας συμβολοσειράς. Είναι'Πυθικό ότι θα σας επέτρεπε να καλέσετε τον κατασκευαστή με οποιονδήποτε τύπο αρχικής παραμέτρου που έχει νόημα.
Για την κωδικοποίηση μιας συμβολοσειράς, νομίζω ότι το some_string.encode(encoding)
είναι πιο πυθωνικό από τη χρήση του κατασκευαστή, επειδή είναι το πιο αυτο-τεκμηριωμένο -- το "take this string and encode it with this encoding" είναι πιο σαφές από το bytes(some_string, encoding)
-- δεν υπάρχει ρητό ρήμα όταν χρησιμοποιείτε τον κατασκευαστή.
Επεξεργασία: Έλεγξα την πηγή της Python. Αν περάσετε ένα unicode string στο bytes
χρησιμοποιώντας την CPython, αυτό καλεί το PyUnicode_AsEncodedString, το οποίο είναι η υλοποίηση του encode
- έτσι απλά παραλείπετε ένα επίπεδο έμμεσης κατεύθυνσης αν καλέσετε το encode
μόνοι σας.
Επίσης, δείτε το σχόλιο του Serdalis' -- το unicode_string.encode(encoding)
είναι επίσης πιο Pythonic επειδή το αντίστροφό του είναι το byte_string.decode(encoding)
και η συμμετρία είναι ωραία.
Είναι ευκολότερο από ό, τι νομίζεται:
my_str = "hello world"
my_str_as_bytes = str.encode(my_str)
type(my_str_as_bytes) # ensure it is byte representation
my_decoded_str = my_str_as_bytes.decode()
type(my_decoded_str) # ensure it is string representation
Ο απολύτως καλύτερος τρόπος δεν είναι κανένας από τους 2, αλλά ο 3ος. Η πρώτη παράμετρος στην encode
προεπιλέγεται σε 'utf-8'
από την Python 3.0 και μετά. Συνεπώς, ο καλύτερος τρόπος είναι
b = mystring.encode()
Αυτό θα είναι επίσης πιο γρήγορο, επειδή το προεπιλεγμένο όρισμα δεν έχει ως αποτέλεσμα το αλφαριθμητικό "utf-8"
στον κώδικα C, αλλά NULL
, το οποίο είναι πολύ πιο γρήγορο στον έλεγχο!
Ακολουθούν μερικοί χρόνοι:
In [1]: %timeit -r 10 'abc'.encode('utf-8')
The slowest run took 38.07 times longer than the fastest.
This could mean that an intermediate result is being cached.
10000000 loops, best of 10: 183 ns per loop
In [2]: %timeit -r 10 'abc'.encode()
The slowest run took 27.34 times longer than the fastest.
This could mean that an intermediate result is being cached.
10000000 loops, best of 10: 137 ns per loop
Παρά την προειδοποίηση οι χρόνοι ήταν πολύ σταθεροί μετά από επανειλημμένες εκτελέσεις - η απόκλιση ήταν μόλις ~2%.
Η χρήση της encode()
χωρίς όρισμα δεν είναι συμβατή με την Python 2, καθώς στην Python 2 η προεπιλεγμένη κωδικοποίηση χαρακτήρων είναι ASCII.
>>> 'äöä'.encode()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)