Python learning

Python learning

編碼

    # -*- coding: utf-8 -*-

計算

Python 支持的數字類型有:int、float、Decimal(十進制)、Fraction(分數)、復數

    >>> 8 / 5
    1.6
    >>> 17 // 5
    3
    >>> 5 * 2
    10
    >>> 5 ** 2
    25
    >>> 3.5 // 1.7
    2.0

字符串

可以單雙引號,特殊字符使用反斜杠轉義。

特殊的一些:

  1. 如果不想讓反斜杠當做轉義輸出,可以用原始字符串,方法是在第一個引號前面加上一個rr"C:\some\name"
  2. 字符串文本能夠分成多行。一種方法是使用三引號: """...""" 或者 '''...'''。行尾換行符會被自動包含到字符串中,但是可以在行尾加上 \ 來避免這個行為(行尾加上則不換行)
  3. 字符串可以由 + 操作符連接(粘到一起),可以由 * 表示重復,3 * 'un' + 'ium' == 'unununium'
  4. 字符串也可以被截取,索引從0記起,如word[2];索引也可以是負數,這將導致從右邊開始計算,word[-1]表示最后一個字符
  5. 字符串還支持切片,如word[2:5]表示獲取位置[2,5)的三個字符,如果word是Python,則獲取的字符串是tho,word[:5]表示從最開始到第4個位置的字符串,切片也支持負數
  6. 索引過大會引發IndexError,但是切片過大不會報錯
  7. Python字符串不可以被更改 — 它們是 不可變的 (整體賦值是可以的)。因此,賦值給字符串索引的位置會導致錯誤。word[1] = 'j'是錯誤的!而word = 'aaa'可以

相關鏈接:

  1. Text Sequence Type — str
  2. String Methods: 轉換和查找
  3. String Formatting
  4. String Formatting Operations

列表

同樣支持索引和切片、所有的切片操作都會返回一個包含請求的元素的新列表。這意味著下面的切片操作返回列表一個新的(淺)拷貝副本

    >>> sq1 = [1, 2, 3]
    >>> sq2 = sq1
    >>> sq3 = sq1[:]
    >>> sq1
    [1, 2, 3]
    >>> sq2
    [1, 2, 3]
    >>> sq3
    [1, 2, 3]
    >>> sq2[1] = 10
    >>> sq1
    [1, 10, 3]
    >>> sq2
    [1, 10, 3]
    >>> sq3[1] = 100
    >>> sq1
    [1, 10, 3]
    >>> sq3
    [1, 100, 3]

所以,我們知道,要想復制一個列表,需要使用[:]來獲取淺拷貝副本,而不能直接賦值。從上面的例子,也可以知道,列表支持對每個元素單獨修改

所以,還可以這樣:

    >>> sq1
    [1, 10, 3]
    >>> sq1 + [1, 2]
    [1, 10, 3, 1, 2]
    >>> sq1
    [1, 10, 3]
    >>> sq1.append(10)
    >>> sq1
    [1, 10, 3, 10]
    >>> sq1.extend([7, 6, 5])
    >>> sq1
    [1, 10, 3, 10, 7, 6, 5]
    >>> # insert value
    ... sq1[1:1] = [40, 50]
    >>> sq1
    [1, 40, 50, 10, 3, 10, 7, 6, 5]
    >>> # replace value
    ... sq1[1:3] = [60, 70]
    >>> sq1
    [1, 60, 70, 10, 3, 10, 7, 6, 5]
    >>> # remove value
    ... sq1[1:3] = []
    >>> sq1
    [1, 10, 3, 10, 7, 6, 5]

一個例子

    >>> # fibonacci
    ... a, b = 0, 1
    >>> while b < 10:
    ...     print(b)
    ...     a, b = b, a+b
    ...
    1
    1
    2
    3
    5
    8

這里要注意的是:

注意a, b = 0, 1a, b = b, a+b,這是 多重賦值 ,變量在賦值前,右邊的表達式從左到右計算,然后再分別賦值給左邊的每個變量。所以,將第二個多重賦值改成b, a = a+b, b也沒有問題

條件判斷:0、空序列(長度為0就算)為false,標準比較操作符與 C 相同: <>==<=>=!=

print()函數可以用,隔開變量輸出,并自動會在兩個變量之間加一個空格;print('aaa', end=','),end的默認值是\n,改掉這個之后,print不換行,而是以,結尾

流程控制

if語句

    if x < 0:
        print(x)
    elif x == 0:
        print("hello")
    else:
        print("+")

for語句

    words = ['cat', 'window', 'defenestrate']
    for w in words:
        print(w, len(w))

這里需要注意的是,Python 的 for 語句依據任意序列(鏈表或字符串)中的子項,按它們在序列中的順序來進行迭代。所以,在迭代過程中修改迭代序列不安全。如果你想要修改你迭代的序列(例如,復制選擇項),你可以迭代它的復本

    for w in words[:]:
        if len(w) > 6:
            words.insert(0, w)
    print(words)
    # ['defenestrate', 'cat', 'window', 'defenestrate']

在循環(for, while)中同樣可以使用breakcontinue,作用和 C 中相同

循環中,支持else子句,作用是在循環正常結束(break不算)后執行

range()函數

用于生成一個等差級數鏈表(注意:這不是列表List,是迭代器),以下是例子:

    >>> for i in range(5):
    ...     print(i)
    ...
    0
    1
    2
    3
    4

    range(5, 10)
       5 through 9

    range(0, 10, 3)
       0, 3, 6, 9

    range(-10, -100, -30)
      -10, -40, -70

    >>> a = ['Mary', 'had', 'a', 'little', 'lamb']
    >>> for i in range(len(a)):
    ...     print(i, a[i])
    ...
    0 Mary
    1 had
    2 a
    3 little
    4 lamb

    >>> print(range(10))
    range(0, 10)

    >>> list(range(5))
    [0, 1, 2, 3, 4]

