1. 程式人生 > 實用技巧 >zookeeper實現分散式鎖的原理和一個小例子

zookeeper實現分散式鎖的原理和一個小例子

  1. python 不支援複數轉換為整數或浮點數

    >>> float(4.5+0j)
    Traceback (most recent call last):
      File "<pyshell#5>", line 1, in <module>
        float(4.5+0j)
    TypeError: can't convert complex to float
    
    >>> int(4+0j)
    Traceback (most recent call last):
      File "<pyshell#6>", line 1, in <module>
        int(4+0j)
    TypeError: can't convert complex to int
    >>>
  2. 隨機數函式中缺少 randint,sample

    random.randint(x,y) #隨機生一個整數int型別,可以指定這個整數的範圍

    例項

    >>> random.randint(1000,9999)
    8449

    random.sample(sequence,length) 可以從指定的序列中,隨機的擷取指定長度的片斷,不修改原序列。

    例項

    >>> lst = random.sample('abcd1234',4)
    >>> strs = ''.join(lst)
    >>> strs
    'a432'
    >>>
  3. print(round(10.4)) #10
    print(round(10.5)) #10
    print(round(10.6)) #11
    print()
    print(round(11.4)) #11
    print(round(11.5)) #12
    print(round(11.6)) #12

    由執行得出結論:

    1. 當小數點左邊為偶數:小數點右邊X<6,舍
    2. 當小數點左邊為偶數:小數點右邊X>=6,入
    3. 當小數點左邊為奇數:小數點右邊X<5,舍
    4. 當小數點左邊為奇數:小數點右邊X>=5,入

    所以當小數點左邊分別為奇數和偶數的時候,小數點右邊的取捨也分別對應兩種取捨標準!

  4. 關於round,接力分析,結論如下:

    當個位為奇數,小數部分>=0.5入,其餘為舍

    當個位為偶數,小數部分>0.5入,其餘為舍。

    互動模式下的 example:

    >>> round(10.49)
    10
    >>> round(10.50)
    10
    >>> round(10.51)
    11
    >>> round(11.50)
    12
    >>> round(11.49)
    11
  5. “4舍6入5看齊,奇進偶不進”我覺得並不是因為浮點數在計算機表示的問題。計算機浮點數的表示是 ieee定義的標準規則,如果 python中存在,沒道理其他語言中不存在。事實上是因為該取捨方法比過去的 "四捨五入"方法在科學計算中更準確。而國家標準也已經規定使用 “4舍6入5看齊,奇進偶不進”取代"四捨五入".

    從統計學的角度上來講,如果大量資料無腦的採用四捨五入會造成統計結果偏大。而"奇進偶舍"可以將舍入誤差降到最低。

    奇進偶舍是一種比較精確比較科學的計數保留法,是一種數字修約規則。

    其具體要求如下(以保留兩位小數為例):

    • (1)要求保留位數的後一位如果是4或者4以下的數字,則捨去, 例如 5.214保留兩位小數為5.21。
    • (2)如果保留位數的後一位如果是6或者6以上的數字,則進上去, 例如5.216保留兩位小數為5.22。
    • (3)如果保留位數是保留整數部分或保留一位小數,則要根據保留位來決定奇進偶舍:
      >>> round(5.215,2)#實際並沒有進位
      5.21
      >>> round(5.225,2)
      5.22
      >>>
      >>> round(1.5)#此處進位
      2
      >>> round(1.5)==round(2.5)#偶數捨去
      True
      >>> round(1.15,1)
      1.1
      >>> round(1.25,1)
      1.2
      >>> round(1.151,1)
      1.2
      >>> round(1.251,1)
      1.3
    • (4) 如果保留位數的後一位如果是5,且該位數後有數字。則進上去,例如5.2152保留兩位小數為5.22,5.2252保留兩位小數為5.23,5.22500001保留兩位小數為5.23。
    從統計學的角度,“奇進偶舍”比“四捨五入”要科學,在大量運算時,它使舍入後的結果誤差的均值趨於零,而不是像四捨五入那樣逢五就入,導致結果偏向大數,使得誤差產生積累進而產生系統誤差,“奇進偶舍”使測量結果受到舍入誤差的影響降到最低。
  6. 針對前面有人提到複數不能強轉為int或者float的問題:

    其實在Python中,複數提供了2個函式,一個函式是real,返回複數的實數部分,另一個函式是imag,返回複數的虛數部分。因為實數跟複數是差異很大的型別,所以不支援強制轉換是可以理解的。因為在強制轉換過程中,虛數部分到底該怎麼轉換,是沒有定義的,而int和float只有實數部分,虛數部分該如何取捨?

    >>> a = 4.1+0.3j
    >>> a
    (4.1+0.3j)
    >>> a.real
    4.1
    >>> a.imag
    0.3
  7. Python3中已經不能使用cmp()函數了,被如下五個函式替代:

    import operator       #首先要匯入運算子模組
    
    operator.gt(1,2)      #意思是greater than(大於)
    operator.ge(1,2)      #意思是greater and equal(大於等於)
    operator.eq(1,2)      #意思是equal(等於)
    operator.le(1,2)      #意思是less and equal(小於等於)
    operator.lt(1,2)      #意思是less than(小於)
  8. fractions 模組提供了分數型別的支援。

    建構函式:
    class fractions.Fraction(numerator=0, denominator=1) 
    class fractions.Fraction(int|float|str|Decimal|Fraction)

    可以同時提供分子(numerator)和分母(denominator)給建構函式用於例項化Fraction類,但兩者必須同時是int型別或者numbers.Rational型別,否則會丟擲型別錯誤。當分母為0,初始化的時候會導致丟擲異常ZeroDivisionError。

    分數型別:

    from fractions import Fraction
    
    >>> x=Fraction(1,3)
    >>> y=Fraction(4,6)
    >>> x+y
    Fraction(1, 1)
    
    >>> Fraction('.25') 
    Fraction(1, 4)

    浮點數與分數的轉換:

    >>> f=2.5
    >>> z=Fraction(*f.as_integer_ratio())
    >>> z
    Fraction(5, 2)
    >>> x=Fraction(1,3)
    >>> float(x)
    0.3333333333333333
    >>>
  9. 小數物件:

    decimal 模組提供了一個 Decimal 資料型別用於浮點數計算,擁有更高的精度。

    >>> import decimal
    >>> decimal.getcontext().prec=4              # 指定精度(4位小數)
    >>> decimal.Decimal(1) / decimal.Decimal(7)
    Decimal('0.1429')
    >>> with decimal.localcontext() as ctx:      # 小數上下文管理器
    ...     ctx.prec=2
    ...     decimal.Decimal('1.00') / decimal.Decimal('3.00')
    ... 
    Decimal('0.33')
    >>>
  10. 關於Python整數比較的一些坑:

    Python中一切都是物件,物件比較可以用 == 或者 is。

    == 比較的是兩個物件的內容是否相等,預設會呼叫物件的 __eq__() 方法。

    is 比較的是兩個物件的 id 是否相等,也就是是否是同一個物件,是否指向同一個記憶體地址。

    >>> a = 4
    >>> b = 4
    >>> a == b
    True
    >>> a is b
    True
    >>> a = 256
    >>> b = 256
    >>> a == b
    True
    >>> a is b
    True
    >>> a = 257
    >>> b = 257
    >>> a == b
    True
    >>> a is b
    False

    我們看到,前幾組比較我們都可以理解顯示的結果,但是最後當 a/b 都指向 257 這個整數物件的時候,用 is 比較以後的結果是 False。

    這是因為 Python 處於對效能的考慮,內部作了優化,對於整數物件,把一些頻繁使用的整數物件快取起來,儲存到一個叫 small_ints 的連結串列中。

    在 Python 整個生命週期中,任何需要引用這些整數物件的地方,都不再重新建立新的整數物件,範圍是 [-5,256]。

    再看下面這個例子 :

    >>> a = 259
    >>> def foo () :
    ...     b = 259
    ...     c = 259
    ...     print(a is b)
    ...     print(b is c)
    ...
    >>> foo()
    False
    True

    這是因為 Python 程式都是由程式碼塊構成,程式碼塊作為程式的一個最小基本單位來執行。一個模組檔案/一個函式體/一個類/互動式命令中的單行程式碼都叫做一個程式碼塊。

    上面的程式中有兩部分程式碼塊,一個是名稱 a 所在的程式碼塊,一個是名稱 b/c 所在的程式碼塊。Python 的另一個優化的地方就是,如果在同一個程式碼塊中建立的兩個整數物件中,它們的值相等的話,那麼這兩個物件引用同一個整數物件。所以Python出於對效能的考慮,但凡是不可變的物件,在同一程式碼塊中,只有值相等的物件就不會重複建立,而是直接引用已經存在的物件。不僅整數物件,字串物件也遵循同樣的原則。

  11. 有時候在編寫程式的時候會用到進位制轉換,通常學校裡面教的都是取餘的方法其實有更加簡便的方法,這裡給大家分享一下。

    二進位制&十六進位制轉換表:

    十六進位制   0     1     2     3     4     5     6     7 
    二進位制   0000  0001  0010  0011  0100  0101  0110  0111
    十進位制     0     1     2     3     4     5     6     7
    十六進位制   8     9     A     B     C     D     E     F 
    二進位制   1000  1001  1010  1011  1100  1101  1110  1111
    十進位制     8     9     10    11    12    13    14    15

    把這個表牢牢記住!然後用下面的方法轉換,會有很高的效率。

    轉換方法:

    取四合一法:從二進位制小數點為分隔符,向左或向右每四位二進位制合為一位十六進位制。例子:

    1011| 1001 |1011.1001
      B     9     B .  9

    那最後的結果就是: b9b.9

    注意:換算時不足四位的情況,可以向左或向右補0
  12. 關於小數的四捨五入問題與電腦的二進位制和十進位制之間轉換問題,這不僅是出現在小數上,也出現在一些除法上,例如:

    10/3=3.3333333333333335 而不是約等於 3.3333……:

    >>> 10/3
    3.3333333333333335

    還有就是 0.1+0.1+0.1-0.3 不會等於 0,而是等於 5.551115123125783e-17:

    >>> 0.1+0.1+0.1-0.3
    5.551115123125783e-17
  13. 補充上面關於 cmp() 函式的問題,官方文件中有如下描述: (If you really need the cmp() functionality, you could use the expression (a > b) - (a < b) as the equivalent for cmp(a,b).)

    補充上面關於round()函式的問題,注意下面例子:

    >>> round(1.05,1)
    1.1
    >>> round(1.15,1)
    1.1
    >>> round(1.55,1)
    1.6
    >>> round(2.05,1)
    2.0
    >>> round(2.15,1)
    2.1
    >>> round(2.55,1)
    2.5

    官方的解釋是:這不是bug,而事關浮點數儲存:

    >>> from decimal import Decimal
    >>> Decimal.from_float(1.05)
    Decimal('1.0500000000000000444089209850062616169452667236328125')
    >>> Decimal.from_float(1.15)
    Decimal('1.149999999999999911182158029987476766109466552734375')
    >>> Decimal.from_float(1.55)
    Decimal('1.5500000000000000444089209850062616169452667236328125')
    >>> Decimal.from_float(2.05)
    Decimal('2.04999999999999982236431605997495353221893310546875')
    >>> Decimal.from_float(2.15)
    Decimal('2.149999999999999911182158029987476766109466552734375')
    >>> Decimal.from_float(2.55)
    Decimal('2.54999999999999982236431605997495353221893310546875')

    儘量避免使用round()。

  14. 數字與字元,列表之間的轉換

    1、字元轉為數字

    var='1234'
    num=int(var) # 如果是小數可用 float

    2、字元轉為列表

    num_list=list(var)

    3、列表轉為陣列

    可以用 numpy 模組:

    import numpy as np
    
    num_array=np.array(num_list)

    也可以是 num_array=[int(i) for i in num_list]。

  15. 一定要注意 +==+ 的不同。

    例項 1:

    >>> a = 5
    >>> a += 6
    >>> a
    11

    以上例項與下面例項的效果一樣:

    >>> a = 5
    >>> a = a + 6
    >>> a
    11

    例項2:

    >>> b = 5
    >>> b =+ 6
    >>> b
    6

    為什麼會是 6 而不是 11 呢? 因為例項2與下面程式碼一樣:

    >>> b = 5
    >>> b = +6  # 其實就是正數,只是一個賦值操作,+ 6 即為 +6,+6 為 6
    >>> b
    6

    一定要分清 += 和 =+ 哦!另外要注意 Python 可是沒有 a++ 指令的!

  16. 其實準確的進位規則是二進位制浮點數的:

    >>> round(1.5,0) # 1.5d -> 0x3FF8000000000000 -> 1.5, 按照5後為0處理,奇進偶不進
    2.0
    >>> round(2.5,0) # 2.5 -> 0x4004000000000000 -> 2.5,  按照5後為0處理,奇進偶不進
    2.0
    >>> round(1.15,1) #1.15 ->0x3FF2666666666666 -> 1.14999999999999991118215802999 按照4處理,退位
    1.1
    >>> round(1.25,1) # 1.25 ->0x3FF4000000000000 ->1.25 同2.5退位
    1.2
    >>>

    可以認為進位首先計算的是與整數間的差距,如果差距相等,才會出現奇進偶不進。注意其中1.15由於進位制問題到1.1和1.2距離不同,所以不是十進位制的round結果。

    >>> abs(1.25-1.2)==abs(1.25-1.2)
    True
    >>> abs(1.15-1.2)==abs(1.15-1.1)
    False