【阿里雲訓練營】python查漏補缺 1

文章來自:微信公衆號【機器學習煉丹術】。
有問題疑惑,或者想交流交朋友的可以加個人微信:cyx645016617
參考目錄:

1 註釋

  • 在 Python 中,# 表示註釋,作用於整行。
  • ''' ''' 或者 """ """ 表示區間註釋,在三引號之間的所有內容被註釋
    【例子】單行註釋
# 這是一個註釋
'''
這是多行註釋,用三個單引號
這是多行註釋,用三個單引號
這是多行註釋,用三個單引號
'''

2 is 與 ==

a = "hello"
b = "hello"
print(a is b, a == b)  # True True

a = ["hello"]
b = ["hello"]
print(a is b, a == b)  # False True

注意:

  • is, is not 對比的是兩個變量的內存地址
  • ==, != 對比的是兩個變量的值
  • 比較的兩個變量,指向的都是地址不可變的類型(str等),那麼is,is not 和 ==,!= 是完全等價的。
  • 對比的兩個變量,指向的是地址可變的類型(list,dict,tuple等),則兩者是有區別的。

3 運算優先級

  • 一元運算符優於二元運算符。例如3 ** -2等價於3 ** (-2)
  • 先算術運算,後移位運算,最後位運算。例如 1 << 3 + 2 & 7等價於 (1 << (3 + 2)) & 7
  • 邏輯運算最後結合。例如3 < 4 and 4 < 5等價於(3 < 4) and (4 < 5)

4 查找所有屬性和方法

利用dir()方法,下面查找int這個類型的屬性和方法

b = dir(int)
print(b)

# ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__',
# '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__',
# '__float__', '__floor__', '__floordiv__', '__format__', '__ge__',
# '__getattribute__', '__getnewargs__', '__gt__', '__hash__',
# '__index__', '__init__', '__init_subclass__', '__int__', '__invert__',
# '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__',
# '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__',
# '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__',
# '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__',
# '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__',
# '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__',
# '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__',
# 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag',
# 'numerator', 'real', 'to_bytes']

其中有一個bit_length,找到一個整數的二進制表示,再返回其長度。

a = 1031
print(bin(a))  # 0b10000000111
print(a.bit_length())  # 11

5 type和isinstance3

  • type() 不會認爲子類是一種父類類型,不考慮繼承關係。
  • isinstance() 會認爲子類是一種父類類型,考慮繼承關係。

6 位運算

操作符 名稱 示例
~ 按位取反 ~4
& 按位與 4 & 5
| 按位或 4 | 5
^ 按位異或 4 ^ 5
<< 左移 4 << 2
>> 右移 4 >> 2
print(bin(4))  # 0b100
print(bin(5))  # 0b101
print(bin(~4), ~4)  # -0b101 -5
print(bin(4 & 5), 4 & 5)  # 0b100 4
print(bin(4 | 5), 4 | 5)  # 0b101 5
print(bin(4 ^ 5), 4 ^ 5)  # 0b1 1
print(bin(4 << 2), 4 << 2)  # 0b10000 16
print(bin(4 >> 2), 4 >> 2)  # 0b1 1

6.1 原碼、反碼和補碼

二進制有三種不同的表示形式:原碼、反碼和補碼,計算機內部使用補碼來表示

原碼:就是其二進制表示(注意,有一位符號位)。

00 00 00 11 -> 3
10 00 00 11 -> -3

反碼:正數的反碼就是原碼,負數的反碼是符號位不變,其餘位取反(對應正數按位取反)。

00 00 00 11 -> 3
11 11 11 00 -> -3

補碼:正數的補碼就是原碼,負數的補碼是反碼+1。

00 00 00 11 -> 3
11 11 11 01 -> -3

符號位:最高位爲符號位,0表示正數,1表示負數。在位運算中符號位也參與運算。

6.2 按位運算

  • 按位非操作 ~
~ 1 = 0
~ 0 = 1

~num的補碼中的 0 和 1 全部取反(0 變爲 1,1 變爲 0)有符號整數的符號位在 ~ 運算中同樣會取反。

00 00 01 01 -> 5
~
---
11 11 10 10 -> -6

11 11 10 11 -> -5
~
---
00 00 01 00 -> 4
  • 按位與操作 &