定義函數

關鍵字def引入一個函數定義,在其后必須跟有函數名和包括形式參數的圓括號

函數體的第一行語句可以是可選的字符串文本,這個字符串是函數的文檔字符串,或者稱為 docstring。有些工具通過 docstrings 自動生成在線的或可打印的文檔,或者讓用戶通過代碼交互瀏覽;在你的代碼中包含 docstrings 是一個好的實踐,讓它成為習慣吧

    def func():
        """ 這是一個docstring """
        ...

沒有return語句的函數會返回None

在函數中引用全局的變量,可以用global語句聲明,如:global a

函數參數

默認參數值

    def func(num, str="hello"):
        if num in (1, 2, 3):
            print(num)

重要警告:默認值只被賦值一次。這使得當默認值是可變對象時會有所不同,比如列表、字典或者大多數類的實例。例如,下面的函數在后續調用過程中會累積(前面)傳給它的參數!!

    def f(a, L=[]):
        L.append(a)
        return L

    print(f(1))
    print(f(2))
    print(f(3))

會輸出:

    [1]
    [1, 2]
    [1, 2, 3]

取而代之的方法:

    def f(a, L=None):
        if L is None:
            L = []
        L.append(a)
        return L

關鍵字參數

    def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
        print("-- This parrot wouldn't", action, end=' ')
        print("if you put", voltage, "volts through it.")
        print("-- Lovely plumage, the", type)
        print("-- It's", state, "!")

    # 接受一個必選參數 (voltage) 以及三個可選參數 (state, action, 和 type)。可以用以下的任一方法調用

    parrot(1000)                                          # 1 positional argument
    parrot(voltage=1000)                                  # 1 keyword argument
    parrot(voltage=1000000, action='VOOOOOM')             # 2 keyword arguments
    parrot(action='VOOOOOM', voltage=1000000)             # 2 keyword arguments
    parrot('a million', 'bereft of life', 'jump')         # 3 positional arguments
    parrot('a thousand', state='pushing up the daisies')  # 1 positional, 1 keyword

可變參數列表

一個最不常用的選擇是可以讓函數調用可變個數的參數。這些參數被包裝進一個元組。在這些可變個數的參數之前,可以有零到多個普通的參數

    def write_multiple_items(file, separator, *args):
        file.write(separator.join(args))

通常,這些可變參數是參數列表中的最后一個(只針對于非關鍵字參數),因為它們將把所有的剩余輸入參數傳遞給函數。任何出現在*args后的參數是關鍵字參數,這意味著,他們只能被用作關鍵字,而不是位置參數

    >>> def concat(*args, sep="/"):
    ...    return sep.join(args)
    ...
    >>> concat("earth", "mars", "venus")
    'earth/mars/venus'
    >>> concat("earth", "mars", "venus", sep=".")
    'earth.mars.venus'

可變關鍵字參數列表

相當于接收一個字典,必須在可變參數列表(如果有)的后面

    def cheeseshop(kind, *arguments, **keywords):
        print("-- Do you have any", kind, "?")
        print("-- I'm sorry, we're all out of", kind)
        for arg in arguments:
            print(arg)
        print("-" * 40)
        keys = sorted(keywords.keys())
        for kw in keys:
            print(kw, ":", keywords[kw])

    cheeseshop("Limburger", "It's very runny, sir.",
               "It's really very, VERY runny, sir.",
               shopkeeper="Michael Palin",
               client="John Cleese",
               sketch="Cheese Shop Sketch")

    """ result:
    -- Do you have any Limburger ?
    -- I'm sorry, we're all out of Limburger
    It's very runny, sir.
    It's really very, VERY runny, sir.
    ----------------------------------------
    client : John Cleese
    shopkeeper : Michael Palin
    sketch : Cheese Shop Sketch
    """

在傳遞可變參數的時候可能遇到一種情況是,當要傳遞的參數已經是一個列表,而函數需要的是可變長參數,可以使用*來拆開。同理,字典拆成關鍵字參數可以用**

    >>> args = [3, 6]
    >>> list(range(*args))
    [3, 4, 5]
    >>> list(range(3, 6))
    [3, 4, 5]

Lambda形式

通過lambda關鍵字,可以創建短小的匿名函數。這里有一個函數返回它的兩個參數的和: lambda a, b: a+b

lambda 形式可以從外部作用域引用變量:

    >>> def make_incrementor(n):
    ...     return lambda x: x + n
    ...
    >>> f = make_incrementor(42)
    >>> f(0)
    42
    >>> f(1)
    43

pass語句

pass 語句什么也不做。它用于那些語法上必須要有什么語句,但程序什么也不做的場合

    class MyCls:
        pass
    def func():
        pass
    while True:
        pass

各種數據結構

列表方法

    >>> a = [66.25, 333, 333, 1, 1234.5]
    >>> print(a.count(333), a.count(66.25), a.count('x'))
    2 1 0
    >>> a.insert(2, -1)
    >>> a.append(333)
    >>> a
    [66.25, 333, -1, 333, 1, 1234.5, 333]
    >>> a.index(333)
    1
    >>> a.remove(333)
    >>> a
    [66.25, -1, 333, 1, 1234.5, 333]
    >>> a.reverse()
    >>> a
    [333, 1234.5, 1, 333, -1, 66.25]
    >>> a.sort()
    >>> a
    [-1, 1, 66.25, 333, 333, 1234.5]
    >>> a.pop()
    1234.5
    >>> a
    [-1, 1, 66.25, 333, 333]

