Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Xem bây giờ hướng dẫn này có một khóa học video liên quan được tạo bởi nhóm Python thực sự. Xem nó cùng với hướng dẫn bằng văn bản để làm sâu sắc thêm sự hiểu biết của bạn: nhị phân, byte và người vận hành bitwise trong Python This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Binary, Bytes, and Bitwise Operators in Python

Show

Máy tính lưu trữ tất cả các loại thông tin như một luồng các chữ số nhị phân được gọi là bit. Cho dù bạn làm việc với văn bản, hình ảnh hoặc video, tất cả đều sôi sục với những cái và số không. Các nhà khai thác bitwise của Python cho phép bạn thao tác các bit dữ liệu riêng lẻ đó ở mức độ chi tiết nhất.bits. Whether you’re working with text, images, or videos, they all boil down to ones and zeros. Python’s bitwise operators let you manipulate those individual bits of data at the most granular level.

Bạn có thể sử dụng các toán tử bitwise để thực hiện các thuật toán như nén, mã hóa và phát hiện lỗi cũng như để kiểm soát các thiết bị vật lý trong dự án Raspberry PI của bạn hoặc ở nơi khác. Thông thường, Python phân lập bạn khỏi các bit bên dưới với sự trừu tượng cao cấp. Bạn có nhiều khả năng tìm thấy hương vị quá tải của các nhà khai thác bitwise trong thực tế. Nhưng khi bạn làm việc với họ ở dạng ban đầu của họ, bạn sẽ ngạc nhiên bởi những điều kỳ quặc của họ!

Trong hướng dẫn này, bạn sẽ học cách:

  • Sử dụng các toán tử bitwise python để thao tác các bit riêng lẻbitwise operators to manipulate individual bits
  • Đọc và viết dữ liệu nhị phân theo cách không chính thống nền tảngplatform-agnostic way
  • Sử dụng bitmasks để đóng gói thông tin trên một byte duy nhấtbitmasks to pack information on a single byte
  • Quá tải các toán tử Bitwise Python trong các loại dữ liệu tùy chỉnh Python bitwise operators in custom data types
  • Ẩn các thông điệp bí mật trong hình ảnh kỹ thuật sốsecret messages in digital images

Để có được mã nguồn đầy đủ của ví dụ Watermarking kỹ thuật số và để trích xuất một điều trị bí mật ẩn trong một hình ảnh, hãy nhấp vào liên kết bên dưới:

Tổng quan về các nhà khai thác bitwise Python

Python đi kèm với một vài loại toán tử khác nhau, chẳng hạn như các toán tử số học, logic và so sánh. Bạn có thể nghĩ chúng là các chức năng tận dụng tiền tố nhỏ gọn và cú pháp infix nhỏ gọn hơn.prefix and infix syntax.

Các toán tử bitwise trông gần như giống nhau trên các ngôn ngữ lập trình khác nhau:

Nhà điều hànhThí dụNghĩa
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
0
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
1
Bitwise và
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
2
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
3
Bitwise hoặc
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
4
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
5
BitWise XOR (độc quyền hoặc)
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
6
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
7
Bit whole không
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
8
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
9
Bitwise trái thay đổi
>>> (1 + 1) or "default"  # The left operand is truthy
2
>>> (1 - 1) or "default"  # The left operand is falsy
'default'
0
>>> (1 + 1) or "default"  # The left operand is truthy
2
>>> (1 - 1) or "default"  # The left operand is falsy
'default'
1
BitWise phải thay đổi

Như bạn có thể thấy, chúng được biểu thị bằng các biểu tượng trông lạ thay vì các từ. Điều này làm cho chúng nổi bật trong Python ít hơn một chút so với bạn có thể thấy. Bạn có thể sẽ có thể tìm ra ý nghĩa của chúng chỉ bằng cách nhìn vào chúng.

Hầu hết các toán tử bitwise là nhị phân, điều đó có nghĩa là họ mong đợi hai toán hạng sẽ hoạt động, thường được gọi là toán hạng bên trái và toán hạng bên phải. Bitwise không (

>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
6) là toán tử bitwise không duy nhất vì nó chỉ mong đợi một toán hạng.binary, which means that they expect two operands to work with, typically referred to as the left operand and the right operand. Bitwise NOT (
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
6) is the only unary bitwise operator since it expects just one operand.

Tất cả các toán tử bitwise nhị phân có một toán tử tổng hợp tương ứng thực hiện một nhiệm vụ tăng cường:compound operator that performs an augmented assignment:

Nhà điều hànhThí dụNghĩa
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
0
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
1
Bitwise và
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
2
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
3
Bitwise hoặc
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
4
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
5
BitWise XOR (độc quyền hoặc)
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
6
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
7
Bit whole không
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
8
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
9
Bitwise trái thay đổi

>>> (1 + 1) or "default"  # The left operand is truthy
2
>>> (1 - 1) or "default"  # The left operand is falsy
'default'
0

>>> (1 + 1) or "default"  # The left operand is truthy
2
>>> (1 - 1) or "default"  # The left operand is falsy
'default'
1logical operators and the bitwise shift operators.

BitWise phải thay đổi

Như bạn có thể thấy, chúng được biểu thị bằng các biểu tượng trông lạ thay vì các từ. Điều này làm cho chúng nổi bật trong Python ít hơn một chút so với bạn có thể thấy. Bạn có thể sẽ có thể tìm ra ý nghĩa của chúng chỉ bằng cách nhìn vào chúng.binary system, which is essential to understanding bitwise operators. If you’re already comfortable with it, then go ahead and jump to the Bitwise Logical Operators section below.