1 & 1 = 1
1 & 0 = 0
0 & 1 = 0
0 & 0 = 0

只有兩個對應位都爲 1 時才爲 1

00 00 01 01 -> 5
&
00 00 01 10 -> 6
---
00 00 01 00 -> 4
  • 按位或操作 |
1 | 1 = 1
1 | 0 = 1
0 | 1 = 1
0 | 0 = 0

只要兩個對應位中有一個 1 時就爲 1

00 00 01 01 -> 5
|
00 00 01 10 -> 6
---
00 00 01 11 -> 7
  • 按位異或操作 ^
1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0

只有兩個對應位不同時才爲 1

00 00 01 01 -> 5
^
00 00 01 10 -> 6
---
00 00 00 11 -> 3

異或操作的性質:滿足交換律和結合律

A: 00 00 11 00
B: 00 00 01 11

A^B: 00 00 10 11
B^A: 00 00 10 11

A^A: 00 00 00 00
A^0: 00 00 11 00

A^B^A: = A^A^B = B = 00 00 01 11
  • 按位左移操作 <<

num << inum的二進制表示向左移動i位所得的值。

00 00 10 11 -> 11
11 << 3
---
01 01 10 00 -> 88 
  • 按位右移操作 >>

num >> inum的二進制表示向右移動i位所得的值。

00 00 10 11 -> 11
11 >> 2
---
00 00 00 10 -> 2 

6.3 利用位運算實現快速計算

通過 <<>> 快速計算2的倍數問題。

n << 1 -> 計算 n*2
n >> 1 -> 計算 n/2,負奇數的運算不可用
n << m -> 計算 n*(2^m),即乘以 2 的 m 次方
n >> m -> 計算 n/(2^m),即除以 2 的 m 次方
1 << n -> 2^n

通過 ^ 快速交換兩個整數。
通過 ^ 快速交換兩個整數。

a ^= b
b ^= a
a ^= b

通過 a & (-a) 快速獲取a的最後爲 1 位置的整數。

00 00 01 01 -> 5
&
11 11 10 11 -> -5
---
00 00 00 01 -> 1

00 00 11 10 -> 14
&
11 11 00 10 -> -14
---
00 00 00 10 -> 2

6.4 利用位運算實現整數集合

一個數的二進制表示可以看作是一個集合(0 表示不在集合中,1 表示在集合中)。

比如集合 {1, 3, 4, 8},可以表示成 01 00 01 10 10 而對應的位運算也就可以看作是對集合進行的操作。

元素與集合的操作:

a | (1<<i)  -> 把 i 插入到集合中
a & ~(1<<i) -> 把 i 從集合中刪除
a & (1<<i)  -> 判斷 i 是否屬於該集合(零不屬於,非零屬於)

集合之間的操作:

a 補   -> ~a
a 交 b -> a & b
a 並 b -> a | b
a 差 b -> a & (~b)

注意:整數在內存中是以補碼的形式存在的,輸出自然也是按照補碼輸出。

【例子】C#語言輸出負數。

class Program
{
    static void Main(string[] args)
    {
        string s1 = Convert.ToString(-3, 2);
        Console.WriteLine(s1); 
        // 11111111111111111111111111111101
        
        string s2 = Convert.ToString(-3, 16);
        Console.WriteLine(s2); 
        // fffffffd
    }
}

【例子】 Python 的bin() 輸出。

print(bin(3))  # 0b11
print(bin(-3))  # -0b11

print(bin(-3 & 0xffffffff))  
# 0b11111111111111111111111111111101

print(bin(0xfffffffd))       
# 0b11111111111111111111111111111101

print(0xfffffffd)  # 4294967293
0b11
-0b11
0b11111111111111111111111111111101
0b11111111111111111111111111111101
4294967293

是不是很顛覆認知,我們從結果可以看出:

  • Python中bin一個負數(十進制表示),輸出的是它的原碼的二進制表示加上個負號,巨坑。
  • Python中的整型是補碼形式存儲的。
  • Python中整型是不限制長度的不會超範圍溢出。

所以爲了獲得負數(十進制表示)的補碼,需要手動將其和十六進制數0xffffffff進行按位與操作,再交給bin()進行輸出,得到的纔是負數的補碼錶示。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章