可以看到,列表自帶pop和append方法,所以,可以直接把列表當做堆棧使用

    >>> stack = [3, 4, 5]
    >>> stack.append(6)
    >>> stack.append(7)
    >>> stack
    [3, 4, 5, 6, 7]
    >>> stack.pop()
    7
    >>> stack
    [3, 4, 5, 6]
    >>> stack.pop()
    6
    >>> stack.pop()
    5
    >>> stack
    [3, 4]

使用隊列:如果把列表當做隊列來使用,效率不高(頭部插入和彈出很慢)。可以使用collections.deque

    >>> from collections import deque
    >>> queue = deque(["Eric", "John", "Michael"])
    >>> queue.append("Terry")       # Terry arrives
    >>> queue.append("Graham")      # Graham arrives
    >>> queue.popleft()             # The first to arrive now leaves
    'Eric'
    >>> queue.popleft()             # The second to arrive now leaves
    'John'
    >>> queue                       # Remaining queue in order of arrival
    deque(['Michael', 'Terry', 'Graham'])

列表推導式為從序列中創建列表提供了一個簡單的方法

常規的方法如下,副作用是x變量在循環完畢后依然存在,而且長...

    >>> squares = []
    >>> for x in range(10):
    ...     squares.append(x**2)
    ...
    >>> squares
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

使用列表推導式:

    >>> squares = [x ** 2 for x in range(10)]
    >>> squares
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

列表推導式由包含一個表達式的括號組成,表達式后面跟隨一個for子句,之后可以有零或多個forif子句。結果是一個列表,由表達式依據其后面的forif子句上下文計算而來的結果構成