Hầu hết các toán tử bitwise là nhị phân, điều đó có nghĩa là họ mong đợi hai toán hạng sẽ hoạt động, thường được gọi là toán hạng bên trái và toán hạng bên phải. Bitwise không (>>> def call(x): ... print(f"call({x=})") ... return x ... >>> call(False) or call(True) # Both operands evaluated call(x=False) call(x=True) True >>> call(True) or call(False) # Only the left operand evaluated call(x=True) True 6) là toán tử bitwise không duy nhất vì nó chỉ mong đợi một toán hạng.

Tất cả các toán tử bitwise nhị phân có một toán tử tổng hợp tương ứng thực hiện một nhiệm vụ tăng cường:

Tương đương vớibase, which represents the number of digits available. People naturally favor the base-ten numeral system, also known as the decimal system, because it plays nicely with counting on fingers.

>>> (1 + 1) or "default"  # The left operand is truthy
2
>>> (1 - 1) or "default"  # The left operand is falsy
'default'
3base-two numeral system, more commonly known as the binary system. Such numbers are composed of only two digits, zero and one.

>>> (1 + 1) or "default"  # The left operand is truthy
2
>>> (1 - 1) or "default"  # The left operand is falsy
'default'
4

>>> (1 + 1) or "default"  # The left operand is truthy
2
>>> (1 - 1) or "default"  # The left operand is falsy
'default'
5

Tuy nhiên, quan trọng hơn, hệ thống nhị phân là hoàn hảo cho các thiết bị điện tử, dịch các chữ số thành các mức điện áp khác nhau. Bởi vì điện áp thích trôi lên và xuống do các loại tiếng ồn khác nhau, bạn muốn giữ đủ khoảng cách giữa các điện áp liên tiếp. Nếu không, tín hiệu có thể cuối cùng bị biến dạng.voltage levels. Because voltage likes to drift up and down due to various kinds of noise, you want to keep sufficient distance between consecutive voltages. Otherwise, the signal might end up distorted.

Bằng cách chỉ sử dụng hai trạng thái, bạn làm cho hệ thống đáng tin cậy hơn và chống lại tiếng ồn. Ngoài ra, bạn có thể tăng điện áp, nhưng điều đó cũng sẽ làm tăng mức tiêu thụ năng lượng, điều mà bạn chắc chắn muốn tránh.power consumption, which you definitely want to avoid.

Làm thế nào để nhị phân hoạt động?

Hãy tưởng tượng trong một khoảnh khắc mà bạn chỉ có hai ngón tay để đếm. Bạn có thể đếm số 0, một và hai. Nhưng khi bạn chạy ra khỏi ngón tay, bạn cần lưu ý bao nhiêu lần bạn đã tính vào hai và sau đó bắt đầu lại cho đến khi bạn đạt được hai lần nữa:

Số thập phânNgón tayTámBốn ngườiTwosNhững ngườiNhị phân
010 0 0 0 0 02
110 0 0 0 1 12
210 0 0 1 0 102
310 ✌+0 0 1 1 112
410 0 1 0 0 1002
510 ✌+0 1 0 1 1012
610 ✌+0 1 1 0 1102
710 ✌++0 1 1 1 1112
810 1 0 0 0 10002
910 ✌+1 0 0 1 10012
1010 ✌+1 0 1 0 10102
1110 ✌+++1 0 1 1 10112
1210 ✌+1 1 0 0 11002
1310 ✌+✌+1 1 0 1 11012

Mỗi khi bạn viết ra một cặp ngón tay khác, bạn cũng cần phải nhóm chúng theo sức mạnh của hai, đó là cơ sở của hệ thống. Ví dụ, để đếm đến mười ba, bạn sẽ phải sử dụng cả hai ngón tay của mình sáu lần và sau đó sử dụng một ngón tay nữa. Ngón tay của bạn có thể được sắp xếp là một tám, một bốn và một.

Các quyền hạn của hai vị trí chữ số trong một số nhị phân và cho bạn biết chính xác các bit nào sẽ bật. Chúng phát triển từ phải sang trái, bắt đầu với bit ít quan trọng nhất, xác định xem số lượng là chẵn hay lẻ.least-significant bit, which determines if the number is even or odd.

Ký hiệu vị trí giống như đồng hồ đo trong xe của bạn: một khi một chữ số ở một vị trí cụ thể đạt đến giá trị tối đa của nó, là một trong hệ thống nhị phân, nó sẽ chuyển sang 0 và một phần bên trái. Điều này có thể có hiệu ứng xếp tầng nếu đã có một số người ở bên trái của chữ số.

Cách máy tính sử dụng nhị phân

Bây giờ bạn đã biết các nguyên tắc cơ bản của hệ thống nhị phân và tại sao máy tính sử dụng nó, bạn đã sẵn sàng tìm hiểu cách chúng đại diện cho dữ liệu với nó.

Trước khi bất kỳ thông tin nào có thể được sao chép ở dạng kỹ thuật số, bạn phải chia nó thành các số và sau đó chuyển đổi chúng thành hệ thống nhị phân. Ví dụ, văn bản thuần túy có thể được coi là một chuỗi các ký tự. Bạn có thể gán một số tùy ý cho mỗi ký tự hoặc chọn một ký tự hiện có mã hóa như ASCII, ISO-8859-1 hoặc UTF-8.

Trong Python, các chuỗi được biểu diễn dưới dạng các mảng của các điểm mã Unicode. Để tiết lộ các giá trị thứ tự của chúng, hãy gọi

>>> len("€uro".encode("utf-8"))
6
08 trên mỗi ký tự:

>>>

>>> [ord(character) for character in "€uro"]
[8364, 117, 114, 111]

Các số kết quả xác định duy nhất các ký tự văn bản trong không gian Unicode, nhưng chúng được hiển thị ở dạng thập phân. Bạn muốn viết lại chúng bằng cách sử dụng các chữ số nhị phân:

Tính cáchĐiểm mã thập phânĐiểm mã nhị phân
836410 100000101011002
u11710 11101012
r11410 11100102
o11110 11011112

Lưu ý rằng độ dài bit, đó là số chữ số nhị phân, thay đổi rất nhiều trên các ký tự. Dấu hiệu đồng euro (

>>> len("€uro".encode("utf-8"))
6
09) yêu cầu mười bốn bit, trong khi phần còn lại của các nhân vật có thể thoải mái phù hợp với bảy bit.bit-length, which is the number of binary digits, varies greatly across the characters. The euro sign (
>>> len("€uro".encode("utf-8"))
6
09) requires fourteen bits, while the rest of the characters can comfortably fit on seven bits.

Độ dài bit biến là có vấn đề. Ví dụ, nếu bạn đặt các số nhị phân đó cạnh nhau trên đĩa quang, thì bạn sẽ kết thúc với một dòng bit dài mà không có ranh giới rõ ràng giữa các ký tự:

100000101011001110101111001011011112

Một cách để biết cách diễn giải thông tin này là chỉ định các mẫu bit có độ dài cố định cho tất cả các ký tự. Trong điện toán hiện đại, đơn vị thông tin nhỏ nhất, được gọi là octet hoặc byte, bao gồm tám bit có thể lưu trữ 256 giá trị riêng biệt.octet or a byte, comprises eight bits that can store 256 distinct values.

Bạn có thể đệm các điểm mã nhị phân của mình bằng các số 0 hàng đầu để thể hiện chúng theo các byte:

Tính cáchĐiểm mã thập phânĐiểm mã nhị phân
836410 u
u11710 r
r11410 o
o11110 Lưu ý rằng độ dài bit, đó là số chữ số nhị phân, thay đổi rất nhiều trên các ký tự. Dấu hiệu đồng euro (
>>> len("€uro".encode("utf-8"))
6
09) yêu cầu mười bốn bit, trong khi phần còn lại của các nhân vật có thể thoải mái phù hợp với bảy bit.

Độ dài bit biến là có vấn đề. Ví dụ, nếu bạn đặt các số nhị phân đó cạnh nhau trên đĩa quang, thì bạn sẽ kết thúc với một dòng bit dài mà không có ranh giới rõ ràng giữa các ký tự:

Một cách để biết cách diễn giải thông tin này là chỉ định các mẫu bit có độ dài cố định cho tất cả các ký tự. Trong điện toán hiện đại, đơn vị thông tin nhỏ nhất, được gọi là octet hoặc byte, bao gồm tám bit có thể lưu trữ 256 giá trị riêng biệt.

>>>

>>> len("€uro".encode("utf-8"))
6

Các số kết quả xác định duy nhất các ký tự văn bản trong không gian Unicode, nhưng chúng được hiển thị ở dạng thập phân. Bạn muốn viết lại chúng bằng cách sử dụng các chữ số nhị phân:

>>>

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1

Các loại thông tin khác có thể được số hóa tương tự như văn bản. Hình ảnh raster được làm bằng pixel, với mỗi pixel có các kênh đại diện cho cường độ màu dưới dạng số. Dạng sóng âm chứa các số tương ứng với áp suất không khí ở một khoảng thời gian lấy mẫu nhất định. Các mô hình ba chiều được xây dựng từ các hình dạng hình học được xác định bởi các đỉnh của chúng, v.v.

Vào cuối ngày, mọi thứ đều là một con số.

Các toán tử logic bitwise

Bạn có thể sử dụng các toán tử bitwise để thực hiện logic boolean trên các bit riêng lẻ. Điều đó tương tự như sử dụng các toán tử logic như

>>> len("€uro".encode("utf-8"))
6
13,
>>> len("€uro".encode("utf-8"))
6
14 và
>>> len("€uro".encode("utf-8"))
6
15, nhưng ở mức độ một chút. Sự tương đồng giữa các toán tử bitwise và logic vượt xa điều đó.

Nó có thể đánh giá các biểu thức Boolean với các toán tử bitwise thay vì các toán tử logic, nhưng việc sử dụng quá mức như vậy thường không được khuyến khích. Nếu bạn quan tâm đến các chi tiết, thì bạn có thể mở rộng hộp bên dưới để tìm hiểu thêm.

Cách thông thường để chỉ định các biểu thức boolean hợp chất trong Python là sử dụng các toán tử logic kết nối các vị từ liền kề, như thế này:

if age >= 18 and not is_self_excluded:
    print("You can gamble")

Ở đây, bạn kiểm tra xem người dùng có ít nhất mười tám tuổi không và nếu họ đã từ chối đánh bạc. Bạn có thể viết lại điều kiện đó bằng các toán tử bitwise:

if age >= 18 & ~is_self_excluded:
    print("You can gamble")

Mặc dù biểu thức này là chính xác về mặt cú pháp, có một vài vấn đề với nó. Đầu tiên, nó được cho là ít dễ đọc hơn. Thứ hai, nó không hoạt động như mong đợi cho tất cả các nhóm dữ liệu. Bạn có thể chứng minh rằng bằng cách chọn các giá trị toán hạng cụ thể:

>>>

>>> age = 18
>>> is_self_excluded = True
>>> age >= 18 & ~is_self_excluded  # Bitwise logical operators
True
>>> age >= 18 and not is_self_excluded  # Logical operators
False

Biểu thức được tạo ra từ các toán tử bitwise đánh giá thành

>>> len("€uro".encode("utf-8"))
6
16, trong khi cùng một biểu thức được xây dựng từ các toán tử logic đánh giá là
>>> len("€uro".encode("utf-8"))
6
17. Điều đó bởi vì các toán tử bitwise được ưu tiên hơn các toán tử so sánh, thay đổi cách thức toàn bộ biểu thức được giải thích:

>>>

>>> age >= (18 & ~is_self_excluded)
True

Nó như thể ai đó đặt dấu ngoặc đơn ngầm xung quanh các toán hạng sai. Để khắc phục điều này, bạn có thể đặt dấu ngoặc rõ ràng, sẽ thực thi đúng thứ tự đánh giá:

>>>

>>> (age >= 18) & ~is_self_excluded
0

Tuy nhiên, bạn không còn nhận được kết quả boolean. Các nhà khai thác Python bitwise được thiết kế chủ yếu để hoạt động với các số nguyên, vì vậy các toán hạng của họ tự động được đúc nếu cần. Điều này có thể không phải lúc nào cũng có thể, mặc dù.

Mặc dù bạn có thể sử dụng các số nguyên Truthy và Falsy trong bối cảnh Boolean, nhưng nó là một phản sản được biết đến có thể khiến bạn mất nhiều giờ để gỡ lỗi không cần thiết. Bạn tốt hơn khi theo dõi Zen of Python để tự cứu mình những rắc rối.truthy and falsy integers in a Boolean context, it’s a known antipattern that can cost you long hours of unnecessary debugging. You’re better off following the Zen of Python to save yourself the trouble.

Cuối cùng nhưng không kém phần quan trọng, bạn có thể cố tình muốn sử dụng các toán tử bitwise để vô hiệu hóa đánh giá ngắn mạch các biểu thức boolean. Biểu thức sử dụng các toán tử logic được đánh giá một cách lười biếng từ trái sang phải. Nói cách khác, việc đánh giá dừng ngay khi đã biết kết quả của toàn bộ biểu thức:short-circuit evaluation of Boolean expressions. Expressions using logical operators are evaluated lazily from left to right. In other words, the evaluation stops as soon as the result of the entire expression is known:

>>>

>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True

Trong ví dụ thứ hai, toán hạng bên phải không được gọi là vì giá trị của toàn bộ biểu thức đã được xác định bởi giá trị của toán hạng bên trái. Bất kể toán hạng phù hợp là gì, nó đã giành được ảnh hưởng đến kết quả, vì vậy, không có điểm nào trong việc gọi nó trừ khi bạn dựa vào tác dụng phụ.

Có những thành ngữ, chẳng hạn như rơi trở lại giá trị mặc định, tận dụng tính đặc thù này:

>>>

>>> (1 + 1) or "default"  # The left operand is truthy
2
>>> (1 - 1) or "default"  # The left operand is falsy
'default'

Một biểu thức boolean lấy giá trị của toán hạng được đánh giá cuối cùng. Toán tử trở thành sự thật hoặc giả mạo bên trong biểu thức nhưng vẫn giữ được loại và giá trị ban đầu của nó sau đó. Cụ thể, một số nguyên dương ở bên trái được truyền, trong khi số 0 bị loại bỏ.

Không giống như các đối tác logic của họ, các toán tử bitwise được đánh giá một cách háo hức:

>>>

>>> len("€uro".encode("utf-8"))
6
0

Mặc dù biết toán hạng bên trái là đủ để xác định giá trị của toàn bộ biểu thức, tất cả các toán hạng luôn được đánh giá vô điều kiện.

Trừ khi bạn có một lý do mạnh mẽ và biết những gì bạn đang làm, bạn chỉ nên sử dụng các toán tử bitwise để kiểm soát các bit. Nó quá dễ dàng để có được sai nếu không. Trong hầu hết các trường hợp, bạn sẽ muốn chuyển các số nguyên làm đối số cho các toán tử bitwise.

Bitwise và

BitWise và toán tử (

>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
0) thực hiện kết hợp logic trên các bit tương ứng của các toán hạng của nó. Đối với mỗi cặp bit chiếm cùng một vị trí trong hai số, nó chỉ trả về một chỉ khi cả hai bit được bật:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Mẫu bit thu được là một giao điểm của các đối số của toán tử. Nó có hai bit được bật ở các vị trí mà cả hai toán hạng là một. Ở tất cả các nơi khác, ít nhất một trong các đầu vào có bit bằng không.intersection of the operator’s arguments. It has two bits turned on in the positions where both operands are ones. In all other places, at least one of the inputs has a zero bit.

Về mặt âm thanh, điều này tương đương với một sản phẩm của hai giá trị bit. Bạn có thể tính toán bitwise và của các số A và B bằng cách nhân các bit của chúng ở mọi chỉ mục I:product of two bit values. You can calculate the bitwise AND of numbers a and b by multiplying their bits at every index i:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Ở đây, một ví dụ cụ thể:

Biểu hiệnGiá trị nhị phânGiá trị thập phân
>>> len("€uro".encode("utf-8"))
6
19
100111002 15610
>>> len("€uro".encode("utf-8"))
6
20
1101002 5210
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
1
101002 2010

Một nhân được nhân với một cho một, nhưng bất cứ thứ gì nhân với 0 sẽ luôn luôn dẫn đến số không. Ngoài ra, bạn có thể lấy tối thiểu hai bit trong mỗi cặp. Lưu ý rằng khi các toán hạng có độ dài bit không bằng nhau, phần ngắn hơn được tự động đệm với số không ở bên trái.

Bitwise hoặc

BitWise hoặc toán tử (

>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
2) thực hiện phân tách logic. Đối với mỗi cặp bit tương ứng, nó sẽ trả về một một nếu ít nhất một trong số chúng được bật:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Mẫu bit kết quả là một liên minh của các đối số của nhà điều hành. Nó có năm bit được bật trong đó một trong hai toán hạng có một. Chỉ có sự kết hợp của hai số 0 cho số 0 trong đầu ra cuối cùng.union of the operator’s arguments. It has five bits turned on where either of the operands has a one. Only a combination of two zeros gives a zero in the final output.

Số học đằng sau nó là sự kết hợp của một tổng và một sản phẩm của các giá trị bit. Để tính toán bitwise hoặc của các số A và B, bạn cần áp dụng công thức sau vào các bit của chúng ở mọi chỉ mục I:sum and a product of the bit values. To calculate the bitwise OR of numbers a and b, you need to apply the following formula to their bits at every index i:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Ở đây, một ví dụ hữu hình:

Biểu hiệnGiá trị nhị phânGiá trị thập phân
>>> len("€uro".encode("utf-8"))
6
19
100111002 15610
>>> len("€uro".encode("utf-8"))
6
20
1101002 5210
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
1
101111002 18810

Một nhân được nhân với một cho một, nhưng bất cứ thứ gì nhân với 0 sẽ luôn luôn dẫn đến số không. Ngoài ra, bạn có thể lấy tối thiểu hai bit trong mỗi cặp. Lưu ý rằng khi các toán hạng có độ dài bit không bằng nhau, phần ngắn hơn được tự động đệm với số không ở bên trái.

Bitwise hoặc

BitWise hoặc toán tử (

>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
2) thực hiện phân tách logic. Đối với mỗi cặp bit tương ứng, nó sẽ trả về một một nếu ít nhất một trong số chúng được bật:

>>> len("€uro".encode("utf-8"))
6
1

Mẫu bit kết quả là một liên minh của các đối số của nhà điều hành. Nó có năm bit được bật trong đó một trong hai toán hạng có một. Chỉ có sự kết hợp của hai số 0 cho số 0 trong đầu ra cuối cùng.

Số học đằng sau nó là sự kết hợp của một tổng và một sản phẩm của các giá trị bit. Để tính toán bitwise hoặc của các số A và B, bạn cần áp dụng công thức sau vào các bit của chúng ở mọi chỉ mục I:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Ở đây, một ví dụ hữu hình:symmetric difference of the operator’s arguments. There are three bits switched on in the result where both numbers have different bit values. Bits in the remaining positions cancel out because they’re the same.

>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
3sum modulo two:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Nó gần giống như một tổng của hai bit nhưng được kẹp ở cấp cao hơn để nó không bao giờ vượt quá giá trị của một bit. Bạn cũng có thể lấy tối đa của hai bit trong mỗi cặp để có được kết quả tương tự.dividend and the divisor—that performs a division and returns its remainder. In Python, there’s a built-in modulo operator denoted with the percent sign (

>>> len("€uro".encode("utf-8"))
6
27).

BitWise XOR

Biểu hiệnGiá trị nhị phânGiá trị thập phân
>>> len("€uro".encode("utf-8"))
6
19
100111002 15610
>>> len("€uro".encode("utf-8"))
6
20
1101002 5210
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
1
101010002 16810

Một nhân được nhân với một cho một, nhưng bất cứ thứ gì nhân với 0 sẽ luôn luôn dẫn đến số không. Ngoài ra, bạn có thể lấy tối thiểu hai bit trong mỗi cặp. Lưu ý rằng khi các toán hạng có độ dài bit không bằng nhau, phần ngắn hơn được tự động đệm với số không ở bên trái.

Bitwise hoặc

BitWise hoặc toán tử (

>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
2) thực hiện phân tách logic. Đối với mỗi cặp bit tương ứng, nó sẽ trả về một một nếu ít nhất một trong số chúng được bật:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Mẫu bit kết quả là một liên minh của các đối số của nhà điều hành. Nó có năm bit được bật trong đó một trong hai toán hạng có một. Chỉ có sự kết hợp của hai số 0 cho số 0 trong đầu ra cuối cùng.complement to one, which turns zeros into ones and ones into zeros. It can be expressed arithmetically as the subtraction of individual bit values from one:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Số học đằng sau nó là sự kết hợp của một tổng và một sản phẩm của các giá trị bit. Để tính toán bitwise hoặc của các số A và B, bạn cần áp dụng công thức sau vào các bit của chúng ở mọi chỉ mục I:

Biểu hiệnGiá trị nhị phânGiá trị thập phân
>>> len("€uro".encode("utf-8"))
6
19
100111002 15610
Ở đây, một ví dụ hữu hình:11000112 9910

>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
3unsigned integers.

Nó gần giống như một tổng của hai bit nhưng được kẹp ở cấp cao hơn để nó không bao giờ vượt quá giá trị của một bit. Bạn cũng có thể lấy tối đa của hai bit trong mỗi cặp để có được kết quả tương tự.

BitWise XOR

Không giống như bitwise và, hoặc, và không, toán tử XOR bitwise (

>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
4) không có một đối tác logic trong Python. Tuy nhiên, bạn có thể mô phỏng nó bằng cách xây dựng trên đầu các toán tử hiện có:

Các nhà khai thác thay đổi bitwise

Các toán tử thay đổi bitwise là một loại công cụ khác để thao tác bit. Họ cho phép bạn di chuyển các bit xung quanh, điều này sẽ có ích để tạo ra bitmasks sau này. Trong quá khứ, chúng thường được sử dụng để cải thiện tốc độ của các hoạt động toán học nhất định.

Dịch trái

Toán tử Bitwise Left Shift (

>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
8) di chuyển các bit của toán hạng đầu tiên sang trái bởi số lượng vị trí được chỉ định trong toán hạng thứ hai của nó. Nó cũng quan tâm đến việc chèn đủ các bit bằng không để lấp đầy khoảng trống phát sinh ở cạnh phải của mẫu bit mới:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Chuyển một bit duy nhất sang bên trái của một nơi tăng gấp đôi giá trị của nó. Ví dụ, thay vì hai, bit sẽ chỉ ra bốn sau khi thay đổi. Di chuyển nó hai nơi sang trái sẽ tăng gấp bốn lần giá trị kết quả. Khi bạn thêm tất cả các bit trong một số nhất định, bạn sẽ nhận thấy rằng nó cũng được nhân đôi với mỗi nơi được thay đổi:

Biểu hiệnGiá trị nhị phânGiá trị thập phân
>>> len("€uro".encode("utf-8"))
6
19
1001112 3910
>>> len("€uro".encode("utf-8"))
6
36
10011102 7810
>>> len("€uro".encode("utf-8"))
6
37
100111002 15610
>>> len("€uro".encode("utf-8"))
6
38
1001110002 31210

Nói chung, việc thay đổi các bit sang trái tương ứng với việc nhân số với công suất của hai, với số mũ bằng số lượng vị trí đã thay đổi:power of two, with an exponent equal to the number of places shifted:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Sự thay đổi bên trái từng là một kỹ thuật tối ưu hóa phổ biến vì dịch chuyển bit là một hướng dẫn duy nhất và rẻ hơn để tính toán so với số mũ hoặc sản phẩm. Tuy nhiên, ngày nay, các trình biên dịch và phiên dịch viên, bao gồm Python, hoàn toàn có khả năng tối ưu hóa mã của bạn đằng sau hậu trường.optimization technique because bit shifting is a single instruction and is cheaper to calculate than exponent or product. Today, however, compilers and interpreters, including Python’s, are quite capable of optimizing your code behind the scenes.

Trên giấy tờ, mẫu bit xuất phát từ một ca bên trái trở nên dài hơn nhiều nơi bạn thay đổi nó. Điều đó cũng đúng với Python nói chung vì cách nó xử lý các số nguyên. Tuy nhiên, trong hầu hết các trường hợp thực tế, bạn sẽ muốn hạn chế độ dài của một mẫu bit là bội số của tám, đó là chiều dài byte tiêu chuẩn.

Ví dụ: nếu bạn làm việc với một byte duy nhất, thì việc chuyển nó sang bên trái sẽ loại bỏ tất cả các bit vượt ra ngoài ranh giới bên trái của nó:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Nó giống như nhìn vào một luồng bit không giới hạn thông qua một cửa sổ có độ dài cố định. Có một vài thủ thuật cho phép bạn làm điều này trong Python. Ví dụ: bạn có thể áp dụng một bitmask với bitwise và toán tử:

>>>

>>> len("€uro".encode("utf-8"))
6
2

Chuyển 3910 bởi ba vị trí sang trái trả về một số cao hơn giá trị tối đa mà bạn có thể lưu trữ trên một byte duy nhất. Phải mất chín bit, trong khi một byte chỉ có tám bit. Để cắt thêm một chút ở bên trái, bạn có thể áp dụng một bitmask với giá trị thích hợp. Nếu bạn muốn giữ các bit nhiều hơn hoặc ít hơn, thì bạn sẽ cần sửa đổi giá trị mặt nạ cho phù hợp.

Đúng sự thay đổi

Toán tử dịch chuyển bên phải bitwise (

>>> (1 + 1) or "default"  # The left operand is truthy
2
>>> (1 - 1) or "default"  # The left operand is falsy
'default'
0) tương tự như bên trái, nhưng thay vì di chuyển các bit sang trái, nó đẩy chúng sang bên phải bởi số lượng vị trí được chỉ định. Các bit ngoài cùng bên phải luôn bị bỏ:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Mỗi khi bạn thay đổi một chút sang bên phải theo một vị trí, bạn giảm một nửa giá trị cơ bản của nó. Di chuyển cùng một bit bằng hai vị trí sang bên phải tạo ra một phần tư giá trị ban đầu, v.v. Khi bạn thêm tất cả các bit riêng lẻ, bạn sẽ thấy rằng cùng một quy tắc áp dụng cho số mà chúng đại diện:

Biểu hiệnGiá trị nhị phânGiá trị thập phân
>>> len("€uro".encode("utf-8"))
6
19
100111012 15710
>>> len("€uro".encode("utf-8"))
6
36
10011102 7810
>>> len("€uro".encode("utf-8"))
6
37
1001112 3910
>>> len("€uro".encode("utf-8"))
6
38
100112 1910

Nói chung, việc thay đổi các bit sang trái tương ứng với việc nhân số với công suất của hai, với số mũ bằng số lượng vị trí đã thay đổi:floor division by a power of two:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Sự thay đổi bên trái từng là một kỹ thuật tối ưu hóa phổ biến vì dịch chuyển bit là một hướng dẫn duy nhất và rẻ hơn để tính toán so với số mũ hoặc sản phẩm. Tuy nhiên, ngày nay, các trình biên dịch và phiên dịch viên, bao gồm Python, hoàn toàn có khả năng tối ưu hóa mã của bạn đằng sau hậu trường.

>>>

>>> len("€uro".encode("utf-8"))
6
3

Chuyển 3910 bởi ba vị trí sang trái trả về một số cao hơn giá trị tối đa mà bạn có thể lưu trữ trên một byte duy nhất. Phải mất chín bit, trong khi một byte chỉ có tám bit. Để cắt thêm một chút ở bên trái, bạn có thể áp dụng một bitmask với giá trị thích hợp. Nếu bạn muốn giữ các bit nhiều hơn hoặc ít hơn, thì bạn sẽ cần sửa đổi giá trị mặt nạ cho phù hợp.

Đúng sự thay đổi

Toán tử dịch chuyển bên phải bitwise (

>>> (1 + 1) or "default"  # The left operand is truthy
2
>>> (1 - 1) or "default"  # The left operand is falsy
'default'
0) tương tự như bên trái, nhưng thay vì di chuyển các bit sang trái, nó đẩy chúng sang bên phải bởi số lượng vị trí được chỉ định. Các bit ngoài cùng bên phải luôn bị bỏ:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Mỗi khi bạn thay đổi một chút sang bên phải theo một vị trí, bạn giảm một nửa giá trị cơ bản của nó. Di chuyển cùng một bit bằng hai vị trí sang bên phải tạo ra một phần tư giá trị ban đầu, v.v. Khi bạn thêm tất cả các bit riêng lẻ, bạn sẽ thấy rằng cùng một quy tắc áp dụng cho số mà chúng đại diện:

Việc xử lý các số âm trong Python hơi khác so với phương pháp truyền thống sang chuyển đổi bitwise. Trong phần tiếp theo, bạn sẽ kiểm tra điều này chi tiết hơn.

Số học so với sự thay đổi logic

Bạn có thể phân loại thêm các toán tử thay đổi bitwise là toán tử dịch chuyển số học và logic. Mặc dù Python chỉ cho phép bạn thực hiện sự thay đổi số học, nhưng nó có giá trị để biết cách các ngôn ngữ lập trình khác thực hiện các toán tử thay đổi bitwise để tránh sự nhầm lẫn và bất ngờ.arithmetic and logical shift operators. While Python only lets you do the arithmetic shift, it’s worthwhile to know how other programming languages implement the bitwise shift operators to avoid confusion and surprises.

Sự khác biệt này xuất phát từ cách họ xử lý bit dấu hiệu, thường nằm ở cạnh xa bên trái của chuỗi nhị phân có chữ ký. Trong thực tế, nó chỉ có liên quan đến toán tử thay đổi phù hợp, có thể khiến một số lật dấu hiệu của nó, dẫn đến tràn nguyên.sign bit, which ordinarily lies at the far left edge of a signed binary sequence. In practice, it’s relevant only to the right shift operator, which can cause a number to flip its sign, leading to integer overflow.

Thông thường, bit dấu hiệu bật biểu thị các số âm, giúp giữ các thuộc tính số học của chuỗi nhị phân:

Giá trị thập phânĐã ký giá trị nhị phânKý tên bitDấu hiệuNghĩa
-10010 100111002 1 -Số âm
2810 000111002 0 +Số dương hoặc không

Nhìn từ bên trái ở hai chuỗi nhị phân này, bạn có thể thấy rằng bit đầu tiên của chúng mang thông tin dấu hiệu, trong khi phần còn lại bao gồm các bit cường độ, giống nhau cho cả hai số.magnitude bits, which are the same for both numbers.

Một sự thay đổi bên phải logic, còn được gọi là một sự thay đổi bên phải không dấu hoặc sự thay đổi bên phải bằng không, di chuyển toàn bộ chuỗi nhị phân, bao gồm bit dấu hiệu và lấp đầy khoảng cách kết quả ở bên trái với số 0:unsigned right shift or a zero-fill right shift, moves the entire binary sequence, including the sign bit, and fills the resulting gap on the left with zeros:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Lưu ý cách thông tin về dấu hiệu của số bị mất. Bất kể dấu hiệu ban đầu là gì, nó sẽ luôn tạo ra một số nguyên không âm vì bit dấu hiệu được thay thế bằng không. Miễn là bạn không quan tâm đến các giá trị số, một sự thay đổi bên phải logic có thể hữu ích trong việc xử lý dữ liệu nhị phân cấp thấp.

Tuy nhiên, vì các số nhị phân đã ký thường được lưu trữ trên một chuỗi bit có độ dài cố định trong hầu hết các ngôn ngữ, nó có thể tạo ra kết quả bao quanh các giá trị cực đoan. Bạn có thể thấy điều này trong một công cụ Java Shell tương tác:

>>> len("€uro".encode("utf-8"))
6
4

Số kết quả thay đổi dấu hiệu của nó từ âm sang dương, nhưng nó cũng tràn, kết thúc rất gần với số nguyên tối đa của Java.

>>> len("€uro".encode("utf-8"))
6
5

Con số này có vẻ tùy ý từ cái nhìn đầu tiên, nhưng nó liên quan trực tiếp đến số lượng bit mà Java phân bổ cho loại dữ liệu

>>> len("€uro".encode("utf-8"))
6
44:

>>> len("€uro".encode("utf-8"))
6
6

Nó sử dụng 32 bit để lưu trữ số nguyên đã ký trong hai đại diện bổ sung. Khi bạn lấy bit dấu hiệu ra, bạn đã để lại 31 bit, có giá trị thập phân tối đa bằng 231 - 1 hoặc 214748364710.

Python, mặt khác, lưu trữ các số nguyên như thể có vô số bit theo ý của bạn. Do đó, một toán tử thay đổi bên phải logic sẽ được định nghĩa tốt trong Python thuần túy, do đó, nó bị thiếu trong ngôn ngữ. Bạn vẫn có thể mô phỏng nó, mặc dù.

Một cách để làm như vậy là tận dụng các loại dữ liệu không dấu có sẵn trong C được hiển thị thông qua mô-đun

>>> len("€uro".encode("utf-8"))
6
45 tích hợp:

>>>

>>> len("€uro".encode("utf-8"))
6
7

Họ cho phép bạn vượt qua một số âm nhưng don don đính kèm bất kỳ ý nghĩa đặc biệt nào vào bit dấu hiệu. Nó được đối xử như phần còn lại của các bit cường độ.

Mặc dù chỉ có một vài loại số nguyên không dấu được xác định trước trong C, khác nhau về độ dài bit, bạn có thể tạo một hàm tùy chỉnh trong Python để xử lý độ dài bit tùy ý:

>>>

>>> len("€uro".encode("utf-8"))
6
8

Họ cho phép bạn vượt qua một số âm nhưng don don đính kèm bất kỳ ý nghĩa đặc biệt nào vào bit dấu hiệu. Nó được đối xử như phần còn lại của các bit cường độ.

Mặc dù chỉ có một vài loại số nguyên không dấu được xác định trước trong C, khác nhau về độ dài bit, bạn có thể tạo một hàm tùy chỉnh trong Python để xử lý độ dài bit tùy ý:

Điều này chuyển đổi một chuỗi bit có chữ ký thành một chuỗi không dấu và sau đó thực hiện sự thay đổi bên phải số học thông thường.signed right shift operator, maintains the sign of a number by replicating its sign bit before moving bits to the right:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Tuy nhiên, vì các chuỗi bit trong Python aren đã cố định về chiều dài, chúng không thực sự có một chút dấu hiệu. Hơn nữa, họ không sử dụng đại diện bổ sung truyền thống của hai người như trong C hoặc Java. Để giảm thiểu điều đó, bạn có thể tận dụng hoạt động của modulo, điều này sẽ giữ các mẫu bit ban đầu cho các số nguyên dương trong khi quấn một cách thích hợp xung quanh các mẫu tiêu cực.

Một sự thay đổi bên phải số học (

>>> (1 + 1) or "default"  # The left operand is truthy
2
>>> (1 - 1) or "default"  # The left operand is falsy
'default'
0), đôi khi được gọi là toán tử chuyển đổi bên phải đã ký, duy trì dấu hiệu của một số bằng cách sao chép bit dấu của nó trước khi di chuyển các bit sang phải:

Đại diện số nhị phân

Bạn đã trải nghiệm tận mắt việc thiếu các loại dữ liệu không dấu trong Python khi sử dụng phủ định bitwise (

>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
6) và toán tử dịch chuyển đúng (
>>> (1 + 1) or "default"  # The left operand is truthy
2
>>> (1 - 1) or "default"  # The left operand is falsy
'default'
0). Bạn đã thấy những gợi ý về cách tiếp cận bất thường để lưu trữ các số nguyên trong Python, điều này làm cho việc xử lý các số âm trở nên khó khăn. Để sử dụng các toán tử bitwise một cách hiệu quả, bạn cần biết về các biểu diễn khác nhau của các số trong nhị phân.

Số nguyên không dấu

Trong các ngôn ngữ lập trình như C, bạn chọn sử dụng hương vị đã ký hay không dấu của một loại số nhất định. Các loại dữ liệu không dấu phù hợp hơn khi bạn biết chắc chắn rằng bạn sẽ không bao giờ cần phải đối phó với các số âm. Bằng cách phân bổ một bit bổ sung đó, nếu không sẽ đóng vai trò là một bit dấu hiệu, bạn thực tế đã tăng gấp đôi phạm vi của các giá trị có sẵn.

Nó cũng làm cho mọi thứ an toàn hơn một chút bằng cách tăng giới hạn tối đa trước khi tràn. Tuy nhiên, tràn ra chỉ xảy ra với độ dài bit cố định, do đó, chúng không liên quan đến Python, mà không có những hạn chế như vậy.

Cách nhanh nhất để có được hương vị của các loại số không dấu trong Python là sử dụng mô -đun

>>> len("€uro".encode("utf-8"))
6
45 đã đề cập trước đó:

>>>

>>> len("€uro".encode("utf-8"))
6
9

Vì không có dấu hiệu nào trong các số nguyên như vậy, tất cả các bit của chúng đại diện cho độ lớn của một số. Vượt qua một số âm buộc Python diễn giải lại mẫu bit như thể nó chỉ có các bit cường độ.

Đã ký số nguyên

Dấu hiệu của một số chỉ có hai trạng thái. Nếu bạn bỏ qua số 0 trong một khoảnh khắc, thì nó có thể là tích cực hoặc tiêu cực, dịch độc đáo cho hệ thống nhị phân. Tuy nhiên, có một vài cách khác để thể hiện số nguyên đã ký trong nhị phân, mỗi số có ưu và nhược điểm riêng.

Có lẽ người đơn giản nhất là độ chính đáng, được xây dựng tự nhiên trên đỉnh của các số nguyên không dấu. Khi một chuỗi nhị phân được hiểu là độ chính đáng, bit quan trọng nhất đóng vai trò của một bit dấu hiệu, trong khi phần còn lại của các bit hoạt động giống như bình thường:sign-magnitude, which builds naturally on top of unsigned integers. When a binary sequence is interpreted as sign-magnitude, the most significant bit plays the role of a sign bit, while the rest of the bits work the same as usual:

Trình tự nhị phânGiá trị hiệu suất ký hiệuGiá trị không dấu
001010102 4210 4210
101010102 -4210 17010

Số 0 trên bit ngoài cùng bên trái biểu thị số dương (

>>> len("€uro".encode("utf-8"))
6
50) và một biểu thị số âm (
>>> len("€uro".encode("utf-8"))
6
51). Lưu ý rằng một bit dấu hiệu không đóng góp vào số giá trị tuyệt đối của con số trong biểu diễn cường độ ký hiệu. Nó chỉ ở đó để cho phép bạn lật dấu hiệu của các bit còn lại.

Tại sao bit ngoài cùng bên trái?

Nó giữ cho chỉ số bit nguyên vẹn, đến lượt nó, giúp duy trì khả năng tương thích ngược của các trọng lượng bit được sử dụng để tính giá trị thập phân của chuỗi nhị phân. Tuy nhiên, không phải tất cả mọi thứ về cường độ ký hiệu là rất tuyệt vời.bit indexing intact, which, in turn, helps maintain backward compatibility of the bit weights used to calculate the decimal value of a binary sequence. However, not everything about sign-magnitude is so great.

Phạm vi của các giá trị mà bạn có thể lưu trữ trong một mẫu bit có độ bền là đối xứng. Nhưng điều đó cũng có nghĩa là bạn kết thúc với hai cách để truyền đạt số không:symmetrical. But it also means that you end up with two ways to convey zero:

Trình tự nhị phânGiá trị hiệu suất ký hiệuGiá trị không dấu
000000002 +010 010
100000002 -010 12810

Số 0 trên bit ngoài cùng bên trái biểu thị số dương (

>>> len("€uro".encode("utf-8"))
6
50) và một biểu thị số âm (
>>> len("€uro".encode("utf-8"))
6
51). Lưu ý rằng một bit dấu hiệu không đóng góp vào số giá trị tuyệt đối của con số trong biểu diễn cường độ ký hiệu. Nó chỉ ở đó để cho phép bạn lật dấu hiệu của các bit còn lại.ambiguous zero isn’t ideal in most cases, it’s not the worst part of the story. The biggest downside of this method is cumbersome binary arithmetic.

Tại sao bit ngoài cùng bên trái?binary arithmetic to numbers stored in sign-magnitude, it may not give you the expected results. For example, adding two numbers with the same magnitude but opposite signs won’t make them cancel out:

Nó giữ cho chỉ số bit nguyên vẹn, đến lượt nó, giúp duy trì khả năng tương thích ngược của các trọng lượng bit được sử dụng để tính giá trị thập phân của chuỗi nhị phân. Tuy nhiên, không phải tất cả mọi thứ về cường độ ký hiệu là rất tuyệt vời.Trình tự nhị phânGiá trị hiệu suất ký hiệu
Giá trị không dấu001010102 4210
Số 0 trên bit ngoài cùng bên trái biểu thị số dương (
>>> len("€uro".encode("utf-8"))
6
50) và một biểu thị số âm (
>>> len("€uro".encode("utf-8"))
6
51). Lưu ý rằng một bit dấu hiệu không đóng góp vào số giá trị tuyệt đối của con số trong biểu diễn cường độ ký hiệu. Nó chỉ ở đó để cho phép bạn lật dấu hiệu của các bit còn lại.
101010102 -4210
Tại sao bit ngoài cùng bên trái?110101002 -8410

Nó giữ cho chỉ số bit nguyên vẹn, đến lượt nó, giúp duy trì khả năng tương thích ngược của các trọng lượng bit được sử dụng để tính giá trị thập phân của chuỗi nhị phân. Tuy nhiên, không phải tất cả mọi thứ về cường độ ký hiệu là rất tuyệt vời.

Phạm vi của các giá trị mà bạn có thể lưu trữ trong một mẫu bit có độ bền là đối xứng. Nhưng điều đó cũng có nghĩa là bạn kết thúc với hai cách để truyền đạt số không:one’s complement representation. The idea was to change how decimal numbers are mapped to particular binary sequences so that they can be added up correctly. For a deeper dive into one’s complement, you can expand the section below.

Về mặt kỹ thuật, Zero không có dấu hiệu, nhưng ở đó, không có cách nào để không bao gồm một người có hiệu suất. Mặc dù có một số 0 mơ hồ là lý tưởng trong hầu hết các trường hợp, nhưng nó không phải là phần tồi tệ nhất của câu chuyện. Nhược điểm lớn nhất của phương pháp này là số học nhị phân cồng kềnh.

Khi bạn áp dụng số học nhị phân tiêu chuẩn cho các số được lưu trữ trong độ chính xác, nó có thể không cho bạn kết quả mong đợi. Ví dụ, việc thêm hai số có cùng độ lớn nhưng các dấu hiệu ngược lại đã giành được chúng làm cho chúng bị hủy bỏ:Biểu hiện
>>> len("€uro".encode("utf-8"))
6
19
000000002 111111112
>>> len("€uro".encode("utf-8"))
6
20
000000012 111111102
>>> len("€uro".encode("utf-8"))
6
54
000000102 111111012 Tổng số 42 và -42 không tạo ra bằng không. Ngoài ra, bit chuyển giao đôi khi có thể truyền từ độ lớn sang bit dấu hiệu, đảo ngược dấu hiệu và mang lại kết quả bất ngờ.
Để giải quyết những vấn đề này, một số máy tính sớm đã sử dụng một đại diện bổ sung của một người khác. Ý tưởng là thay đổi cách các số thập phân được ánh xạ tới các chuỗi nhị phân cụ thể để chúng có thể được thêm vào chính xác. Để tìm hiểu sâu hơn vào một bổ sung, bạn có thể mở rộng phần bên dưới.Để giải quyết những vấn đề này, một số máy tính sớm đã sử dụng một đại diện bổ sung của một người khác. Ý tưởng là thay đổi cách các số thập phân được ánh xạ tới các chuỗi nhị phân cụ thể để chúng có thể được thêm vào chính xác. Để tìm hiểu sâu hơn vào một bổ sung, bạn có thể mở rộng phần bên dưới.Để giải quyết những vấn đề này, một số máy tính sớm đã sử dụng một đại diện bổ sung của một người khác. Ý tưởng là thay đổi cách các số thập phân được ánh xạ tới các chuỗi nhị phân cụ thể để chúng có thể được thêm vào chính xác. Để tìm hiểu sâu hơn vào một bổ sung, bạn có thể mở rộng phần bên dưới.
011111112 100000002 Trong một bổ sung của một người khác, các số dương giống như độ chính xác của dấu hiệu, nhưng các số âm thu được bằng cách lật các bit số dương bằng cách sử dụng một chút không:

Trình tự tích cực

Một bổ sungSign-MagnitudeGiá trị thập phân
111111112 100000002 -010
111111102 100000012 -110
111111012 100000102 -210
100000102 111111012 -12510
100000012 111111102 -12610
100000002 111111112 -12710

Nhờ đó, bây giờ bạn có thể thêm hai số đáng tin cậy hơn vì bit dấu hiệu không cần điều trị đặc biệt. Nếu một người chuyển giao bắt nguồn từ bit dấu hiệu, nó sẽ được đưa trở lại ở cạnh phải của chuỗi nhị phân thay vì chỉ bị bỏ. Điều này đảm bảo kết quả chính xác.

Tuy nhiên, các máy tính hiện đại don don sử dụng một bổ sung của một người khác để đại diện cho các số nguyên vì có một cách thậm chí còn tốt hơn được gọi là bổ sung hai. Bằng cách áp dụng một sửa đổi nhỏ, bạn có thể loại bỏ Double Zero và đơn giản hóa số học nhị phân trong một lần. Để khám phá hai bổ sung chi tiết hơn, bạn có thể mở rộng phần bên dưới.two’s complement. By applying a small modification, you can eliminate double zero and simplify the binary arithmetic in one go. To explore two’s complement in more detail, you can expand the section below.

Khi tìm thấy các chuỗi bit của các giá trị âm trong hai bổ sung, thủ thuật là thêm một vào kết quả sau khi phủ định các bit:

Trình tự tích cựcMột bổ sung (không)Hai bổ sung (không phải+1)
000000002 111111112 000000002
000000012 111111102 111111112
000000102 111111012 111111102
011111112 100000002 100000012

Nhờ đó, bây giờ bạn có thể thêm hai số đáng tin cậy hơn vì bit dấu hiệu không cần điều trị đặc biệt. Nếu một người chuyển giao bắt nguồn từ bit dấu hiệu, nó sẽ được đưa trở lại ở cạnh phải của chuỗi nhị phân thay vì chỉ bị bỏ. Điều này đảm bảo kết quả chính xác.

Tuy nhiên, các máy tính hiện đại don don sử dụng một bổ sung của một người khác để đại diện cho các số nguyên vì có một cách thậm chí còn tốt hơn được gọi là bổ sung hai. Bằng cách áp dụng một sửa đổi nhỏ, bạn có thể loại bỏ Double Zero và đơn giản hóa số học nhị phân trong một lần. Để khám phá hai bổ sung chi tiết hơn, bạn có thể mở rộng phần bên dưới.asymmetrical, with a lower bound that’s a power of two and an odd upper bound. For example, an 8-bit signed integer will let you store numbers from -12810 to 12710 in two’s complement:

Khi tìm thấy các chuỗi bit của các giá trị âm trong hai bổ sung, thủ thuật là thêm một vào kết quả sau khi phủ định các bit:Một bổ sungGiá trị thập phân
100000002 -12810
100000012 100000002 -12710
100000102 100000012 -12610
111111102 111111012 -210
111111112 111111102 -110
111111112 -010
000000002 000000002 010
000000012 000000012 110
000000102 000000102 210
011111112 011111112 12710

Nhờ đó, bây giờ bạn có thể thêm hai số đáng tin cậy hơn vì bit dấu hiệu không cần điều trị đặc biệt. Nếu một người chuyển giao bắt nguồn từ bit dấu hiệu, nó sẽ được đưa trở lại ở cạnh phải của chuỗi nhị phân thay vì chỉ bị bỏ. Điều này đảm bảo kết quả chính xác.

Tuy nhiên, các máy tính hiện đại don don sử dụng một bổ sung của một người khác để đại diện cho các số nguyên vì có một cách thậm chí còn tốt hơn được gọi là bổ sung hai. Bằng cách áp dụng một sửa đổi nhỏ, bạn có thể loại bỏ Double Zero và đơn giản hóa số học nhị phân trong một lần. Để khám phá hai bổ sung chi tiết hơn, bạn có thể mở rộng phần bên dưới.Khi tìm thấy các chuỗi bit của các giá trị âm trong hai bổ sung, thủ thuật là thêm một vào kết quả sau khi phủ định các bit:Trình tự tích cựcMột bổ sung (không)Hai bổ sung (không phải+1)Điều này đẩy các chuỗi bit của các số âm xuống một nơi, loại bỏ số điểm không khét tiếng. Thay vào đó, một trừ đi một trừ khi một người sẽ tiếp quản mẫu bit của nó.Là một tác dụng phụ, phạm vi của các giá trị có sẵn trong hai phần bổ sung trở thành không đối xứng, với một giới hạn dưới, một sức mạnh của hai và một giới hạn trên lẻ. Ví dụ, số nguyên có chữ ký 8 bit sẽ cho phép bạn lưu trữ số từ -12810 đến 12710 trong hai bổ sung:Hai bổ sung
-27 26 25 24 23 22 21 20
-128 64 32 16 8 4 2 1

N/a

Một cách khác để đặt nó là bit quan trọng nhất mang cả dấu hiệu và một phần của cường độ số:

Bit 7

Bit 6

Bit 5sign, exponent, and mantissa bits. Without getting into too many technical details, you can think of it as the scientific notation for binary numbers. The decimal point “floats” around to accommodate a varying number of significant figures, except it’s a binary point.

Bit 4

  1. Bit 3 1 sign bit, 8 exponent bits, 23 mantissa bits
  2. Bit 2 1 sign bit, 11 exponent bits, 52 mantissa bits

Bit 1

Bit 0

Lưu ý dấu hiệu trừ bên cạnh trọng lượng bit ngoài cùng bên trái. Lấy giá trị thập phân từ một chuỗi nhị phân như thế chỉ là vấn đề thêm các cột thích hợp. Ví dụ: giá trị của 110101102 trong biểu diễn bổ sung hai bit 8 bit giống như tổng: -12810 + 6410 + 1610 + 410 + 210 = -4210.Với hai biểu diễn bổ sung hai, bạn không còn cần phải lo lắng về bit chuyển tiếp trừ khi bạn muốn sử dụng nó như một cơ chế phát hiện tràn, loại gọn gàng.Có một vài biến thể khác của các biểu diễn số có chữ ký, nhưng chúng không phổ biến.
02 100000002 .100100100001111110100002

Số điểm nổi

Tiêu chuẩn IEEE 754 xác định biểu diễn nhị phân cho các số thực bao gồm các dấu hiệu, số mũ và mantissa. Không cần đi vào quá nhiều chi tiết kỹ thuật, bạn có thể nghĩ nó là ký hiệu khoa học cho số nhị phân. Điểm thập phân nổi nổi nổi xung quanh để chứa một số lượng lớn các số liệu quan trọng khác nhau, ngoại trừ nó là một điểm nhị phân.

  • Hai loại dữ liệu phù hợp với tiêu chuẩn đó được hỗ trợ rộng rãi: 12810
  • Độ chính xác đơn: 1 bit dấu, 8 bit số mũ, 23 bit mantissa 2-1 + 2-4 + … + 2-19 = 29926110/52428810 ≈ 0.57079510

Độ chính xác gấp đôi: 1 bit dấu hiệu, 11 bit số mũ, 52 bit mantissa

Kiểu dữ liệu Python từ

>>> len("€uro".encode("utf-8"))
6
55 tương đương với loại chính xác kép. Lưu ý rằng một số ứng dụng yêu cầu nhiều hoặc ít bit hơn. Ví dụ, định dạng hình ảnh Openexr tận dụng một nửa độ chính xác để biểu diễn các pixel với phạm vi màu sắc cao ở kích thước tệp hợp lý.

Số PI (π) có biểu diễn nhị phân sau trong độ chính xác đơn khi được làm tròn đến năm vị trí thập phân:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Khi bạn thay thế các biến cho các giá trị thực trong ví dụ trên, bạn sẽ có thể giải mã mẫu bit của số điểm nổi được lưu trữ trong độ chính xác đơn:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Ở đó, được cho rằng PI đã được làm tròn đến năm vị trí thập phân. Bạn sẽ học cách hiển thị các số như vậy trong nhị phân sau này.

Số điểm cố định

Mặc dù các số điểm nổi là phù hợp tốt cho mục đích kỹ thuật, nhưng chúng thất bại trong các tính toán tiền tệ do độ chính xác hạn chế của chúng. Ví dụ, một số số có biểu diễn hữu hạn trong ký hiệu thập phân chỉ có một biểu diễn vô hạn trong nhị phân. Điều đó thường dẫn đến một lỗi làm tròn, có thể tích lũy theo thời gian:monetary calculations due to their limited precision. For example, some numbers with a finite representation in decimal notation have only an infinite representation in binary. That often results in a rounding error, which can accumulate over time:

>>>

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
0

Trong những trường hợp như vậy, bạn nên sử dụng mô-đun Python từ

>>> len("€uro".encode("utf-8"))
6
56, thực hiện số học điểm cố định và cho phép bạn chỉ định nơi đặt điểm thập phân trên một bit có độ dài nhất định. Ví dụ: bạn có thể cho biết bạn muốn bảo tồn bao nhiêu chữ số:fixed-point arithmetic and lets you specify where to put the decimal point on a given bit-length. For example, you can tell it how many digits you want to preserve:

>>>

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
1

Trong những trường hợp như vậy, bạn nên sử dụng mô-đun Python từ

>>> len("€uro".encode("utf-8"))
6
56, thực hiện số học điểm cố định và cho phép bạn chỉ định nơi đặt điểm thập phân trên một bit có độ dài nhất định. Ví dụ: bạn có thể cho biết bạn muốn bảo tồn bao nhiêu chữ số:

Tuy nhiên, nó bao gồm tất cả các chữ số, không chỉ các phân số.

Nếu bạn có thể hoặc không muốn sử dụng một loại dữ liệu điểm cố định, một cách đơn giản để lưu trữ các giá trị tiền tệ đáng tin cậy là mở rộng số lượng đến đơn vị nhỏ nhất, chẳng hạn như xu và đại diện cho chúng bằng số nguyên.

Số nguyên trong Python

Trong những ngày xưa của lập trình, bộ nhớ máy tính đã ở mức cao. Do đó, các ngôn ngữ sẽ cung cấp cho bạn quyền kiểm soát chi tiết về số lượng byte để phân bổ cho dữ liệu của bạn. Hãy cùng xem một vài loại số nguyên từ C làm ví dụ:Loại hìnhKích thướcGiá trị tối thiểu
Gia trị lơn nhât
>>> len("€uro".encode("utf-8"))
6
57
-128 127
1 byte
>>> len("€uro".encode("utf-8"))
6
58
-32,768 32,767
2 byte
>>> len("€uro".encode("utf-8"))
6
59
-2,147,483,648 2,147,483,647
4 byte
>>> len("€uro".encode("utf-8"))
6
60
-9,223,372,036,854,775,808 9,223,372,036,854,775,807

8 byte

Các giá trị này có thể thay đổi từ nền tảng này sang nền tảng khác. Tuy nhiên, sự phong phú của các loại số cho phép bạn sắp xếp dữ liệu trong bộ nhớ một cách gọn gàng. Hãy nhớ rằng những don don này thậm chí bao gồm các loại không dấu!

Ở phía bên kia của quang phổ là các ngôn ngữ như JavaScript, chỉ có một loại số để cai trị tất cả. Mặc dù điều này ít gây nhầm lẫn cho các lập trình viên bắt đầu, nhưng nó có giá tăng mức tiêu thụ bộ nhớ, giảm hiệu quả xử lý và giảm độ chính xác.

Khi nói về các nhà khai thác bitwise, nó rất cần thiết để hiểu cách Python xử lý các số nguyên. Rốt cuộc, bạn sẽ sử dụng các toán tử này chủ yếu để làm việc với các số nguyên. Có một vài đại diện cực kỳ khác nhau của các số nguyên trong Python phụ thuộc vào giá trị của chúng.

Số nguyên thực tập

>>>

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
2

Trong những trường hợp như vậy, bạn nên sử dụng mô-đun Python từ

>>> len("€uro".encode("utf-8"))
6
56, thực hiện số học điểm cố định và cho phép bạn chỉ định nơi đặt điểm thập phân trên một bit có độ dài nhất định. Ví dụ: bạn có thể cho biết bạn muốn bảo tồn bao nhiêu chữ số:

>>>

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
3

Trong những trường hợp như vậy, bạn nên sử dụng mô-đun Python từ

>>> len("€uro".encode("utf-8"))
6
56, thực hiện số học điểm cố định và cho phép bạn chỉ định nơi đặt điểm thập phân trên một bit có độ dài nhất định. Ví dụ: bạn có thể cho biết bạn muốn bảo tồn bao nhiêu chữ số:

>>>

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
4

Trong những trường hợp như vậy, bạn nên sử dụng mô-đun Python từ

>>> len("€uro".encode("utf-8"))
6
56, thực hiện số học điểm cố định và cho phép bạn chỉ định nơi đặt điểm thập phân trên một bit có độ dài nhất định. Ví dụ: bạn có thể cho biết bạn muốn bảo tồn bao nhiêu chữ số:

Tuy nhiên, nó bao gồm tất cả các chữ số, không chỉ các phân số.string interning mechanism in Python, which kicks in for short texts comprised of ASCII letters only. It helps speed up dictionary lookups by allowing their keys to be compared by memory addresses, or C pointers, instead of by the individual string characters.

Nếu bạn có thể hoặc không muốn sử dụng một loại dữ liệu điểm cố định, một cách đơn giản để lưu trữ các giá trị tiền tệ đáng tin cậy là mở rộng số lượng đến đơn vị nhỏ nhất, chẳng hạn như xu và đại diện cho chúng bằng số nguyên.

Số nguyên trong Python

Trong những ngày xưa của lập trình, bộ nhớ máy tính đã ở mức cao. Do đó, các ngôn ngữ sẽ cung cấp cho bạn quyền kiểm soát chi tiết về số lượng byte để phân bổ cho dữ liệu của bạn. Hãy cùng xem một vài loại số nguyên từ C làm ví dụ:

>>>

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
5

Trong những trường hợp như vậy, bạn nên sử dụng mô-đun Python từ

>>> len("€uro".encode("utf-8"))
6
56, thực hiện số học điểm cố định và cho phép bạn chỉ định nơi đặt điểm thập phân trên một bit có độ dài nhất định. Ví dụ: bạn có thể cho biết bạn muốn bảo tồn bao nhiêu chữ số:

Số nguyên chính xác tùy ý

Bạn có nhớ rằng bài hát K-Pop nổi tiếng là Gang Gangnam Style, đã trở thành một hit trên toàn thế giới vào năm 2012 không? Video YouTube là người đầu tiên phá vỡ một tỷ lượt xem. Ngay sau đó, rất nhiều người đã xem video mà nó làm cho View Counter tràn. YouTube không có lựa chọn nào khác ngoài việc nâng cấp bộ đếm của họ từ số nguyên có chữ ký 32 bit lên 64 bit.

Điều đó có thể mang lại nhiều khoảng trống cho một quầy xem, nhưng thậm chí còn có những con số lớn hơn mà không phải là không phổ biến trong cuộc sống thực, đáng chú ý là trong thế giới khoa học. Tuy nhiên, Python có thể đối phó với họ một cách dễ dàng:

>>>

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
6

Con số này có năm mươi hai chữ số thập phân. Sẽ mất ít nhất 170 bit để thể hiện nó trong nhị phân với cách tiếp cận truyền thống:

>>>

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
7

Con số này có năm mươi hai chữ số thập phân. Sẽ mất ít nhất 170 bit để thể hiện nó trong nhị phân với cách tiếp cận truyền thống:

Vì chúng rất tốt về các giới hạn mà bất kỳ loại C nào cũng phải cung cấp, các số thiên văn như vậy được chuyển đổi thành một hệ thống vị trí có độ bền của dấu hiệu, có cơ sở là 230. Có, bạn đọc chính xác. Trong khi bạn có mười ngón tay, Python có hơn một tỷ!

>>>

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
8

Con số này có năm mươi hai chữ số thập phân. Sẽ mất ít nhất 170 bit để thể hiện nó trong nhị phân với cách tiếp cận truyền thống:

Vì chúng rất tốt về các giới hạn mà bất kỳ loại C nào cũng phải cung cấp, các số thiên văn như vậy được chuyển đổi thành một hệ thống vị trí có độ bền của dấu hiệu, có cơ sở là 230. Có, bạn đọc chính xác. Trong khi bạn có mười ngón tay, Python có hơn một tỷ!

Một lần nữa, điều này có thể thay đổi tùy thuộc vào nền tảng mà bạn hiện đang sử dụng. Khi nghi ngờ, bạn có thể kiểm tra kỹ:

  1. Điều này sẽ cho bạn biết có bao nhiêu bit được sử dụng trên mỗi chữ số và kích thước trong byte là gì của cấu trúc C bên dưới. Để có được tên tương tự trong Python 2, bạn đã đề cập đến thuộc tính
    >>> len("€uro".encode("utf-8"))
    6
    
    66 thay thế.
  2. Trong khi sự chuyển đổi này giữa các số nguyên chính xác cố định và tùy ý được thực hiện liền mạch dưới mui xe trong Python 3, đã có lúc mọi thứ rõ ràng hơn. Để biết thêm thông tin, bạn có thể mở rộng hộp bên dưới.

Trong quá khứ, Python đã xác định rõ ràng hai loại số nguyên riêng biệt:

>>>

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
9

Con số này có năm mươi hai chữ số thập phân. Sẽ mất ít nhất 170 bit để thể hiện nó trong nhị phân với cách tiếp cận truyền thống:

>>>

if age >= 18 and not is_self_excluded:
    print("You can gamble")
0

Con số này có năm mươi hai chữ số thập phân. Sẽ mất ít nhất 170 bit để thể hiện nó trong nhị phân với cách tiếp cận truyền thống:

>>>

if age >= 18 and not is_self_excluded:
    print("You can gamble")
1

Con số này có năm mươi hai chữ số thập phân. Sẽ mất ít nhất 170 bit để thể hiện nó trong nhị phân với cách tiếp cận truyền thống:

Vì chúng rất tốt về các giới hạn mà bất kỳ loại C nào cũng phải cung cấp, các số thiên văn như vậy được chuyển đổi thành một hệ thống vị trí có độ bền của dấu hiệu, có cơ sở là 230. Có, bạn đọc chính xác. Trong khi bạn có mười ngón tay, Python có hơn một tỷ!

Một lần nữa, điều này có thể thay đổi tùy thuộc vào nền tảng mà bạn hiện đang sử dụng. Khi nghi ngờ, bạn có thể kiểm tra kỹ:

Điều này sẽ cho bạn biết có bao nhiêu bit được sử dụng trên mỗi chữ số và kích thước trong byte là gì của cấu trúc C bên dưới. Để có được tên tương tự trong Python 2, bạn đã đề cập đến thuộc tính

>>> len("€uro".encode("utf-8"))
6
66 thay thế.

Trong khi sự chuyển đổi này giữa các số nguyên chính xác cố định và tùy ý được thực hiện liền mạch dưới mui xe trong Python 3, đã có lúc mọi thứ rõ ràng hơn. Để biết thêm thông tin, bạn có thể mở rộng hộp bên dưới.

Trong quá khứ, Python đã xác định rõ ràng hai loại số nguyên riêng biệt:negative numbers are treated as two’s complement bit sequences when you apply the bitwise operators on them, even though the result will be presented to you in sign-magnitude form. There are ways to emulate the sign bit and some of the unsigned types in Python, though.

Số nguyên đơn giản

Số nguyên dàibit strings correspond to the expected numbers in Python. Here’s how.

Loại đầu tiên được mô hình hóa sau loại C >>> len("€uro".encode("utf-8")) 6 64, thường chiếm 32 hoặc 64 bit và cung cấp một phạm vi giá trị hạn chế:

Đối với số lượng lớn hơn, bạn được cho là sử dụng loại thứ hai mà không có giới hạn. Python sẽ tự động quảng bá các số nguyên đơn giản lên các số nguyên nếu cần:

>>>

if age >= 18 and not is_self_excluded:
    print("You can gamble")
2

Con số này có năm mươi hai chữ số thập phân. Sẽ mất ít nhất 170 bit để thể hiện nó trong nhị phân với cách tiếp cận truyền thống:

>>>

if age >= 18 and not is_self_excluded:
    print("You can gamble")
3

Vì chúng rất tốt về các giới hạn mà bất kỳ loại C nào cũng phải cung cấp, các số thiên văn như vậy được chuyển đổi thành một hệ thống vị trí có độ bền của dấu hiệu, có cơ sở là 230. Có, bạn đọc chính xác. Trong khi bạn có mười ngón tay, Python có hơn một tỷ!binary literal, which starts with the prefix

>>> len("€uro".encode("utf-8"))
6
71 and is followed by ones and zeros. It always shows the minimum number of digits without the leading zeros.

Một lần nữa, điều này có thể thay đổi tùy thuộc vào nền tảng mà bạn hiện đang sử dụng. Khi nghi ngờ, bạn có thể kiểm tra kỹ:

>>>

if age >= 18 and not is_self_excluded:
    print("You can gamble")
4

Điều này sẽ cho bạn biết có bao nhiêu bit được sử dụng trên mỗi chữ số và kích thước trong byte là gì của cấu trúc C bên dưới. Để có được tên tương tự trong Python 2, bạn đã đề cập đến thuộc tính

>>> len("€uro".encode("utf-8"))
6
66 thay thế.hexadecimal and octal ones, which you can obtain with the
>>> len("€uro".encode("utf-8"))
6
72 and
>>> len("€uro".encode("utf-8"))
6
73 functions, respectively:

>>>

if age >= 18 and not is_self_excluded:
    print("You can gamble")
5

Lưu ý cách hệ thống thập lục phân, cơ bản mười sáu, tận dụng các chữ cái

>>> len("€uro".encode("utf-8"))
6
74 đến
>>> len("€uro".encode("utf-8"))
6
75 để tăng cường tập hợp các chữ số có sẵn. Các chữ octal trong các ngôn ngữ lập trình khác thường có tiền tố bằng số 0, có thể gây nhầm lẫn. Python một cách rõ ràng cấm những người biết chữ như vậy để tránh mắc lỗi:

>>>

if age >= 18 and not is_self_excluded:
    print("You can gamble")
6

Bạn có thể thể hiện cùng một giá trị theo những cách khác nhau bằng cách sử dụng bất kỳ chữ số nguyên đề cập nào:

>>>

if age >= 18 and not is_self_excluded:
    print("You can gamble")
7

Chọn một trong đó có ý nghĩa nhất trong bối cảnh. Ví dụ, nó theo thông lệ để thể hiện bitmasks với ký hiệu thập lục phân. Mặt khác, nghĩa đen của bát phân hiếm khi được nhìn thấy trong những ngày này.

Tất cả các chữ số trong Python đều không nhạy cảm với trường hợp, vì vậy bạn có thể tiền tố chúng bằng chữ cái chữ thường hoặc chữ hoa:

>>>

if age >= 18 and not is_self_excluded:
    print("You can gamble")
8

Điều này cũng áp dụng cho các chữ số dấu phẩy động sử dụng ký hiệu khoa học cũng như các chữ số phức tạp.

Chuyển đổi nhị phân thành >>> len("€uro".encode("utf-8")) 6 59

Khi bạn đã sẵn sàng chuỗi bit của mình, bạn có thể nhận được biểu diễn thập phân của nó bằng cách tận dụng một nghĩa đen nhị phân:

Đây là một cách nhanh chóng để thực hiện chuyển đổi trong khi làm việc bên trong trình thông dịch Python tương tác. Thật không may, nó đã giành chiến thắng cho phép bạn chuyển đổi trình tự bit được tổng hợp trong thời gian chạy vì tất cả các chữ cần phải được mã hóa cứng trong mã nguồn.

Gọi

>>> len("€uro".encode("utf-8"))
6
77 với hai đối số sẽ hoạt động tốt hơn trong trường hợp chuỗi bit được tạo động:

>>>

if age >= 18 and not is_self_excluded:
    print("You can gamble")
9

Đối số đầu tiên là một chuỗi các chữ số, trong khi phân tích thứ hai xác định cơ sở của hệ thống số. Không giống như một chữ nhị phân, một chuỗi có thể đến từ bất cứ đâu, ngay cả người dùng gõ trên bàn phím. Để có cái nhìn sâu sắc hơn về

>>> len("€uro".encode("utf-8"))
6
77, bạn có thể mở rộng hộp bên dưới.

Có nhiều cách khác để gọi

>>> len("€uro".encode("utf-8"))
6
77. Ví dụ: nó trả về 0 khi được gọi mà không có đối số:

Tính năng này làm cho nó trở thành một mẫu phổ biến trong bộ sưu tập

>>> len("€uro".encode("utf-8"))
6
80, cần một nhà cung cấp giá trị mặc định. Lấy cái này làm ví dụ:

>>>

if age >= 18 & ~is_self_excluded:
    print("You can gamble")
0

Ở đây,

>>> len("€uro".encode("utf-8"))
6
77 giúp đếm các từ trong một câu. Nó được gọi là tự động bất cứ khi nào
>>> len("€uro".encode("utf-8"))
6
80 cần khởi tạo giá trị của một khóa bị thiếu trong từ điển.

Một cách sử dụng phổ biến khác của

>>> len("€uro".encode("utf-8"))
6
77 là đánh máy. Ví dụ: khi bạn vượt qua
>>> len("€uro".encode("utf-8"))
6
77 giá trị dấu phẩy động, nó cắt giảm giá trị bằng cách loại bỏ thành phần phân số:

Khi bạn cho nó một chuỗi, nó cố gắng phân tích một số từ nó:

>>>

if age >= 18 & ~is_self_excluded:
    print("You can gamble")
1

Nói chung,

>>> len("€uro".encode("utf-8"))
6
77 sẽ chấp nhận một đối tượng thuộc bất kỳ loại nào miễn là nó định nghĩa một phương thức đặc biệt có thể xử lý việc chuyển đổi.

Càng xa càng tốt. Nhưng những gì về số âm?

Mô phỏng bit dấu hiệu

Khi bạn gọi

>>> len("€uro".encode("utf-8"))
6
70 trên một số nguyên âm, nó chỉ chuẩn bị dấu trừ cho chuỗi bit thu được từ giá trị dương tương ứng:

>>>

if age >= 18 & ~is_self_excluded:
    print("You can gamble")
2

Thay đổi dấu hiệu của một số không ảnh hưởng đến chuỗi bit cơ bản trong Python. Ngược lại, bạn đã cho phép tiền tố một chuỗi một chút với dấu trừ khi chuyển đổi nó thành dạng thập phân:

>>>

if age >= 18 & ~is_self_excluded:
    print("You can gamble")
3

Điều đó có ý nghĩa trong Python bởi vì, bên trong, nó không sử dụng bit dấu hiệu. Bạn có thể nghĩ về dấu hiệu của một số nguyên trong Python như một phần thông tin được lưu trữ riêng biệt với mô đun.

Tuy nhiên, có một vài cách giải quyết cho phép bạn mô phỏng các chuỗi bit có độ dài cố định chứa bit dấu hiệu:

  • Bitmask
  • Hoạt động Modulo (
    >>> len("€uro".encode("utf-8"))
    6
    
    27)
  • >>> len("€uro".encode("utf-8"))
    6
    
    45 Mô -đun
  • >>> len("€uro".encode("utf-8"))
    6
    
    89 Mô -đun
  • Mô -đun
    >>> len("€uro".encode("utf-8"))
    6
    
    90

Bạn biết từ các phần trước để đảm bảo độ dài bit nhất định của một số, bạn có thể sử dụng bitmask tiện lợi. Ví dụ: để giữ một byte, bạn có thể sử dụng mặt nạ bao gồm chính xác tám bit bật:

>>>

if age >= 18 & ~is_self_excluded:
    print("You can gamble")
4

Mặt nạ lực lượng Python tạm thời thay đổi số lượng đại diện của số từ mức độ ký hiệu sang hai phần bổ sung và sau đó quay lại. Nếu bạn quên mất giá trị thập phân của chữ nhị phân kết quả, bằng 21410, thì nó sẽ đại diện cho -4210 trong hai bổ sung. Bit ngoài cùng bên trái sẽ là bit dấu hiệu.

Ngoài ra, bạn có thể tận dụng thao tác modulo mà bạn đã sử dụng trước đây để mô phỏng sự thay đổi bên phải logic trong Python:

>>>

if age >= 18 & ~is_self_excluded:
    print("You can gamble")
5

Nếu điều đó trông quá phức tạp cho sở thích của bạn, thì bạn có thể sử dụng một trong các mô -đun từ thư viện tiêu chuẩn thể hiện cùng ý định rõ ràng hơn. Ví dụ: sử dụng

>>> len("€uro".encode("utf-8"))
6
45 sẽ có tác dụng giống hệt nhau:

>>>

if age >= 18 & ~is_self_excluded:
    print("You can gamble")
6

Bạn đã nhìn thấy nó trước đây, nhưng cũng như một lời nhắc nhở, nó sẽ cõng các loại số nguyên không dấu từ C.

Một mô -đun tiêu chuẩn khác mà bạn có thể sử dụng cho loại chuyển đổi này trong Python là mô -đun

>>> len("€uro".encode("utf-8"))
6
89. Nó xác định một cấu trúc dữ liệu mà tương tự như
>>> len("€uro".encode("utf-8"))
6
93 nhưng chỉ được phép giữ các phần tử thuộc cùng loại số. Khi khai báo một mảng, bạn cần chỉ ra kiểu của nó lên phía trước bằng một chữ cái tương ứng:

>>>

if age >= 18 & ~is_self_excluded:
    print("You can gamble")
7

Ví dụ,

>>> len("€uro".encode("utf-8"))
6
94 là viết tắt của một byte có chữ ký 8 bit, trong khi
>>> len("€uro".encode("utf-8"))
6
95 là viết tắt của nó tương đương không dấu của nó. Có một vài loại được xác định trước khác, chẳng hạn như số nguyên 16 bit có chữ ký hoặc số điểm nổi 32 bit.

Sao chép các byte thô giữa hai mảng này thay đổi cách giải thích bit. Tuy nhiên, phải mất gấp đôi số lượng bộ nhớ, khá lãng phí. Để thực hiện việc viết lại một chút như vậy, bạn có thể dựa vào mô -đun

>>> len("€uro".encode("utf-8"))
6
90, sử dụng một bộ ký tự định dạng tương tự cho các khai báo loại:

>>>

if age >= 18 & ~is_self_excluded:
    print("You can gamble")
8

Đóng gói cho phép bạn đặt các đối tượng trong bộ nhớ theo các nhà xác định loại dữ liệu C đã cho. Nó trả về một đối tượng

>>> len("€uro".encode("utf-8"))
6
97 chỉ đọc, chứa các byte thô của khối bộ nhớ kết quả. Sau đó, bạn có thể đọc lại các byte đó bằng một bộ mã loại khác để thay đổi cách chúng được dịch thành các đối tượng Python.

Cho đến thời điểm này, bạn đã sử dụng các kỹ thuật khác nhau để có được chuỗi bit có độ dài cố định của các số nguyên được thể hiện trong hai biểu diễn bổ sung hai. Nếu bạn muốn chuyển đổi các loại chuỗi bit trở lại thành số nguyên Python, thì bạn có thể thử chức năng này:

if age >= 18 & ~is_self_excluded:
    print("You can gamble")
9

Hàm chấp nhận một chuỗi bao gồm các chữ số nhị phân. Đầu tiên, nó chuyển đổi các chữ số thành một số nguyên không dấu đơn giản, coi thường bit dấu hiệu. Tiếp theo, nó sử dụng hai bitmasks để trích xuất các dấu hiệu và độ lớn, vị trí phụ thuộc vào độ dài bit được chỉ định. Cuối cùng, nó kết hợp chúng bằng cách sử dụng số học thông thường, biết rằng giá trị liên quan đến bit dấu là âm.

Bạn có thể thử nó so với chuỗi bit cũ đáng tin cậy từ các ví dụ trước đó:

>>>

>>> age = 18
>>> is_self_excluded = True
>>> age >= 18 & ~is_self_excluded  # Bitwise logical operators
True
>>> age >= 18 and not is_self_excluded  # Logical operators
False
0

Python sườn

>>> len("€uro".encode("utf-8"))
6
77 coi tất cả các bit là cường độ, vì vậy không có bất ngờ nào ở đó. Tuy nhiên, chức năng mới này giả định chuỗi dài 32 bit theo mặc định, điều đó có nghĩa là bit dấu được ngầm bằng 0 cho các chuỗi ngắn hơn. Khi bạn yêu cầu một bit có độ dài phù hợp với chuỗi bit của bạn, thì bạn sẽ nhận được kết quả dự kiến.

Mặc dù số nguyên là loại dữ liệu phù hợp nhất để làm việc với các toán tử bitwise trong hầu hết các trường hợp, đôi khi bạn cần phải trích xuất và thao tác các đoạn dữ liệu nhị phân có cấu trúc, chẳng hạn như pixel hình ảnh. Các mô -đun

>>> len("€uro".encode("utf-8"))
6
89 và
>>> len("€uro".encode("utf-8"))
6
90 liên lạc ngắn gọn về chủ đề này, vì vậy bạn sẽ khám phá nó chi tiết hơn tiếp theo.

Nhìn thấy dữ liệu trong nhị phân

Bạn biết cách đọc và giải thích các byte cá nhân. Tuy nhiên, dữ liệu trong thế giới thực thường bao gồm nhiều hơn một byte để truyền tải thông tin. Lấy kiểu dữ liệu

>>> len("€uro".encode("utf-8"))
6
55 làm ví dụ. Một số điểm nổi duy nhất trong Python chiếm tới tám byte trong bộ nhớ.

Làm thế nào để bạn nhìn thấy những byte đó?

Bạn có thể chỉ cần sử dụng các toán tử bitwise vì họ không làm việc với các số điểm nổi:

>>>

>>> age = 18
>>> is_self_excluded = True
>>> age >= 18 & ~is_self_excluded  # Bitwise logical operators
True
>>> age >= 18 and not is_self_excluded  # Logical operators
False
1

Bạn phải quên mất loại dữ liệu cụ thể mà bạn đang xử lý và nghĩ về nó theo dòng byte chung chung. Bằng cách đó, nó đã giành được vấn đề về những gì các byte đại diện bên ngoài bối cảnh chúng được xử lý bởi các nhà khai thác bitwise.

Để có được

>>> len("€uro".encode("utf-8"))
6
97 của số điểm nổi trong Python, bạn có thể đóng gói nó bằng mô-đun
>>> len("€uro".encode("utf-8"))
6
90 quen thuộc:

>>>

>>> age = 18
>>> is_self_excluded = True
>>> age >= 18 & ~is_self_excluded  # Bitwise logical operators
True
>>> age >= 18 and not is_self_excluded  # Logical operators
False
2

Bỏ qua các ký tự định dạng được truyền qua đối số đầu tiên. Họ đã giành chiến thắng có ý nghĩa cho đến khi bạn đến phần thứ tự byte bên dưới. Đằng sau đại diện văn bản khá mơ hồ này che giấu một danh sách tám số nguyên:

>>>

>>> age = 18
>>> is_self_excluded = True
>>> age >= 18 & ~is_self_excluded  # Bitwise logical operators
True
>>> age >= 18 and not is_self_excluded  # Logical operators
False
3

Các giá trị của chúng tương ứng với các byte tiếp theo được sử dụng để biểu thị một số điểm nổi trong nhị phân. Bạn có thể kết hợp chúng để tạo ra một chuỗi bit rất dài:

>>>

>>> age = 18
>>> is_self_excluded = True
>>> age >= 18 & ~is_self_excluded  # Bitwise logical operators
True
>>> age >= 18 and not is_self_excluded  # Logical operators
False
4

64 bit này là dấu hiệu, số mũ và mantissa trong độ chính xác gấp đôi mà bạn đọc trước đó. Để tổng hợp một

>>> len("€uro".encode("utf-8"))
6
55 từ một chuỗi bit tương tự, bạn có thể đảo ngược quá trình:

>>>

>>> age = 18
>>> is_self_excluded = True
>>> age >= 18 & ~is_self_excluded  # Bitwise logical operators
True
>>> age >= 18 and not is_self_excluded  # Logical operators
False
5

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
05 trả về một tuple vì nó cho phép bạn đọc nhiều hơn một giá trị cùng một lúc. Ví dụ: bạn có thể đọc cùng một chuỗi bit như bốn số nguyên đã ký 16 bit:

>>>

>>> age = 18
>>> is_self_excluded = True
>>> age >= 18 & ~is_self_excluded  # Bitwise logical operators
True
>>> age >= 18 and not is_self_excluded  # Logical operators
False
6

Như bạn có thể thấy, cách một chuỗi một chút nên được giải thích phải được biết đến phía trước để tránh kết thúc với dữ liệu bị cắt xén. Một câu hỏi quan trọng bạn cần tự hỏi mình là kết thúc của luồng byte mà bạn nên bắt đầu đọc từ bên trái hoặc phải. Đọc để tìm hiểu.

Đơn đặt hàng byte

Không có tranh chấp về thứ tự các bit trong một byte duy nhất. Bạn luôn luôn tìm thấy bit ít đáng kể nhất ở Index Zero và bit có ý nghĩa nhất ở Index Seven, bất kể họ đặt ra thể chất trong bộ nhớ như thế nào. Các toán tử thay đổi bitwise dựa vào tính nhất quán này.

Tuy nhiên, không có sự đồng thuận nào cho thứ tự byte trong các khối dữ liệu đa dạng. Một phần thông tin bao gồm nhiều byte có thể được đọc từ trái sang phải như một văn bản tiếng Anh hoặc từ phải sang trái như một người Ả Rập chẳng hạn. Máy tính nhìn thấy byte trong một luồng nhị phân như con người nhìn thấy các từ trong một câu.byte order in multibyte chunks of data. A piece of information comprising more than one byte can be read from left to right like an English text or from right to left like an Arabic one, for example. Computers see bytes in a binary stream like humans see words in a sentence.

Nó không quan trọng là máy tính hướng nào chọn đọc các byte miễn là chúng áp dụng các quy tắc tương tự ở mọi nơi. Thật không may, các kiến ​​trúc máy tính khác nhau sử dụng các cách tiếp cận khác nhau, khiến việc chuyển dữ liệu giữa chúng trở nên khó khăn.

Big-endian vs Little-endian

Hãy để một số nguyên không dấu 32 bit tương ứng với số 196910, đó là năm mà Monty Python xuất hiện lần đầu tiên trên TV. Với tất cả các số không hàng đầu, nó có biểu diễn nhị phân sau đây 00000000000000000000111101100012.

Làm thế nào bạn sẽ lưu trữ một giá trị như vậy trong bộ nhớ máy tính?

Nếu bạn tưởng tượng bộ nhớ là một băng một chiều bao gồm các byte, thì bạn cần phải chia dữ liệu đó thành các byte riêng lẻ và sắp xếp chúng trong một khối liền kề. Một số người thấy tự nhiên khi bắt đầu từ đầu trái bởi vì đó là cách mà họ đọc, trong khi những người khác thích bắt đầu ở đầu bên phải:

Đơn đặt hàng byteĐịa chỉ nĐịa chỉ N+1Địa chỉ N+2Địa chỉ N+3
Lớn000000002 000000002 000001112 101100012
Little-endian101100012 000001112 000000002 000000002

Khi byte được đặt từ trái sang phải, byte có ý nghĩa nhất được gán cho địa chỉ bộ nhớ thấp nhất. Điều này được gọi là trật tự lớn. Ngược lại, khi các byte được lưu trữ từ phải sang trái, byte ít đáng kể nhất xuất hiện trước. Đó là đơn đặt hàng ít endian.big-endian order. Conversely, when bytes are stored from right to left, the least-significant byte comes first. That’s called little-endian order.

Cách nào tốt hơn?

Từ quan điểm thực tế, không có lợi thế thực sự của việc sử dụng cái này hơn cái kia. Có thể có một số lợi ích cận biên về hiệu suất ở cấp độ phần cứng, nhưng bạn đã giành được thông báo cho họ. Các giao thức mạng chính sử dụng thứ tự lớn, cho phép chúng lọc các gói dữ liệu nhanh chóng hơn với thiết kế phân cấp của địa chỉ IP. Ngoài ra, một số người có thể thấy thuận tiện hơn khi làm việc với một đơn đặt hàng byte cụ thể khi gỡ lỗi.

Dù bằng cách nào, nếu bạn không làm cho nó đúng và trộn lẫn hai tiêu chuẩn, thì những điều tồi tệ bắt đầu xảy ra:

>>>

>>> age = 18
>>> is_self_excluded = True
>>> age >= 18 & ~is_self_excluded  # Bitwise logical operators
True
>>> age >= 18 and not is_self_excluded  # Logical operators
False
7

Khi bạn tuần tự hóa một số giá trị cho một luồng byte bằng một quy ước và thử đọc lại với một quy ước khác, bạn sẽ nhận được một kết quả hoàn toàn vô dụng. Kịch bản này rất có thể khi dữ liệu được gửi qua mạng, nhưng bạn cũng có thể trải nghiệm nó khi đọc một tệp cục bộ ở một định dạng cụ thể. Ví dụ, tiêu đề của Windows Bitmap luôn sử dụng Little-Endian, trong khi JPEG có thể sử dụng cả hai đơn đặt hàng byte.

Endianness bản địa

Để tìm hiểu về Nền tảng của bạn, bạn có thể sử dụng mô -đun

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
06:

>>>

>>> age = 18
>>> is_self_excluded = True
>>> age >= 18 & ~is_self_excluded  # Bitwise logical operators
True
>>> age >= 18 and not is_self_excluded  # Logical operators
False
8

Khi bạn tuần tự hóa một số giá trị cho một luồng byte bằng một quy ước và thử đọc lại với một quy ước khác, bạn sẽ nhận được một kết quả hoàn toàn vô dụng. Kịch bản này rất có thể khi dữ liệu được gửi qua mạng, nhưng bạn cũng có thể trải nghiệm nó khi đọc một tệp cục bộ ở một định dạng cụ thể. Ví dụ, tiêu đề của Windows Bitmap luôn sử dụng Little-Endian, trong khi JPEG có thể sử dụng cả hai đơn đặt hàng byte.CPU architecture. It’s impossible to mock it for testing purposes without hardware virtualization such as QEMU, so even the popular VirtualBox won’t help.

Endianness bản địa

Để tìm hiểu về Nền tảng của bạn, bạn có thể sử dụng mô -đun

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
06:

Mặc dù vậy, bạn có thể thay đổi sự thay đổi, bởi vì nó là một tính năng nội tại của kiến ​​trúc CPU của bạn. Nó không thể chế giễu nó cho mục đích thử nghiệm mà không có ảo hóa phần cứng như QEMU, vì vậy ngay cả VirtualBox phổ biến cũng giành được sự giúp đỡ.

>>> age = 18
>>> is_self_excluded = True
>>> age >= 18 & ~is_self_excluded  # Bitwise logical operators
True
>>> age >= 18 and not is_self_excluded  # Logical operators
False
9

Đáng chú ý, gia đình X86 của các bộ xử lý từ Intel và AMD, cung cấp năng lượng cho hầu hết các máy tính xách tay và máy tính để bàn hiện đại, là ít endian. Các thiết bị di động dựa trên kiến ​​trúc ARM năng lượng thấp, là Bi-endian, trong khi một số kiến ​​trúc cũ như Motorola 68000 cổ đại chỉ là lớn.

Để biết thông tin về việc xác định tính endian trong C, mở rộng hộp bên dưới.

>>>

>>> age >= (18 & ~is_self_excluded)
True
0

Khi bạn tuần tự hóa một số giá trị cho một luồng byte bằng một quy ước và thử đọc lại với một quy ước khác, bạn sẽ nhận được một kết quả hoàn toàn vô dụng. Kịch bản này rất có thể khi dữ liệu được gửi qua mạng, nhưng bạn cũng có thể trải nghiệm nó khi đọc một tệp cục bộ ở một định dạng cụ thể. Ví dụ, tiêu đề của Windows Bitmap luôn sử dụng Little-Endian, trong khi JPEG có thể sử dụng cả hai đơn đặt hàng byte.

>>>

>>> age >= (18 & ~is_self_excluded)
True
1

Khi bạn tuần tự hóa một số giá trị cho một luồng byte bằng một quy ước và thử đọc lại với một quy ước khác, bạn sẽ nhận được một kết quả hoàn toàn vô dụng. Kịch bản này rất có thể khi dữ liệu được gửi qua mạng, nhưng bạn cũng có thể trải nghiệm nó khi đọc một tệp cục bộ ở một định dạng cụ thể. Ví dụ, tiêu đề của Windows Bitmap luôn sử dụng Little-Endian, trong khi JPEG có thể sử dụng cả hai đơn đặt hàng byte.

Endianness bản địa

Để tìm hiểu về Nền tảng của bạn, bạn có thể sử dụng mô -đun

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
06:

Mặc dù vậy, bạn có thể thay đổi sự thay đổi, bởi vì nó là một tính năng nội tại của kiến ​​trúc CPU của bạn. Nó không thể chế giễu nó cho mục đích thử nghiệm mà không có ảo hóa phần cứng như QEMU, vì vậy ngay cả VirtualBox phổ biến cũng giành được sự giúp đỡ.big-endian.

Các chương trình muốn giao tiếp qua mạng có thể lấy API C cổ điển, trong đó tóm tắt các chi tiết nitty-gritty bằng một lớp ổ cắm. Python kết thúc API thông qua mô-đun

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
12 tích hợp. Tuy nhiên, trừ khi bạn viết một giao thức nhị phân tùy chỉnh, bạn có thể muốn tận dụng sự trừu tượng hóa cấp cao hơn, chẳng hạn như giao thức HTTP, dựa trên văn bản.

Trong đó mô -đun

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
12 có thể hữu ích trong chuyển đổi thứ tự byte. Nó phơi bày một vài chức năng từ API C, với tên đặc biệt, twisting của chúng:

>>>

>>> age >= (18 & ~is_self_excluded)
True
2

Nếu máy chủ của bạn đã sử dụng đơn đặt hàng byte lớn, thì không có gì để làm. Các giá trị sẽ vẫn giữ nguyên.

Bitmasks

Một bitmask hoạt động giống như một stprint graffiti ngăn chặn sơn không được phun trên các khu vực cụ thể của một bề mặt. Nó cho phép bạn cô lập các bit để áp dụng một số chức năng trên chúng một cách chọn lọc. Bitmasking liên quan đến cả các toán tử logic bitwise và các toán tử thay đổi bitwise mà bạn đã đọc.

Bạn có thể tìm thấy bitmasks trong rất nhiều bối cảnh khác nhau. Ví dụ, mặt nạ mạng con trong địa chỉ IP thực sự là một bitmask giúp bạn trích xuất địa chỉ mạng. Các kênh pixel, tương ứng với các màu đỏ, xanh lá cây và xanh dương trong mô hình RGB, có thể được truy cập bằng bitmask. Bạn cũng có thể sử dụng Bitmask để xác định các cờ Boolean mà sau đó bạn có thể đóng gói trên một trường một chút.

Có một vài loại hoạt động phổ biến liên quan đến bitmasks. Bạn sẽ xem nhanh một số trong số họ dưới đây.

Nhận được một chút

Để đọc giá trị của một bit cụ thể trên một vị trí nhất định, bạn có thể sử dụng bitwise và chống lại một bitmask chỉ bao gồm một bit ở chỉ mục mong muốn:

>>>

>>> age >= (18 & ~is_self_excluded)
True
3

Nếu máy chủ của bạn đã sử dụng đơn đặt hàng byte lớn, thì không có gì để làm. Các giá trị sẽ vẫn giữ nguyên.

>>>

Nếu máy chủ của bạn đã sử dụng đơn đặt hàng byte lớn, thì không có gì để làm. Các giá trị sẽ vẫn giữ nguyên.

Bitmasks

Một bitmask hoạt động giống như một stprint graffiti ngăn chặn sơn không được phun trên các khu vực cụ thể của một bề mặt. Nó cho phép bạn cô lập các bit để áp dụng một số chức năng trên chúng một cách chọn lọc. Bitmasking liên quan đến cả các toán tử logic bitwise và các toán tử thay đổi bitwise mà bạn đã đọc.

Bạn có thể tìm thấy bitmasks trong rất nhiều bối cảnh khác nhau. Ví dụ, mặt nạ mạng con trong địa chỉ IP thực sự là một bitmask giúp bạn trích xuất địa chỉ mạng. Các kênh pixel, tương ứng với các màu đỏ, xanh lá cây và xanh dương trong mô hình RGB, có thể được truy cập bằng bitmask. Bạn cũng có thể sử dụng Bitmask để xác định các cờ Boolean mà sau đó bạn có thể đóng gói trên một trường một chút.

>>>

>>> age >= (18 & ~is_self_excluded)
True
5

Nếu máy chủ của bạn đã sử dụng đơn đặt hàng byte lớn, thì không có gì để làm. Các giá trị sẽ vẫn giữ nguyên.

Bitmasks

Một bitmask hoạt động giống như một stprint graffiti ngăn chặn sơn không được phun trên các khu vực cụ thể của một bề mặt. Nó cho phép bạn cô lập các bit để áp dụng một số chức năng trên chúng một cách chọn lọc. Bitmasking liên quan đến cả các toán tử logic bitwise và các toán tử thay đổi bitwise mà bạn đã đọc.

>>>

>>> age >= (18 & ~is_self_excluded)
True
6

Nếu máy chủ của bạn đã sử dụng đơn đặt hàng byte lớn, thì không có gì để làm. Các giá trị sẽ vẫn giữ nguyên.

Bitmasks

Một bitmask hoạt động giống như một stprint graffiti ngăn chặn sơn không được phun trên các khu vực cụ thể của một bề mặt. Nó cho phép bạn cô lập các bit để áp dụng một số chức năng trên chúng một cách chọn lọc. Bitmasking liên quan đến cả các toán tử logic bitwise và các toán tử thay đổi bitwise mà bạn đã đọc.

>>>

>>> age >= (18 & ~is_self_excluded)
True
7

Bạn có thể tìm thấy bitmasks trong rất nhiều bối cảnh khác nhau. Ví dụ, mặt nạ mạng con trong địa chỉ IP thực sự là một bitmask giúp bạn trích xuất địa chỉ mạng. Các kênh pixel, tương ứng với các màu đỏ, xanh lá cây và xanh dương trong mô hình RGB, có thể được truy cập bằng bitmask. Bạn cũng có thể sử dụng Bitmask để xác định các cờ Boolean mà sau đó bạn có thể đóng gói trên một trường một chút.

Có một vài loại hoạt động phổ biến liên quan đến bitmasks. Bạn sẽ xem nhanh một số trong số họ dưới đây.

Nhận được một chút

Để đọc giá trị của một bit cụ thể trên một vị trí nhất định, bạn có thể sử dụng bitwise và chống lại một bitmask chỉ bao gồm một bit ở chỉ mục mong muốn:

Mặt nạ sẽ triệt tiêu tất cả các bit ngoại trừ cái mà bạn quan tâm. Nó sẽ dẫn đến bằng không hoặc một sức mạnh của hai với số mũ bằng với chỉ số bit. Nếu bạn muốn nhận được một câu trả lời có hoặc không đơn giản, thì bạn có thể chuyển sang bên phải và kiểm tra bit ít đáng kể nhất:

>>> age >= (18 & ~is_self_excluded)
True
4

  • >>> len("€uro".encode("utf-8"))
    6
    
    59
  • >>> for char in "€uro":
    ...     print(char, len(char.encode("utf-8")))
    ...
    € 3
    u 1
    r 1
    o 1
    
    17
  • Lần này, nó sẽ bình thường hóa giá trị bit để nó không bao giờ vượt quá một. Sau đó, bạn có thể sử dụng hàm đó để lấy giá trị boolean
    >>> len("€uro".encode("utf-8"))
    6
    
    16 hoặc
    >>> len("€uro".encode("utf-8"))
    6
    
    17 chứ không phải là giá trị số.
  • Đặt một chút

Đặt một chút tương tự như nhận được một. Bạn tận dụng cùng một bitmask như trước đây, nhưng thay vì sử dụng bitwise và, bạn sử dụng bitwise hoặc toán tử:set algebra, such as union, intersection, and symmetric difference, as well as merge and update dictionaries.

Mặt nạ giữ lại tất cả các bit ban đầu trong khi thực thi một nhị phân ở chỉ mục được chỉ định. Nếu bit đó đã được đặt, giá trị của nó sẽ thay đổi.

Khai trương một chútĐể xóa một chút, bạn muốn sao chép tất cả các chữ số nhị phân trong khi thực thi 0 tại một chỉ mục cụ thể. Bạn có thể đạt được hiệu ứng này bằng cách sử dụng cùng một bitmask một lần nữa, nhưng ở dạng đảo ngược:
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
23
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
3
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
25
>>> (1 + 1) or "default"  # The left operand is truthy
2
>>> (1 - 1) or "default"  # The left operand is falsy
'default'
7
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
27
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
1
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
29
>>> (1 + 1) or "default"  # The left operand is truthy
2
>>> (1 - 1) or "default"  # The left operand is falsy
'default'
4
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
31
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
5
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
33
>>> len("€uro".encode("utf-8"))
6
00

Họ làm hầu như điều tương tự, vì vậy, nó sẽ sử dụng cú pháp nào. Ngoài ra, còn có một toán tử trừ quá tải (

>>> len("€uro".encode("utf-8"))
6
51), trong đó thực hiện sự khác biệt của hai bộ. Để thấy chúng hoạt động, giả sử bạn có hai bộ trái cây và rau quả sau:

>>>

>>> age >= (18 & ~is_self_excluded)
True
8

Họ chia sẻ một thành viên chung, khó phân loại, nhưng phần còn lại của các yếu tố của họ là rời rạc.

Một điều cần chú ý là

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
36 bất biến, thiếu các phương pháp để cập nhật tại chỗ. Tuy nhiên, khi bạn sử dụng các đối tác toán tử bitwise của họ, ý nghĩa hơi khác nhau:

>>>

>>> age >= (18 & ~is_self_excluded)
True
9

Họ chia sẻ một thành viên chung, khó phân loại, nhưng phần còn lại của các yếu tố của họ là rời rạc.

>>> (age >= 18) & ~is_self_excluded
0
0

Một điều cần chú ý là

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
36 bất biến, thiếu các phương pháp để cập nhật tại chỗ. Tuy nhiên, khi bạn sử dụng các đối tác toán tử bitwise của họ, ý nghĩa hơi khác nhau:

Có vẻ như

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
36 là rất bất biến khi bạn sử dụng các toán tử bitwise, nhưng ma quỷ nằm trong các chi tiết. Đây là những gì thực sự xảy ra:

>>>

>>> (age >= 18) & ~is_self_excluded
0
1

Họ chia sẻ một thành viên chung, khó phân loại, nhưng phần còn lại của các yếu tố của họ là rời rạc.

Một điều cần chú ý là >>> for char in "€uro": ... print(char, len(char.encode("utf-8"))) ... € 3 u 1 r 1 o 1 36 bất biến, thiếu các phương pháp để cập nhật tại chỗ. Tuy nhiên, khi bạn sử dụng các đối tác toán tử bitwise của họ, ý nghĩa hơi khác nhau:

Có vẻ như

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
36 là rất bất biến khi bạn sử dụng các toán tử bitwise, nhưng ma quỷ nằm trong các chi tiết. Đây là những gì thực sự xảy ra:

Lý do nó hoạt động lần thứ hai là bạn không thay đổi đối tượng bất biến ban đầu. Thay vào đó, bạn tạo một cái mới và gán nó cho cùng một biến.

>>>

>>> (age >= 18) & ~is_self_excluded
0
2

Họ chia sẻ một thành viên chung, khó phân loại, nhưng phần còn lại của các yếu tố của họ là rời rạc.

Một điều cần chú ý là

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
36 bất biến, thiếu các phương pháp để cập nhật tại chỗ. Tuy nhiên, khi bạn sử dụng các đối tác toán tử bitwise của họ, ý nghĩa hơi khác nhau:

Có vẻ như

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
36 là rất bất biến khi bạn sử dụng các toán tử bitwise, nhưng ma quỷ nằm trong các chi tiết. Đây là những gì thực sự xảy ra:

>>> (age >= 18) & ~is_self_excluded
0
3

Lý do nó hoạt động lần thứ hai là bạn không thay đổi đối tượng bất biến ban đầu. Thay vào đó, bạn tạo một cái mới và gán nó cho cùng một biến.unpythonic use of bitwise operators when it sees them in this type of expression. It immediately suggests replacing every occurrence of

>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
0 with a logical
>>> len("€uro".encode("utf-8"))
6
13, not knowing that doing so would make the code stop working!

Python

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
20 chỉ hỗ trợ bitwise hoặc, hoạt động giống như một nhà điều hành công đoàn. Bạn có thể sử dụng nó để cập nhật từ điển tại chỗ hoặc hợp nhất hai từ điển thành một từ mới:

Phiên bản tăng cường của toán tử bitwise tương đương với >>> for char in "€uro": ... print(char, len(char.encode("utf-8"))) ... € 3 u 1 r 1 o 1 39.

Các mô-đun bên thứ ba

Nhiều thư viện phổ biến, bao gồm Numpy, Pandas và Sqlalchemy, làm quá tải các toán tử bitwise cho các loại dữ liệu cụ thể của chúng. Đây là nơi có khả năng nhất mà bạn sẽ tìm thấy các nhà khai thác bitwise trong Python vì chúng không được sử dụng rất thường xuyên theo nghĩa ban đầu của chúng nữa.

Ví dụ, Numpy áp dụng chúng cho dữ liệu được vector hóa theo kiểu theo chiều điểm:Bằng cách này, bạn không cần phải áp dụng thủ công cùng một toán tử bitwise cho từng phần tử của mảng. Nhưng bạn có thể làm điều tương tự với các danh sách thông thường trong Python.
Pandas sử dụng Numpy phía sau hậu trường và nó cũng cung cấp các phiên bản quá tải của các toán tử bitwise cho các đối tượng
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
40 và
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
41. Tuy nhiên, họ cư xử như bạn mong đợi. Sự khác biệt duy nhất là họ thực hiện công việc thông thường của họ trên các vectơ và ma trận số thay vì trên các vô hướng riêng lẻ.
Mọi thứ trở nên thú vị hơn với các thư viện cung cấp cho các nhà khai thác bitwise hoàn toàn mới. Ví dụ: SQLalchemy cung cấp một cú pháp nhỏ gọn để truy vấn cơ sở dữ liệu:
BitWise và toán tử (
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
0) cuối cùng sẽ dịch sang một phần truy vấn SQL. Tuy nhiên, điều đó không rõ ràng lắm, ít nhất là không phải là IDE của tôi, điều này phàn nàn về việc sử dụng không thể sử dụng các toán tử bitwise khi nó nhìn thấy chúng trong loại biểu thức này. Nó ngay lập tức đề xuất thay thế mọi lần xuất hiện của
>>> def call(x):
...     print(f"call({x=})")
...     return x
...
>>> call(False) or call(True)  # Both operands evaluated
call(x=False)
call(x=True)
True
>>> call(True) or call(False)  # Only the left operand evaluated
call(x=True)
True
0 bằng
>>> len("€uro".encode("utf-8"))
6
13 logic, không biết rằng làm như vậy sẽ làm cho mã ngừng hoạt động!
Loại quá tải của nhà điều hành này là một thực hành gây tranh cãi dựa trên phép thuật ngầm mà bạn phải biết trước. Một số ngôn ngữ lập trình như Java ngăn chặn sự lạm dụng như vậy bằng cách không cho phép người vận hành quá tải hoàn toàn. Python tự do hơn về vấn đề đó và tin tưởng rằng bạn biết những gì bạn đang làm.
Kiểu dữ liệu tùy chỉnhĐể tùy chỉnh hành vi của các toán tử bitwise Python, bạn phải xác định một lớp và sau đó thực hiện các phương thức ma thuật tương ứng trong đó. Đồng thời, bạn có thể xác định lại hành vi của các toán tử bitwise cho các loại hiện có. Quá tải toán tử chỉ có thể trên các loại dữ liệu mới.
Dưới đây, một sự nhanh chóng của các phương pháp đặc biệt cho phép bạn làm quá tải các toán tử bitwise:Phương pháp ma thuật
Biểu hiện
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
45
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
46
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
47
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
48
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
49
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
50
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
51
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
52
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
53
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
54
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
55
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
56
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
57
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
58
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
59
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
60
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
61
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
62
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
63
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
64
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
65
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
66
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
67

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
68

>>>

>>> (age >= 18) & ~is_self_excluded
0
4

Họ chia sẻ một thành viên chung, khó phân loại, nhưng phần còn lại của các yếu tố của họ là rời rạc.

Một điều cần chú ý là >>> for char in "€uro": ... print(char, len(char.encode("utf-8"))) ... € 3 u 1 r 1 o 1 36 bất biến, thiếu các phương pháp để cập nhật tại chỗ. Tuy nhiên, khi bạn sử dụng các đối tác toán tử bitwise của họ, ý nghĩa hơi khác nhau:

Có vẻ như

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
36 là rất bất biến khi bạn sử dụng các toán tử bitwise, nhưng ma quỷ nằm trong các chi tiết. Đây là những gì thực sự xảy ra:

Để làm theo cùng với các ví dụ trong phần này, bạn có thể tải xuống mã nguồn bằng cách nhấp vào liên kết bên dưới:

Bạn sẽ tìm hiểu về Steganography và áp dụng khái niệm này để bí mật nhúng các tệp tùy ý vào hình ảnh bitmap.

Cryptography vs Steganography

Cryptography là về việc thay đổi một thông điệp thành một thông điệp chỉ có thể đọc được cho những người có chìa khóa phù hợp. Mọi người khác vẫn có thể nhìn thấy thông điệp được mã hóa, nhưng nó đã giành được bất kỳ ý nghĩa gì với họ. Một trong những hình thức mật mã đầu tiên là mật mã thay thế, chẳng hạn như mật mã Caesar được đặt theo tên của Julius Caesar. is about changing a message into one that is readable only to those with the right key. Everyone else can still see the encrypted message, but it won’t make any sense to them. One of the first forms of cryptography was the substitution cipher, such as the Caesar cipher named after Julius Caesar.

Steganography tương tự như mật mã vì nó cũng cho phép bạn chia sẻ các tin nhắn bí mật với đối tượng mong muốn của bạn. Tuy nhiên, thay vì sử dụng mã hóa, nó khéo léo che giấu thông tin trong một phương tiện không thu hút sự chú ý. Các ví dụ bao gồm sử dụng mực vô hình hoặc viết một bản nhạc trong đó chữ cái đầu tiên của mỗi từ hoặc dòng tạo thành một thông điệp bí mật. is similar to cryptography because it also allows you to share secret messages with your desired audience. However, instead of using encryption, it cleverly hides information in a medium that doesn’t attract attention. Examples include using invisible ink or writing an acrostic in which the first letter of every word or line forms a secret message.

Trừ khi bạn biết rằng một tin nhắn bí mật đã được che giấu và phương pháp để phục hồi nó, bạn có thể bỏ qua nhà mạng. Bạn có thể kết hợp cả hai kỹ thuật để thậm chí an toàn hơn, ẩn một thông điệp được mã hóa hơn là thông báo gốc.

Có rất nhiều cách để buôn lậu dữ liệu bí mật trong thế giới kỹ thuật số. Cụ thể, các định dạng tệp mang nhiều dữ liệu, chẳng hạn như tệp âm thanh, video hoặc hình ảnh, rất phù hợp vì chúng cung cấp cho bạn rất nhiều chỗ để làm việc. Các công ty phát hành tài liệu có bản quyền có thể sử dụng Steganography để đánh dấu các bản sao riêng lẻ và truy tìm nguồn gốc của một rò rỉ, ví dụ.

Dưới đây, bạn sẽ tiêm dữ liệu bí mật vào một bitmap đơn giản, rất đơn giản để đọc và viết bằng Python mà không cần sự phụ thuộc bên ngoài.bitmap, which is straightforward to read and write in Python without the need for external dependencies.

Định dạng tệp bitmap

Từ bitmap thường đề cập đến định dạng tệp bitmap Windows (

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
79), hỗ trợ một vài cách thay thế để biểu diễn pixel. Để làm cho cuộc sống dễ dàng hơn, bạn sẽ cho rằng các pixel được lưu trữ trong định dạng RGB (đỏ, xanh lá cây và xanh dương 24 bit không nén 24 bit. Một pixel sẽ có ba kênh màu có thể giữ các giá trị từ 010 đến 25510.

Mỗi bitmap bắt đầu bằng một tiêu đề tệp, chứa siêu dữ liệu như chiều rộng và chiều cao hình ảnh. Dưới đây là một vài lĩnh vực thú vị và vị trí của chúng liên quan đến việc bắt đầu tiêu đề:file header, which contains metadata such as the image width and height. Here are a few interesting fields and their positions relative to the start of the header:

Đồng ruộngByte bùChiều dài byteLoại hìnhGiá trị mẫu
Chữ ký
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
80
2 Sợi dâyBM
Kích thước tập tin
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
81
4 Int không dấu7,629,186
Dự trữ số 1
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
82
2 Byte0
Dự trữ #2
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
83
2 Byte0
Dự trữ #2
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
83
4 Int không dấu122
Dự trữ số 1
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
82
4 Int không dấu7,629,064
Dự trữ số 1
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
82
4 Int không dấu1,954
Dự trữ số 1
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
82
4 Int không dấu1,301
Dự trữ số 1
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
82
2 Byte24
Dự trữ #2
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
83
4 Int không dấu0
Dự trữ số 1
>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
82
4 Int không dấu0

Dự trữ số 1

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
82binary mode, seek the desired offset, read the given number of bytes, and deserialize them using
>>> len("€uro".encode("utf-8"))
6
90 like before:

>>> (age >= 18) & ~is_self_excluded
0
5

Byte

Dự trữ #2

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
83padded with zeros so that every row is a multiple of four bytes. If the width of the image times three bytes happens to be a multiple of four, then there’s no need for padding. Otherwise, empty bytes are added at the end of every row.

Pixel bù

>>> for char in "€uro": ... print(char, len(char.encode("utf-8"))) ... € 3 u 1 r 1 o 1 84

Kích thước pixel

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
85steganalysis, which uses statistics.

Hãy xem những hình ảnh bị cắt này:

Hướng dẫn does python have bitwise operators? - python có toán tử bitwise không?

Một bên trái đến từ bitmap ban đầu, trong khi hình ảnh bên phải mô tả một bitmap được xử lý với một video được nhúng được lưu trữ trên các bit ít có ý nghĩa nhất. Bạn có thể nhận ra sự khác biệt?

Phần mã sau đây mã hóa dữ liệu bí mật vào bitmap:

>>> (age >= 18) & ~is_self_excluded
0
6

Đối với mỗi byte của dữ liệu bí mật và tám byte tương ứng của dữ liệu pixel, không bao gồm các byte pad, nó chuẩn bị một danh sách các bit được truyền bá. Tiếp theo, nó ghi đè lên bit ít đáng kể nhất trong mỗi tám byte bằng cách sử dụng bitmask có liên quan. Kết quả được chuyển đổi thành đối tượng

>>> len("€uro".encode("utf-8"))
6
97 và được gán lại cho phần bitmap mà nó ban đầu đến.

Để giải mã một tệp từ cùng một bitmap, bạn cần biết có bao nhiêu byte bí mật đã được viết cho nó. Bạn có thể phân bổ một vài byte ở đầu luồng dữ liệu để lưu trữ số này hoặc bạn có thể sử dụng các trường dành riêng từ tiêu đề bitmap:

>>> (age >= 18) & ~is_self_excluded
0
7

Điều này nhảy sang phần bù bên phải trong tệp, tuần tự hóa Python

>>> len("€uro".encode("utf-8"))
6
59 thành các byte thô và viết chúng xuống.

Bạn cũng có thể muốn lưu trữ tên của tệp bí mật của bạn. Vì nó có thể có độ dài tùy ý, nên việc tuần tự hóa nó bằng cách sử dụng chuỗi kết thúc null, sẽ đi trước nội dung tệp. Để tạo một chuỗi như vậy, bạn cần mã hóa một đối tượng Python

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
94 cho các byte và nối thủ công byte null ở cuối:

>>>

>>> (age >= 18) & ~is_self_excluded
0
8

Ngoài ra, nó không bị tổn thương khi bỏ thư mục phụ huynh dư thừa từ đường dẫn bằng cách sử dụng

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
95.

Mã mẫu bổ sung bài viết này sẽ cho phép bạn mã hóa, giải mã và xóa một tệp bí mật khỏi bitmap đã cho bằng các lệnh sau:encode, decode, and erase a secret file from the given bitmap with the following commands:

>>> (age >= 18) & ~is_self_excluded
0
9

Đây là một mô -đun Runnable có thể được thực thi bằng cách gọi thư mục bao gồm của nó. Bạn cũng có thể thực hiện kho lưu trữ định dạng zip di động ra khỏi nội dung của nó để tận dụng hỗ trợ ứng dụng Python ZIP.

Chương trình này dựa trên các mô -đun từ thư viện tiêu chuẩn được đề cập trong bài viết và một vài mô -đun khác mà bạn có thể chưa nghe thấy trước đây. Một mô-đun quan trọng là

>>> for char in "€uro":
...     print(char, len(char.encode("utf-8")))
...
€ 3
u 1
r 1
o 1
96, hiển thị giao diện Python cho các tệp được ánh xạ bộ nhớ. Họ cho phép bạn thao tác các tệp lớn bằng cả API tệp tiêu chuẩn và API chuỗi. Nó như thể tập tin là một danh sách có thể thay đổi lớn mà bạn có thể cắt lát.memory-mapped files. They let you manipulate huge files using both the standard file API and the sequence API. It’s as if the file were one big mutable list that you could slice.

Đi trước và chơi xung quanh với bitmap gắn liền với các vật liệu hỗ trợ. Nó chứa một chút bất ngờ cho bạn!

Sự kết luận

Nắm vững các nhà khai thác Bitwise Python cho bạn sự tự do cuối cùng để thao túng dữ liệu nhị phân trong các dự án của bạn. Bây giờ bạn biết cú pháp của họ và các hương vị khác nhau cũng như các loại dữ liệu hỗ trợ chúng. Bạn cũng có thể tùy chỉnh hành vi của họ cho nhu cầu của riêng bạn.binary data in your projects. You now know their syntax and different flavors as well as the data types that support them. You can also customize their behavior for your own needs.

Trong hướng dẫn này, bạn đã học được cách:

  • Sử dụng các toán tử bitwise python để thao tác các bit riêng lẻbitwise operators to manipulate individual bits
  • Đọc và viết dữ liệu nhị phân theo cách không chính thống nền tảngplatform-agnostic way
  • Sử dụng bitmasks để đóng gói thông tin trên một byte duy nhấtbitmasks to pack information on a single byte
  • Quá tải các toán tử Bitwise Python trong các loại dữ liệu tùy chỉnh Python bitwise operators in custom data types
  • Ẩn các thông điệp bí mật trong hình ảnh kỹ thuật sốsecret messages in digital images

Bạn cũng đã học cách máy tính sử dụng hệ thống nhị phân để thể hiện các loại thông tin kỹ thuật số khác nhau. Bạn đã thấy một số cách phổ biến để giải thích các bit và cách giảm thiểu việc thiếu các loại dữ liệu không dấu trong Python cũng như cách lưu trữ số nguyên của Python, trong bộ nhớ.binary system to represent different kinds of digital information. You saw several popular ways to interpret bits and how to mitigate the lack of unsigned data types in Python as well as Python’s unique way of storing integer numbers in memory.

Với thông tin này, bạn đã sẵn sàng sử dụng đầy đủ dữ liệu nhị phân trong mã của mình. Để tải xuống mã nguồn được sử dụng trong ví dụ Watermarking và tiếp tục thử nghiệm với các toán tử bitwise, bạn có thể nhấp vào liên kết bên dưới:

Xem bây giờ hướng dẫn này có một khóa học video liên quan được tạo bởi nhóm Python thực sự. Xem nó cùng với hướng dẫn bằng văn bản để làm sâu sắc thêm sự hiểu biết của bạn: nhị phân, byte và các toán tử bitwise trong Python This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Binary, Bytes, and Bitwise Operators in Python

Có bao nhiêu nhà khai thác bitwise trong Python?

Có 6 toán tử bitwise trong Python.6 bitwise operators in Python.

Làm thế nào để bạn viết các toán tử bitwise trong Python?

Nó là đơn giản và có tác dụng của các bit 'lật'..của các bit được chỉ định bởi toán hạng bên phải.

Nhà điều hành bitwise có quan trọng trong Python không?

Các toán tử bitwise trong Python cho phép chúng tôi thao túng các bit dữ liệu riêng lẻ ở cấp độ cơ bản nhất.Nói cách khác, các toán tử bitwise trong Python được sử dụng để thực hiện các tính toán bitwise trên các giá trị số nguyên.Do đó, các giá trị số nguyên trước tiên được chuyển đổi thành dạng nhị phân và sau đó các hoạt động từng bit được thực hiện.lets us manipulate individual bits of data at the most basic level. In other words, bitwise operators in Python are used to perform bitwise calculations on integer values. Thus, the integer values are first converted into binary form, and then bit-by-bit operations are performed.

Cái nào không phải là toán tử bitwise trong Python?

Tổng quan về các nhà khai thác bitwise của Python.