Python之路day11-迭代器_迭代對象_函數名_global_nonlocal

前言時刻:

等會再寫吧,剛剛寫完一篇博客,我先寫信息安全讀書的筆記吧!python

寫完了,開始寫day11的總結吧c++

總結一波:今天學習了迭代對象、迭代器、函數名的用法、以及默認參數的坑、全局變量的修改和定義

一、迭代對象

迭代對象和迭代器,兩個很容易搞混,我以前一直覺得兩個是同樣的。直到昨天聽老師講了一遍,彷彿打開了一扇門😂,瞬間明白了。git

Python 中的迭代對象內部都有一個 __iter__ 方法,這是一個重要的標誌。python 中一切皆對象,可認爲迭代對象是一個可迭代重複輸出的對象。常見的有:str、list、tuple、dict、set、range面試

這裏咱們使用 dir 打印對象的全部方法,看 __iter__ 是否在裏面,api

>>> name = "python"
>>> dir(name)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

>>> "__iter__" in dir(name)
True

能夠看出字符串中是有 __iter__ 方法的,同理能夠測試列表、元組、字典等。數組

1.1 迭代對象的優缺點

迭代對象優勢:能夠直觀顯示內部數據,有不少方法,訪問速度快。迭代對象缺點:佔用存儲空間大,不能夠直接使用 for 循環,屬於典型的用空間複雜度換時間複雜度。安全

可是你可能會說爲啥字符串、列表、元組等都是能夠使用 for 循環的,這是由於當你使用 for 進行循環迭代對象的時候,Python 內部會默認將其轉成迭代器進行迭代循環。不懂迭代器嗎,那麼請看下面:bash

二、迭代器

從字面上理解就是可迭代的工具,其最大的優勢在於節省內存空間,每次僅迭代讀取其中一部份內容,可是相對費時間,典型的用時間複雜度換空間複雜度。而且只能一步一步向下迭代,不可逆向迭代。app

怎麼判斷是否是迭代器呢?答:看是否包含有 __iter____next__ 方法。目前已知的迭代器是讀取文件時的句柄f,能夠看下面的例子。ssh

>>> with open('test.txt', mode='r', encoding='utf8') as f:
...     print(dir(f))
...     print('__iter__' in dir(f) and '__next__' in dir(f))
... 
['_CHUNK_SIZE', '__class__', '__del__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_checkClosed', '_checkReadable', '_checkSeekable', '_checkWritable', '_finalizing', 'buffer', 'close', 'closed', 'detach', 'encoding', 'errors', 'fileno', 'flush', 'isatty', 'line_buffering', 'mode', 'name', 'newlines', 'read', 'readable', 'readline', 'readlines', 'reconfigure', 'seek', 'seekable', 'tell', 'truncate', 'writable', 'write', 'write_through', 'writelines']
True

2.1 迭代對象轉成迭代器

經過使用 iter() 將迭代對象轉成迭代器

name = "python"
item = iter(name)  # 將迭代對象 str 類型的字符串轉成一個迭代器

# 二、打印迭代器的內容 使用 next 向後讀取
print(item.__next__())  # 或者是 等價 next(item)
print(next(item))
# p
# y

三、全局變量和局部變量

3.1 global

操做全局變量可用 global

  1. 可在局部中建立全局變量

    # 一、局部中建立全局變量
    name = "python"
    
    def test():
        global age
        age = 17
        print(age, name)  # 17 python
    
    test()
    print(age)   # 17
  1. 也可在局部中修改全局變量

    # 二、局部中修改全局變量
    name = "python"
    
    def test():
        global name
        name = "I love python"
        print(name)  # I love python
    
    test()

這裏須要注意的是,若是不在局部中聲明 name 是全局變量,那麼就沒法修改全局變量,而就變成定義一個叫 name 的局部變量。

3.2 nonlocal

操做局部變量可用 nonlocal ,做用:1.不能修改全局變量,2.用於內層函數對外層函數的數據修改。

例子:

# nonlocal 的用法

def test():
    name = "I"
    
    def love():
        nonlocal name     # 若是此處不聲明 nonlocal 的話會報錯,找不到 name 變量
        name += " love Python"
        print(name)  # I love Python
    love()

test()

四、函數名

這個做爲函數的一點補充,函數的名稱能夠做爲:

  • 容器內的成員,將函數名放到容器(list、dict等)內。有點相似於 c++ 中的對象數組
  • 函數名能夠做爲函數的參數,
  • 函數名也可做爲函數的返回值

總的來講,函數名僅僅是一個函數的入口地址,運行時並不作實例化,只有調用時在進行解釋並實例化。

def test1():
    """直接調用型"""
    print("func test1")

def test2(func):
    """
    :params func: 函數名
    """
    print("func test2")
    func()

def test3():
    """
    :return: 函數名
    """
    print("func test3")
    return test1

func_list = [test1, test2, test3]

print(func_list)
# [<function test1 at 0x7fd89ecd4ee0>, <function test2 at 0x7fd89ecd4dc0>, <function test2 at 0x7fd89ecd4dc0>]

# 一、函數名存在容器中 調用
func_list[0]()   # func test1


# 二、函數名做爲函數的參數
func_list[1](test1)
"""
func test2
func test1
"""

# 三、函數名做爲返回值 調用
func_list[2]()()
"""
func test3
func test1
"""

小試牛刀面試題

注意面試的時候可不會讓你拿電腦跑代碼的,因此要用心思考。

(1)定義和引用順序問題:

# 一、默認參數的坑

def func():
    print(count)
    count = 3

func()

"""你的結果是?

此處報錯:UnboundLocalError: local variable 'count' referenced before assignment
緣由:你在定義變量的前面引用變量了。

"""

(2)默認參數的坑的題:

# 默認參數的坑 案例2.1def func(name, lis=[]):    lis.append(name)    print(lis)func('I')func('love')func('python')"""你的結果是?['I']['I', 'love']['I', 'love', 'python']"""

結果沒想到吧,這是由於函數默認的參數 lis定義了一個空列表,有存儲地址。當你連續調用函數 func 時,傳入的參數都添加到 lis 中了,因此就是上面打印的數據了。

弄懂了嗎?來來試試第二個題

# 默認參數的坑 案例2.2def func(name, lis=[]):    lis.append(name)    print(lis)func('I')func('love', ['c++'])func('python')"""你的結果是?['I']['c++', 'love']['I', 'python']"""

你會發現和第一題的答案差別仍是很大的,爲啥呢?首先第二個調用 func ,傳入了一個列表設爲 lis2 ,這個 lis2 會替換掉函數參數中的 lis 的值。注意是替換而不是覆蓋,自己 lis 對應的存儲地址仍是有的,因此當第三個調用是 func 時,將 "python" 追加到了 lis 中,就變成了 ['I', 'python']。

總結:

寫總結真的很腦子,鍛鍊本身的總結能力。

相關文章
相關標籤/搜索