另一個例子:

    >>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
    [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

更多例子!!

del語句

del語句可以刪除列表的對應的索引項 或 變量,與pop()方法的區別在于不返回值,并且可以刪除切片和整個變量

    >>> a = [-1, 1, 66.25, 333, 333, 1234.5]
    >>> del a[0]
    >>> a
    [1, 66.25, 333, 333, 1234.5]
    >>> del a[2:4]
    >>> a
    [1, 66.25, 1234.5]
    >>> del a[:]
    >>> a
    []
    >>> del a
    >>> a
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'a' is not defined

元組和序列

我們知道列表和字符串有很多通用的屬性,例如索引和切割操作。它們是序列類型中的兩種

元組也是一種標準序列類型,一個元組由數個逗號分隔的值組成:

    >>> t = 12345, 54321, 'hello!'
    >>> t[0]
    12345
    >>> t
    (12345, 54321, 'hello!')
    >>> # Tuples may be nested:
    ... u = t, (1, 2, 3, 4, 5)
    >>> u
    ((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))
    >>> # Tuples are immutable:
    ... t[0] = 88888
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'tuple' object does not support item assignment
    >>> # but they can contain mutable objects:
    ... v = ([1, 2, 3], [3, 2, 1])
    >>> v
    ([1, 2, 3], [3, 2, 1])

上面的例子說明,元組在輸出的時候總是有括號的,但是輸入的時候可以不用。元組元素就像字符串元素,不可變。但是,如果元組中包含可變元素,里面的元素是可變的(如:列表)

特殊的情況,創建零個或一個元素的元組。零個元素直接用(),而一個元素的時候,需要額外加一個逗號,丑但有效1,(1,)

    >>> empty = ()
    >>> singleton = 'hello',    # <-- note trailing comma
    >>> len(empty)
    0
    >>> len(singleton)
    1
    >>> singleton
    ('hello',)

集合

集合(set)是一個無序不重復元素的集,基本功能包括關系測試和消除重復元素。集合對象還支持 union(聯合),intersection(交),difference(差)和 sysmmetric difference(對稱差集)等數學運算

大括號{...}set()函數可以用來創建集合。注意:想要創建空集合,你必須使用set()而不是{}。后者用于創建空字典

    >>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
    >>> print(basket)      # show that duplicates have been removed
    {'orange', 'banana', 'pear', 'apple'}
    >>> 'orange' in basket # fast membership testing
    True
    >>> 'crabgrass' in basket
    False

    >>> # Demonstrate set operations on unique letters from two words
    ...
    >>> a = set('abracadabra')
    >>> b = set('alacazam')
    >>> a          # unique letters in a
    {'a', 'r', 'b', 'c', 'd'}
    >>> a - b      # letters in a but not in b
    {'r', 'd', 'b'}
    >>> a | b      # letters in either a or b
    {'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
    >>> a & b      # letters in both a and b
    {'a', 'c'}
    >>> a ^ b      # letters in a or b but not both
    {'r', 'd', 'b', 'm', 'z', 'l'}

以上例子證明,集合支持自動的去重(但亂序)和數學運算

集合也支持推導式(并去重)

    >>> a = {x for x in 'abracadabra' if x not in 'abc'}
    >>> a
    {'r', 'd'}

字典

字典在其他語言中,可能被稱為“關聯數組”(associative arrays)。字典以關鍵字為索引,關鍵字可以是任意不可變類型,通常用字符串或數值。如果元組中只包含字符串和數字,它可以做為關鍵字,如果它直接或間接的包含了可變對象,就不能當做關鍵字。不能用列表做關鍵字,因為列表可以用索引、切割或者append()extend()等方法改變

字典的主要操作是依據鍵來存儲和析取值。也可以用del來刪除鍵:值對(key:value)。如果你用一個已經存在的關鍵字存儲值,以前為該關鍵字分配的值就會被遺忘。試圖從一個不存在的鍵中取值會導致錯誤

    >>> tel = {'jack': 4098, 'sape': 4139}
    >>> tel['guido'] = 4127
    >>> tel
    {'sape': 4139, 'guido': 4127, 'jack': 4098}
    >>> tel['jack']
    4098
    >>> del tel['sape']
    >>> tel['irv'] = 4127
    >>> tel
    {'guido': 4127, 'irv': 4127, 'jack': 4098}
    >>> list(tel.keys())
    ['irv', 'guido', 'jack']
    >>> sorted(tel.keys())
    ['guido', 'irv', 'jack']
    >>> 'guido' in tel
    True
    >>> 'jack' not in tel
    False

dict()構造函數可以直接從key-value對中創建字典。此外,字典推導式可以從任意的鍵值表達式中創建字典

    >>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
    {'sape': 4139, 'jack': 4098, 'guido': 4127}
    >>> dict(sape=4139, guido=4127, jack=4098)
    {'sape': 4139, 'jack': 4098, 'guido': 4127}
    >>> {x: x**2 for x in (2, 4, 6)}
    {2: 4, 4: 16, 6: 36}

循環技巧

循環字典,使用item()方法:

    >>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
    >>> for k, v in knights.items():
    ...     print(k, v)
    ...
    gallahad the pure
    robin the brave

循環序列,使用enumerate()

    >>> for i, v in enumerate(['tic', 'tac', 'toe']):
    ...     print(i, v)
    ...
    0 tic
    1 tac
    2 toe

同時循環兩個或更多序列,使用zip()整體打包:

    >>> questions = ['name', 'quest', 'favorite color']
    >>> answers = ['lancelot', 'the holy grail', 'blue']
    >>> for q, a in zip(questions, answers):
    ...     print('What is your {0}?  It is {1}.'.format(q, a))
    ...
    """ result:
    What is your name?  It is lancelot.
    What is your quest?  It is the holy grail.
    What is your favorite color?  It is blue.
    """

逆向循環,使用reversed()

    >>> for i in reversed(range(1, 10, 2)):
    ...     print(i)
    ...
    9
    7
    5
    3
    1

排序去重后輸出,使用sorted()

    >>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
    >>> for f in sorted(set(basket)):
    ...     print(f)
    ...
    apple
    banana
    orange
    pear

若要在循環內部修改正在遍歷的序列(例如復制某些元素),建議您首先制作副本(!)

    >>> words = ['cat', 'window', 'defenestrate']
    >>> for w in words[:]:  # Loop over a slice copy of the entire list.
    ...     if len(w) > 6:
    ...         words.insert(0, w)
    ...
    >>> words
    ['defenestrate', 'cat', 'window', 'defenestrate']

條件判斷

  1. 比較操作符innot in審核值是否在一個區間之內,1 not in [2, 3]
  2. 比較操作符isis not比較兩個對象是否相同,[] is ()
  3. 比較操作可以傳遞,1 <= 3 > 2,比較操作符具有相同的優先級
  4. 短路運算符andor,參數從左向右解析,一旦結果可以確定即停止,短路操作符的返回值通常是最后一個變量0 and 1
  5. notandor同屬于邏輯操作符,優先級not>and>or
  6. 總優先級:數值操作 > 比較操作 > 邏輯操作符
  7. C不同,Python在表達式內不能賦值

序列對象可以與相同類型的其他對象作比較,比較操作按字典序進行:首先比較前兩個元素,如果不同,就決定了比較的結果;如果相同,就比較后兩個元素,依此類推,直到所有序列都完成比較。如果兩個元素本身就是同樣類 型的序列,就遞歸字典序比較。如果兩個序列的所有子項都相等,就認為序列相等。如果一個序列是另一個序列的初始子序列,較短的一個序列就小于另一個。字符串的字典序按照單字符的ASCII順序

模塊

模塊是包括Python定義和聲明的文件。文件名就是模塊名加上.py后綴。模塊的模塊名(做為一個字符串)可以由全局變量__name__得到

    # 先在桌面新建一個test.py,定義一個hello()方法
    >>> os.getcwd()
    '/home/my/Desktop'
    >>> import test
    >>> test.hello()
    hello world
    >>> test.__name__
    'test'

除了包含函數定義外,模塊也可以包含可執行語句。這些語句一般用來初始化模塊。他們僅在 第一次 被導入的地方執行一次

    # 在test.py中加入一個輸出語句
    >>> import test
    import mod test successfully!

每個模塊都有自己私有的符號表,被模塊內所有的函數定義作為全局符號表使用。因此,模塊的作者可以在模塊內部使用全局變量,而無需擔心它與某個用戶的全局變量意外沖突

模塊可以導入其他的模塊。一個(好的)習慣是將所有的import語句放在模塊的開始(或者是腳本),這并非強制。被導入的模塊名會放入當前模塊的全局符號表中

import語句的一個變體直接從被導入的模塊中導入命名到本模塊的語義表中

    >>> from fibo import fib, fib2
    >>> fib(500)
    1 1 2 3 5 8 13 21 34 55 89 144 233 377

作為腳本來執行模塊

只需要添加一個if判定:

    if __name__ == "__main__":
        import sys
        fib(int(sys.argv[1]))

然后用python fibo.py 50即可傳入參數并執行

模塊的搜索路徑

導入一個叫spam的模塊時,解釋器先在當前目錄中搜索名為spam.py的文件。如果沒有找到的話,接著會到sys.path變量中給出的目錄列表中查找,變量的初始值如下:

  • 輸入腳本的目錄(當前目錄)
  • 環境變量PYTHONPATH表示的目錄列表中搜索
  • Python默認安裝路徑中的搜索
    >>> sys.path
    ['', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu', '/usr/lib/python3.5/lib-dynload', '/usr/local/lib/python3.5/dist-packages', '/usr/lib/python3/dist-packages']

需要注意的是由于這些目錄中包含有搜索路徑中運行的腳本,所以這些腳本不應該和標準模塊重名,否則在導入模塊時Python會嘗試把這些腳本當作模塊來加載。這通常會引發錯誤

dir()函數

內置函數dir()用于按模塊名搜索模塊定義,它返回一個字符串類型的存儲列表

    >>> import fibo, sys
    >>> dir(fibo)
    ['__name__', 'fib', 'fib2']

包通常是使用用“圓點模塊名”的結構化模塊命名空間。例如,名為 A.B 的模塊表示了名為A的包中名為B的子模塊。可以避免全局變量之間的相互沖突

包的結構可能是這樣的

    sound/              Top-level package
          __init__.py   Initialize the sound package
          formats/      Subpackage for file format conversions
                  __init__.py
                  wavread.py
                  wavwrite.py
                  aiffread.py
                  aiffwrite.py
                  auread.py
                  auwrite.py
                  ...
          effects/      Subpackage for sound effects
                  __init__.py
                  echo.py
                  surround.py
                  reverse.py
                  ...
          filters/      Subpackage for filters
                  __init__.py
                  equalizer.py
                  vocoder.py
                  karaoke.py
                  ...

當導入這個包時,Python通過sys.path搜索路徑查找包含這個包的子目錄

為了讓Python將目錄當做內容包,目錄中必須包含__init__.py文件。這是為了避免一個含有爛俗名字的目錄無意中隱藏了稍后在模塊搜索路徑中出現的有效模塊,比如string。最簡單的情況下,只需要一個空的__init__.py文件即可。當然它也可以執行包的初始化代碼,或者定義稍后介紹的__all__變量

導入模塊的方法:

    # 1
    import sound.effects.echo
    sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
    # 2
    from sound.effects import echo
    echo.echofilter(input, output, delay=0.7, atten=4)
    # 3
    from sound.effects.echo import echofilter
    echofilter(input, output, delay=0.7, atten=4)

from sound.effects import *可能會很慢,或者出現一些意外(強烈不推薦的寫法)。但是這種情況難以避免,對于包的作者來說唯一的解決方案就是提供一個明確的包索引:執行from package import *時,如果包中的__init__.py代碼定義了一個名為__all__的列表,就會按照列表中給出的模塊名進行導入(可以避免導入所有模塊)

輸入輸出

print()函數對于每個參數,自動用空格分開輸出,以下是比較優雅的輸出方式(不是拼接的):

    >>> print('We are the {} who say "{}!"'.format('knights', 'Ni'))
    We are the knights who say "Ni!"

    >>> print('{0} and {1}'.format('spam', 'eggs'))
    spam and eggs
    >>> print('{1} and {0}'.format('spam', 'eggs'))
    eggs and spam

    >>> print('This {food} is {adjective}.'.format(
    ...       food='spam', adjective='absolutely horrible'))
    This spam is absolutely horrible.

    >>> print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred',
                                                           other='Georg'))
    The story of Bill, Manfred, and Georg.

    >>> import math
    >>> print('The value of PI is approximately {0:.3f}.'.format(math.pi))
    The value of PI is approximately 3.142.

可以看到,{}用于指代格式化的內容,里面可以規定順序、關鍵字等

字段名后允許可選的':'和格式指令。這允許對值的格式化加以更深入的控制

更多例子

舊式的字符串格式化,使用%

    >>> print("Name:%10s Age:%8d Height:%8.2f" % ("Aviad", 25, 1.83))
    Name:     Aviad Age:      25 Height:    1.83

更多例子

文件讀寫

函數open()返回文件對象,這個函數通常需要兩個字符串參數:文件名、打開模式

這里要特別注意的是,對于非文本文件,要在模式后面加上'b',否則會錯誤當做文本文件,修改一些平臺有關的行結束符字符(Python打開文本,會默認會轉換成平臺相關的行結束符)

    >>> f = open('openfile', 'w');

文件的對象方法:

f.read(size)方法用于讀取文件內容,size是可選的數值,如果沒有指定size或者指定為負數,就會讀取并返回整個文件。當文件大小為當前機器內存兩倍時,就會產生問題。反之,會盡可能按比較大的size讀取和返回數據。如果到了文件末尾,f.read()會返回一個空字符串''

    >>> f.read()
    'This is the entire file.\n'
    >>> f.read()
    ''
    >>> f.read()
    ''

f.readline()從文件中讀取單獨一行,字符串結尾會自動加上一個換行符\n,只有當文件最后一行沒有以換行符結尾時,這一操作才會被忽略。這樣返回值就不會有混淆,如果f.readline()返回一個空字符串,那就表示到達了文件末尾,如果是一個空行,就會描述為'\n',一個只包含換行符的字符串

    >>> f.readline()
    'This is the first line of the file.\n'
    >>> f.readline()
    'Second line of the file\n'
    >>> f.readline()
    ''

高效的讀取方法

    >>> for line in f:
    ...     print(line, end='')
    ...

    ''' result:
    This is the first line of the file.
    Second line of the file
    '''

將所有行讀到一個列表中

    >>> f.seek(0)
    >>> list(f)
    ['dfsafdsa\n', 'dfsafds\n', 'fdsagdfhfdh\n', 'hfgng\n', 'nh\n', 'trh\n', 'trh\n', 'tr\n', '\n', '\n', 'h\n', 'tr\n', 'htrhtr\n', 'h\n', 'tr\n', 'htr\n', 'h\n', 'tr\n', '\n', '\n', '\n', 'htrhtr\n']
    >>> list(f)
    []
    >>> f.seek(0)
    >>> f.readlines()
    ['dfsafdsa\n', 'dfsafds\n', 'fdsagdfhfdh\n', 'hfgng\n', 'nh\n', 'trh\n', 'trh\n', 'tr\n', '\n', '\n', 'h\n', 'tr\n', 'htrhtr\n', 'h\n', 'tr\n', 'htr\n', 'h\n', 'tr\n', '\n', '\n', '\n', 'htrhtr\n']

f.write(string)方法將string的內容寫入文件(是覆蓋還是追加,視打開文件的模式而定),Python3.5.2經測試沒有返回值。如果想寫入非字符串的內容,首先要轉換為字符串

    >>> f.write('This is a test\n')

    >>> value = ('the answer', 42)
    >>> s = str(value)
    >>> f.write(s)

文件對象的指針

f.tell()返回一個整數,代表文件對象在文件中的指針位置,該數值計量了自文件開頭到指針處的比特數。需要改變文件對象指針話話,使用f.seek(offset,from_what)。指針在該操作中從指定的引用位置移動offset比特,引用位置由from_what參數指定。from_what值為0表示自文件起始處開始,1表示自當前文件指針位置開始,2表示自文件末尾開始(配合的offset是負數)。from_what可以忽略,其默認值為0

    >>> f = open('workfile', 'rb+')
    >>> f.write(b'0123456789abcdef')
    16
    >>> f.seek(5)     # Go to the 6th byte in the file
    5
    >>> f.read(1)
    b'5'
    >>> f.seek(-3, 2) # Go to the 3rd byte before the end
    13
    >>> f.read(1)
    b'd'

當你使用完一個文件時,調用f.close()方法就可以關閉它并釋放其占用的所有系統資源。在調用f.close()方法后,試圖再次使用文件對象將會自動失敗

    >>> f.close()
    >>> f.read()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: I/O operation on closed file
    >>> f
    <closed file 'test.txt', mode 'a+' at 0x7f8cd23ca5d0>

使用with處理文件對象的好習慣

使用關鍵字with的先進之處在于文件用完后會自動關閉,就算發生異常也沒關系。它是try-finally塊的簡寫

    >>> with open('test.txt', 'r') as f:
    ...     read_data = f.read()
    ...
    >>> read_data
    'dfsafdsa\n'
    >>> f.closed
    True

以上的語句相當于,先調用了open()函數,并將返回值賦給f,然后里面的語句是try塊里面的內容,finally的內容隱藏在f對象的__exit__方法中,即f.close()。這里需要注意的是,這里出現異常的話,仍然需要自己定義try-except來處理。參考鏈接

使用json存儲格式化數據

需要使用json標準模塊,import json

    >>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
    '["foo", {"bar": ["baz", null, 1.0, 2]}]'
    >>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]')
    ['foo', {'bar': ['baz', None, 1.0, 2]}]

    >>> x
    '["foo", {"bar": ["baz", null, 1.0, 2]}]'
    >>> f = open("test.txt", "w+")
    >>> f.read()
    ''
    >>> f.tell()
    0
    >>> json.dump(x, f)
    >>> f.seek(0)
    >>> f.read()
    '"[\\"foo\\", {\\"bar\\": [\\"baz\\", null, 1.0, 2]}]"'
    >>> f.seek(0)
    >>> y = json.load(f)
    >>> y
    u'["foo", {"bar": ["baz", null, 1.0, 2]}]'
    >>> z = json.loads(y)
    >>> z[1]["bar"][2]
    1.0

錯誤和異常

語法錯誤

語法錯誤,也被稱作解析錯誤(最常見)

    >>> while True print('Hello world')
      File "<stdin>", line 1
        while True print('Hello world')
                       ^
    SyntaxError: invalid syntax

異常

即使一條語句或表達式在語法上是正確的,當試圖執行它時也可能會引發錯誤。運行期檢測到的錯誤稱為異常,并且程序不會無條件的崩潰:很快,你將學到如何在Python程序中處理它們。然而,大多數異常都不會被程序處理,像這里展示的一樣最終會產生一個錯誤信息

    >>> 10 * (1/0)
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
    ZeroDivisionError: int division or modulo by zero
    >>> 4 + spam*3
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
    NameError: name 'spam' is not defined
    >>> '2' + 2
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
    TypeError: Can't convert 'int' object to str implicitly

錯誤信息的最后一行指出發生了什么錯誤。異常也有不同的類型,異常類型做為錯誤信息的一部分顯示出來

異常處理

try語句按如下方式工作:

  1. 首先,執行try子句 (在tryexcept關鍵字之間的部分)
  2. 如果沒有異常發生,except子句在try語句執行完畢后就被忽略了
  3. 如果在try子句執行過程中發生了異常,那么該子句其余的部分就會被忽略。如果異常匹配于except關鍵字后面指定的異常類型,就執行對應的except子句。然后繼續執行try語句之后的代碼
  4. 如果發生了一個異常,在except子句中沒有與之匹配的分支,它就會傳遞到上一級try語句中。如果最終仍找不到對應的處理語句,它就成為一個未處理異常,終止程序運行,顯示提示信息

一個except子句可以在括號中列出多個異常的名字去匹配相應的異常;如果省略括號,則表示全部匹配

    import sys

    try:
        f = open('myfile.txt')
        s = f.readline()
        i = int(s.strip())
    except OSError as err:
        print("OS error: {0}".format(err))
    except ValueError:
        print("Could not convert data to an integer.")
    except:
        print("Unexpected error:", sys.exc_info()[0])
        raise

try-except語句可以帶有一個else子句,該子句只能出現在所有except子句之后。當try語句沒有拋出異常時,需要執行一些代碼,可以使用這個子句

    for arg in sys.argv[1:]:
        try:
            f = open(arg, 'r')
        except IOError:
            print('cannot open', arg)
        else:
            print(arg, 'has', len(f.readlines()), 'lines')
            f.close()

使用else子句比在try子句中附加代碼要好,因為這樣可以避免try-except意外的截獲本來不屬于它們保護的那些代碼拋出的異常

所以,except里面的代碼是錯誤的時候執行的;else里面的代碼是正確的時候執行的;finally里面的代碼是無論如何都會執行的(后面講到)

發生異常時,可能會有一個附屬值,作為異常的參數存在。這個參數是否存在、是什么類型,依賴于異常的類型。通常可以為except子句指定(as)一個變量,可以直接print出來看

異常處理器不僅僅處理那些在 try 子句中立刻發生的異常,也會處理那些 try 子句中調用的函數內部發生的異常

    >>> def this_fails():
    ...     x = 1/0
    ...
    >>> try:
    ...     this_fails()
    ... except ZeroDivisionError as err:
    ...     print('Handling run-time error:', err)
    ...
    Handling run-time error: int division or modulo by zero

raise語句允許程序員強制拋出一個指定的異常(必須是一個異常實例或異常類)

如果你需要明確一個異常是否拋出,但不想處理它,raise語句可以讓你很簡單的重新拋出該異常(一些監控工具的實現)

    >>> try:
    ...     raise NameError('HiThere')
    ... except NameError:
    ...     print('An exception flew by!')
    ...     raise
    ...
    ''' result:
    An exception flew by!
    Traceback (most recent call last):
      File "<stdin>", line 2, in ?
    NameError: HiThere
    '''

用戶可以自定義異常,異常類通常應該直接或間接從Exception類派生,下面是一個例子,更多例子看這里

    >>> class MyError(Exception):
    ...     def __init__(self, value):
    ...         self.value = value
    ...     def __str__(self):
    ...         return repr(self.value)
    ...
    >>> try:
    ...     raise MyError(2*2)
    ... except MyError as e:
    ...     print('My exception occurred, value:', e.value)
    ...
    ''' result:
    My exception occurred, value: 4
    >>> raise MyError('oops!')
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
    __main__.MyError: 'oops!'
    '''

前面說到的finally語句,是無論什么情況都會執行的功能,通常放的是清理行為,如果遇到異常,執行完這段清理語句之后就結束了,下面是一個混合try-except-else-finally的代碼塊

    >>> def divide(x, y):
    ...     try:
    ...         result = x / y
    ...     except ZeroDivisionError:
    ...         print("division by zero!")
    ...     else:
    ...         print("result is", result)
    ...     finally:
    ...         print("executing finally clause")
    ...
    >>> divide(2, 1)
    result is 2
    executing finally clause
    >>> divide(2, 0)
    division by zero!
    executing finally clause
    >>> divide("2", "1")
    executing finally clause
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
      File "<stdin>", line 3, in divide
    TypeError: unsupported operand type(s) for /: 'str' and 'str'

在真實場景的應用程序中,finally子句用于釋放外部資源(文件 或網絡連接之類的),無論它們的使用過程中是否出錯

有些對象定義了標準的清理行為,無論對象操作是否成功,不再需要該對象的時候就會起作用。下面有兩段代碼:

    # para 1
    for line in open("myfile.txt"):
        print(line)

    # para 2
    with open("myfile.txt") as f:
        for line in f:
            print(line)

區別在于,第一段代碼沒有關閉打開的文件,而with語句可以使文件之類的對象確保總能及時準確地進行清理。在第二段語句執行后,文件對象總會被關閉,即使是在處理文件中的數據時出錯也一樣可以

關于作用域的示例(注意變量的查找順序),以下例子:

    def scope_test():
        def do_local():
            spam = "local spam"
        def do_nonlocal():
            nonlocal spam
            spam = "nonlocal spam"
        def do_global():
            global spam
            spam = "global spam"
        spam = "test spam"
        do_local()
        print("After local assignment:", spam)
        do_nonlocal()
        print("After nonlocal assignment:", spam)
        do_global()
        print("After global assignment:", spam)

    scope_test()
    print("In global scope:", spam)

類定義語法

類定義就像函數定義,要先執行才能生效

    class ClassName:
        <statement-1>
        .
        .
        .
        <statement-N>

Python的類對象支持屬性引用和實例化,如:

    class MyClass:
        """A simple example class"""
        i = 12345
        def f(self):
            return 'hello world'

屬性引用: MyClass.i, MyClass.f, MyClass.__doc__
實例化: x = MyClass()

構造函數的定義:

    def __init__(self[, other params]):
        pass

類方法的第一個參數一定是self,在調用的時候省略傳入,代指實例本身

Python的實例對象唯一可用的操作是屬性引用。和局部變量一樣,數據屬性不需要聲明,第一次使用時它們就會生成

在調用方法的時候,如:x.f()事實上是調用了MyClass.f(x),這就是要在定義類方法的時候加上參數self的原因

類和實例變量

一般來說,實例變量用于對每一個實例都是唯一的數據,類變量用于類的所有實例共享的屬性和方法

    class Dog:

        kind = 'canine'         # class variable shared by all instances

        def __init__(self, name):
            self.name = name    # instance variable unique to each instance

    >>> d = Dog('Fido')
    >>> e = Dog('Buddy')
    >>> d.kind                  # shared by all dogs
    'canine'
    >>> e.kind                  # shared by all dogs
    'canine'
    >>> d.name                  # unique to d
    'Fido'
    >>> e.name                  # unique to e
    'Buddy'

這樣會出現,可變對象作共享數據的問題

    class Dog:

        tricks = []             # mistaken use of a class variable

        def __init__(self, name):
            self.name = name

        def add_trick(self, trick):
            self.tricks.append(trick)

    >>> d = Dog('Fido')
    >>> e = Dog('Buddy')
    >>> d.add_trick('roll over')
    >>> e.add_trick('play dead')
    >>> d.tricks                # unexpectedly shared by all dogs
    ['roll over', 'play dead']

正確的做法是,將這個列表作為一個實例變量,即放入構造方法中賦值

    class Dog:

        def __init__(self, name):
            self.name = name
            self.tricks = []    # creates a new empty list for each dog

        def add_trick(self, trick):
            self.tricks.append(trick)

    >>> d = Dog('Fido')
    >>> e = Dog('Buddy')
    >>> d.add_trick('roll over')
    >>> e.add_trick('play dead')
    >>> d.tricks
    ['roll over']
    >>> e.tricks
    ['play dead']

類的繼承

派生類的定義例子:

    class DerivedClassName(BaseClassName):
        <statement-1>
        .
        .
        .
        <statement-N>

派生類定義的執行過程和基類是一樣的。構造派生類對象時,就記住了基類。這在解析屬性引用的時候尤其有用:如果在類中找不到請求調用的屬性,就搜索基類

如果基類是由別的類派生而來,這個規則會遞歸的應用上去。方法引用按如下規則解析:搜索對應的類屬性,必要時沿基類鏈逐級搜索,如果找到了函數對象這個方法引用就是合法的

派生類可能會覆蓋其基類的方法。因為方法調用同一個對象中的其它方法時沒有特權,基類的方法調用同一個基類的方法時,可能實際上最終調用了派生類中的覆蓋方法

派生類中調用基類方法,這時需要傳入self參數了,BaseClassName.methodname(self, arguments)

判斷類或者實例之間的關系

  • 函數isinstance()用于檢查實例類型:isinstance(obj, int)只有在obj.__class__int或其它從int繼承的類型
  • 函數issubclass()用于檢查類繼承:issubclass(bool, int)True,因為boolint的子類
  • 然而,issubclass(float, int)False,因為float不是int的子類

Python同樣有限的支持多繼承形式,例子如下:

    class DerivedClassName(Base1, Base2, Base3):
        <statement-1>
        .
        .
        .
        <statement-N>

搜索順序:如果在DerivedClassName(示例中的派生類)中沒有找到某個屬性,就會搜索Base1,然后(遞歸的)搜索其基類,如果最終沒有找到,就搜索Base2,以此類推

上面的搜索順序有一個問題,如果多個Base擁有相同的基類,就會發生重復訪問基類的情況,這時,可以用super()來動態改變解析順序

為了防止重復訪問基類,通過動態的線性化算法,每個類都按從左到右的順序特別指定了順序,每個祖先類只調用一次

私有變量

Python中不存在只能從對象內部訪問的實例變量,一般規定私有變量以一個下劃線開頭命名,例如_spam。此外,形如__spam,以兩個下劃線開頭,后面至多只有一個下劃線的變量,會被替換為_classname__spam

    >>> class Ms1:
    ...     def _update(self):
    ...             print(345)
    ...     def __hello(self):
    ...             print("hello world")
    ...
    >>> m = Ms1()
    >>> m._Ms1__hello()
    hello world
    >>> m.__hello()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'Ms1' object has no attribute '__hello'
    >>> m._Ms1__hello()
    hello world
    >>> m._update()
    345

迭代器

大多數容器對象都可以用for遍歷,如for elem in [1, 2, 3]。在后臺,for語句在容器對象中調用iter(),該函數返回一個定義了__next__()方法的迭代器對象,它在容器中逐一訪問元素,當沒有后續的元素時,__next__()拋出一個StopIteration異常來通知for語句結束循環

可以使用內建的next()函數來調用__next__()方法

    >>> s = 'abc'
    >>> it = iter(s)
    >>> it
    <iterator object at 0x00A1DB50>
    >>> next(it)
    'a'
    >>> next(it)
    'b'
    >>> next(it)
    'c'
    >>> next(it)
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
        next(it)
    StopIteration

根據之前所說的原理,可以很容易的為自己的類添加迭代器行為,以下例子:

    class Reverse:
        """Iterator for looping over a sequence backwards."""
        def __init__(self, data):
            self.data = data
            self.index = len(data)
        def __iter__(self):
            return self
        def __next__(self):
            if self.index == 0:
                raise StopIteration
            self.index = self.index - 1
            return self.data[self.index]

    >>> rev = Reverse('spam')
    >>> iter(rev)
    <__main__.Reverse object at 0x00A1DB50>
    >>> for char in rev:
    ...     print(char)
    ...
    m
    a
    p
    s

生成器

生成器是創建迭代器的簡單而強大的工具,它們寫起來就像是正規的函數,需要返回數據的時候使用yield語句

    def reverse(data):
        for index in range(len(data)-1, -1, -1):
            yield data[index]

    >>> for char in reverse('golf'):
    ...     print(char)
    ...
    f
    l
    o
    g

前面中描述了基于類的迭代器,它能做的每一件事生成器也能做到。因為自動創建了__iter__()__next__()方法,生成器顯得如此簡潔。除了創建和保存程序狀態的自動方法,當發生器終結時,還會自動拋出StopIteration異常。綜上所述,這些功能使得編寫一個正規函數成為創建迭代器的最簡單方法

更多關于標準庫、包管理等的內容見手冊

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容

  • 定義類并創建實例 在Python中,類通過 class 關鍵字定義。以 Person 為例,定義一個Person類...
    績重KF閱讀 3,964評論 0 13
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,737評論 18 399
  • Python是一種對代碼風格很重視的語言,從縮進就能看出這一點,Python強調易于理解。最近在負責代碼重構的工作...
    知曰閱讀 10,981評論 1 85
  • 前言 ||| 第二章 使用ArcPy編寫腳本 Python支持大部分在其他語言中出現的編程結構。在本章內容中,我們...
    muyan閱讀 90,141評論 10 55
  • 那一年,2008。南方大雪災。還在北方冰天雪地里搓手取暖的我,想象著南方的雪到底是多大。 那一年,2008。西...
    情風古陽草閱讀 212評論 0 0