Pythonの基礎-09 高階関数

高次関数

  • ある関数を別の関数の戻り値として使用する
def demo():
    print('我是test函数')
    return 'hello'

def demo():
    print('我是demo函数')
    return test

def bar():
    print('我是bar函数')
    return test()

x = test()  # 我是test函数
print(x)  # hello

y = demo()  # 我是demo函数
print(y)  # <function test at 0x000002136781CB80>
z = y()  # 我是test函数
print(z)    # hello

a = bar()  # 我是bar函数  我是test函数
print(a)  # hello
  • 別の関数のパラメータとしての関数 (ラムダ匿名関数)
# sort filter map reduce方法
# 主要还是 lambda 匿名函数的使用
  • 関数内に別の関数を定義する
# 函数嵌套
def outer(x):
    def inner():
        print('我是inner函数')

    if x > 18:
        inner()
    
    print('我是outer函数')

    return 'hello'

outer(12)  # 我是outer函数
outer(21)  # 我是inner函数  我是outer函数

閉鎖

  • まず、外部関数を内部関数でネストする必要があります。
  • 次に、外部関数が内部関数に戻る必要があります (内部関数を返す呼び出しではありません)。
  • 外部関数で変数を定義します。これはローカル変数です。
  • 内部関数では、これで定義したローカル変数を操作します
  • 外側の関数の戻り値が内側の関数になります
  • クロージャ= (ファンクション ブロック + 参照環境)
  • 内部関数で、外部スコープの変数 (グローバル スコープではない) が参照される場合、内部関数はクロージャと見なすことができます。

外部関数のローカル変数を内部関数で変更する方法

def outer():
    x = 10

    def inner():
        # 在内部函数中如何修改外部函数的局部变量的值
        nonlocal x  # 此处声明之后,修改的x就是外部的x,而不是内部新定义的变量x
        y = x + 1
        x = 20  # 当前语句会导致内部函数inner新建一个名为x的局部变量,因此上一句会报错
    
    return inner

outer()()

デコレータ

コードの実行時間を計算する

  • コード実行前に現在時刻を取得する
  • コード実行後に現在時刻を取得する
  • time モジュールを使用して現在のタイムスタンプを取得します
import time

# 在代码运行之前,获取一下时间
start = time.time()
# 时间戳是从1970-01-01 00:00:00 UTC(国际标准时)时间到现在时间经过的秒数
# 如需查看当前时间,需要将东八区时间转换成当前的国际标准时
print('start =',start)

x = 0 
for i in range(1,10000000):
    x += 1

print(x)
# 代码完成之后,在获取一下当前时间戳
end = time.time()
print('end =',end)
print('当前程序运行耗时秒数:',end-start)
  • 任意のコードの実行時間を調べるには、関数を定義することで実現できます。
import time

def get_used_time(fn):
    start = time.time()
    print('start =',start)
    fn()
    end = time.time()
    print('end =',end)
    print('当前程序运行耗时秒数:',end-start)

def test():
    x = 0  
    for i in range(1,10000000):
        x += 1

    print(x)

def sleep_time():
    print('hello')
    time.sleep(3)
    print('hi')

get_used_time(sleep_time)
get_used_time(test)

デコレータの使用

  • デコレータの使用例
import time

def cal_time(fn):
    def inner():
        start = time.time()
        fn()
        end = time.time()
        print('代码耗时',end-start)
    
    return inner

@cal_time # 第一件事,调用cal_time函数,第二件事,将demo函数当做cal_time的参数传递给fn
def demo():
    x = 0
    for i in range(1,100000):
        x += 1
    print(x)


@cal_time
def foo():
    print('hello')
    time.sleep(3)
    print('hi')

demo()  # 第三件事,调用inner函数,此时的demo函数,已经是被cal_time函数装饰过之后的inner函数
foo()

# 99999
# 代码耗时 0.00999903678894043
# hello
# hi
# 代码耗时 3.0013046264648438

デコレータの詳しい説明

  • デコレータを書く:
    • 仮パラメータ (fn) を使用して関数を定義 (デコレート)
    • この関数の中に内部関数(inner)もあります
    • 内部関数 (inner) は、仮パラメータ (fn) を処理 (装飾) し、仮パラメータ (fn) で渡された関数を呼び出します。
    • 外部関数 (decorate) は内部関数 (inner) を返します。
    • 使用する場合は、装飾が必要な関数(demo)の先頭で、@記号を使用してデコレーター(@decorate)を参照します。
    • インタプリタが関数 (デモ) を処理するとき、最初にデコレータ関数 (decorate) を呼び出します。
    • 仮引数(fn)にデコレーター関数の引数としてデコレートする関数(demo)を渡します。
    • デコレーター関数 (inner) 内で仮パラメーター (fn) を呼び出して修飾します。
    • デコレーター関数は内部関数 (inner) を処理して返します。このとき、元の関数 (demo) はデコレーターによって装飾された関数 (inner) になります。
    • 元の関数 (demo) を呼び出すと、実際に呼び出されるのは、デコレータ関数 (decorate) によって装飾された後に返される (inner) です。
  • デコレータ関数(decorate)の内部関数(inner)が値を返さない場合、修飾が必要な関数(demo)に戻り値がある場合、元の関数(demo)は正常に戻ることができなくなるため、次の例のように内部関数で元の関数の戻り値を取得して返す必要があります
import time

def cal_time(fn):
    def inner():
        start = time.time()
        fn()
        end = time.time()
        print('代码耗时',end-start)
    
    return inner

@cal_time
def demo():
    x = 0
    for i in range(1,100000):
        x += 1
    return x

x = demo()
print(x)

# 代码耗时 0.007985830307006836
# None
# 此时demo()实际上返回的是inner函数,因此返回值为None
  • 上記の問題を解決するには、次の例に示すように、内部関数 (inner) で変数を定義して、元の関数 (デモ) の戻り値を取得してそれを返すことができます。
import time

def cal_time(fn):
    def inner():
        start = time.time()
        x = fn()  # 定义一个x变量,获取原函数的返回值
        end = time.time()
        print('代码耗时',end-start)
        return x  # 返回x
    
    return inner

@cal_time
def demo():
    x = 0
    for i in range(1,100000):
        x += 1
    return x

x = demo()
print(x)

# 代码耗时 0.008002519607543945
# 99999
  • 同様に、元の関数 (デモ) に仮パラメータがある場合は、内部関数 (inner) で対応する仮パラメータを定義し、内部関数 (inner) で元の関数 (デモ) を呼び出すときにパラメータを渡す必要があります。複数のパラメータが必要な場合は、 inner(x, *args, **kwargs) を使用できます: 複数のパラメータを受け入れます

デコレータの高度な使用法

def can_play(fn):
    def inner(x,y,*args,**kwargs):
        clock = kwargs.get('clock',23)
        if clock >= 22:
            fn(x,y)
        else:
            print('太晚了赶紧睡')
    
    return inner

@can_play
def play_games(name,game):
    print('{}正在玩{}'.format(name,game))

play_games('张三','王者荣耀',m='hello',n='good',clock=18)  # 太晚了赶紧睡
play_games('王五','吃鸡')  # 王五正在玩吃鸡

モジュール

  • Pythonでは、pyファイルはモジュールとして理解できます
  • すべての py ファイルをモジュールとしてインポートできるわけではありません
  • py ファイルをインポートする場合、ファイル名は命名規則に従う必要があります。
    • 数字、文字、アンダースコアで構成されます
    • 数字で始めることはできません

モジュールをインポートするための構文

  • 開発を容易にするために、Python には多くの組み込みモジュールが提供されています
  • モジュールをインポートする方法
    1. import 模块名モジュールを直接インポートする
    2. from 模块名 import 函数名モジュールにメソッドまたは変数をインポートする
    3. from 模块名 import *このモジュールの「すべて」の変数とメソッドをインポートします
      1. 最初のインポートモジュール名との比較
      2. このメソッドは、print(pi) などのモジュール内の変数を直接使用できます。
      3. 最初のメソッドではモジュール名、変数名 (print(math.pi) など) を使用する必要があります。
    4. from 模块名 as 别名このモジュールをインポートし、このモジュールにエイリアスを付ける
    5. from 模块名 import 方法名 as 别名モジュールにメソッドをインポートし、このメソッドにエイリアスを付ける
# 导入这个模块之后,就可以使用这个模块里面的方法
import time  # 使用import 模块名 直接导入一个模块
from random import randint  # from 模块名 import 函数名 导入一个模块中某一个方法或者变量
from math import *  # from 模块名 import * 导入这个模块中"所有"的变量和方法(相比import 模块名,可以直接使用变量或者方法,而不需要模块名.变量名)
from datetime as dt  # from 模块名 as 别名 导入这个模块,并将这个模块起个别名
from copy import deepcopy as dp # from 模块名 import 方法名 as 别名 导入模块中的某个方法,将这个方法起个别名

共通の内蔵モジュール

OSモジュール

  • os モジュールは、オペレーティング システムのメソッドを呼び出すために使用されます。
import os
os.getcwd()  # 获取当前的工作目录,即当前python脚本工作的目录
os.chdir('test') # 改变当前脚本工作目录,相当于shell下的cd命令
os.rename('毕业论文.txt','毕业论文-最终版.txt') # 文件重命名
os.remove('毕业论文.txt') # 删除文件
os.rmdir('demo')  # 删除空文件夹
os.removedirs('demo') # 删除空文件夹
os.mkdir('demo')  # 创建一个文件夹
os.chdir('C:\\') # 切换工作目录
os.listdir('C:\\') # 列出指定目录里的所有文件和文件夹
os.name # nt->widonws posix->Linux/Unix或者MacOS
os.environ # 获取到环境配置
os.environ.get('PATH') # 获取指定的环境配置

os.path.abspath(path) # 获取Path规范会的绝对路径
os.path.exists(path)  # 如果Path存在,则返回True
os.path.isdir(path)  # 如果path是一个存在的目录,返回True。否则返回False
os.path.isfile(path) # 如果path是一个存在的文件,返回True。否则返回False
os.path.splitext(path)  # 用来将指定路径进行分隔,可以获取到文件的后缀名

システムモジュール

  • システム関連機能
import sys
sys.path # 模块的查找路径,结果是一个列表
sys.argv # 传递给Python脚本的命令行参数列表
sys.exit(code) # 让程序以指定的退出码结束

sys.stdin # 标准输入。可以通过它来获取用户的输入,和input相关
sys.stdout # 标准输出。可以通过修改它来改变默认输出位置
sys.stderr # 错误输出。可以通过修改它来改变错误删除

数学モジュール

  • 数学関連モジュール
import math
print(math.fabs(-100)) # 取绝对值
print(math.ceil(34.01))  #向上取整
print(math.factorial(5)) # 计算阶乘
print(math.floor(34.98))  # 向下取整
print(math.pi)   # π的值,约等于 3.141592653589793
print(math.pow(2, 10)) # 2的10次方
print(math.sin(math.pi / 6))  # 正弦值
print(math.cos(math.pi / 3))  # 余弦值
print(math.tan(math.pi / 2))  # 正切值

ランダムモジュール

  • 乱数関連のモジュール
print(random.random())  # 生成 [0,1)的随机浮点数
print(random.uniform(20, 30))  # 生成[20,30]的随机浮点数
print(random.randint(10, 30))  # 生成[10,30]的随机整数,等价于randrange(a,b+1)
print(random.randrange(20, 30))  # 生成[20,30)的随机整数
print(random.choice('abcdefg'))  # 从列表里随机取出一个元素
print(random.sample('abcdefghij', 3)) # 从列表里随机取出指定个数的元素

日時モジュール

  • date クラス: 日付を表示するために使用されます
  • 時間クラス: 時間を表示するために使用されます
  • datetime クラス: 時刻と日付を表示するために使用されます。
  • timedelta: 時間を計算するために使用されます
import datetime
print(datetime.date(2020, 1, 1))  # 创建一个日期
print(datetime.time(18, 23, 45)) # 创建一个时间
print(datetime.datetime.now())  # 获取当前的日期时间
print(datetime.datetime.now() + datetime.timedelta(3))  # 计算三天以后的日期时间

タイムモジュール

  • time モジュールは時間を操作するために使用されます
print(time.time())  # 获取从1970-01-01 00:00:00 UTC 到现在时间的秒数
print(time.strftime("%Y-%m-%d %H:%M:%S")) # 按照指定格式输出时间
print(time.asctime()) #Mon Apr 15 20:03:23 2019  给一个元组,转换成标准时间
print(time.ctime()) # Mon Apr 15 20:03:23 2019  给一个指定的时间戳可以转化成标准时间

print('hello')
print(time.sleep(10)) # 让线程暂停10秒钟
print('world')

カレンダーモジュール

  • カレンダーに関する操作
calendar.setfirstweekday(calendar.SUNDAY) # 设置每周起始日期码。周一到周日分别对应 0 ~ 6
calendar.firstweekday()# 返回当前每周起始日期的设置。默认情况下,首次载入calendar模块时返回0,即星期一。
c = calendar.calendar(2019)  # 生成2019年的日历,并且以周日为其实日期码
print(c)  #打印2019年日历
print(calendar.isleap(2000)) # True.闰年返回True,否则返回False
count = calendar.leapdays(1996,2010) # 获取1996年到2010年一共有多少个闰年
print(calendar.month(2019, 3))  # 打印2019年3月的日历

hashlibモジュールとhmacモジュール

これら 2 つのモジュールはデータ暗号化に使用され、
hashlib モジュールは主に 2 つのアルゴリズム md5 および sha 暗号化をサポートします。

import hashlib

# 待加密信息
str = '这是一个测试'

# 创建md5对象
hl = hashlib.md5('hello'.encode(encoding='utf8'))
print('MD5加密后为 :' + hl.hexdigest())

h1 = hashlib.sha1('123456'.encode())
print(h1.hexdigest())
h2 = hashlib.sha224('123456'.encode())
print(h2.hexdigest())
h3 = hashlib.sha256('123456'.encode())
print(h3.hexdigest())
h4 = hashlib.sha384('123456'.encode())
print(h4.hexdigest())
# sha算法后面的数字代表加密后的数字长度

x = hashlib.md5()
x.update('abc'.encode('utf-8'))
print(x)  # <md5 HASH object @ 0x0000020F9C19D9F0>
print(x.hexdigest())  # 900150983cd24fb0d6963f7d28e17f72

hmac モジュール暗号化、暗号化キーを指定できます

h = hmac.new('h'.encode(),'你好'.encode())
result = h.hexdigest()
print(result)  # 获取加密后的结果

uuidモジュール

グローバルに一意の ID を生成するために使用されます

方法 効果
uuid.uuid1() MAC アドレス、タイムスタンプ、乱数に基づいて一意の uuid を生成し、グローバルな一意性を確保します
uuid.uuid2() アルゴリズムは uuid1 と同じですが、タイムスタンプの最初の 4 ビットが POSIX UID に置き換えられる点が異なります。Python には DEC ベースのアルゴリズムがないため、Python の uuid モジュールには uuid2 メソッドがないことに注意してください。
uuid.uuid3(名前空間,名前) 名前空間名の md5 ハッシュ値を計算して uuid を取得することにより、異なる名前空間の異なる名前は異なる uuid を持ちますが、同じ名前は同じ uuid であることが保証されます。名前空間は、それ自体が手動で指定される文字列やその他の量ではなく、uuid モジュール自体で指定されるいくつかの値です。uuid.NAMESPACE_DNS、uuid.NAMESPACE_OID、uuid.NAMESPACE_OID などの値。これらの値自体も UUID オブジェクトであり、特定のルールに従って計算されます。
uuid.uuid4() 擬似乱数による uuid の取得が繰り返される可能性がある
uuid.uuid5(名前空間,名前) 基本的には uuid3 と同じですが、使用されるアルゴリズムは sha1 に置き換えられます。

一般に、uuid の要件がそれほど複雑でない場合は、uuid1 メソッドと uuid4 メソッドを使用するだけで十分です。

import uuid

print(uuid.uuid1())  # 根据时间戳和机器码生成uuid,可以保证全球唯一
print(uuid.uuid4())  # 随机生成uuid,可能会有重复

# 使用命名空间和字符串生成uuid.
# 注意一下两点:
# 1. 命名空间不是随意输入的字符串,它也是一个uuid类型的数据
# 2. 相同的命名空间和想到的字符串,生成的uuid是一样的
print(uuid.uuid3(uuid.NAMESPACE_DNS, 'hello'))
print(uuid.uuid5(uuid.NAMESPACE_OID, 'hello'))

ピップの使用

  • cmd で pip を直接実行します。エラーが報告された場合は、Python のインストール中に環境変数が設定されているか、pip がインストールされていないかを確認してください。
  • pipコマンド:
    • pip install flask(pip install <パッケージ名> は指定されたパッケージをインストールします)
    • pip uninstall flask(pip uninstall <パッケージ名> は指定されたパッケージをアンインストールします)
    • pip list(現在の環境にインストールされているモジュールを一覧表示するために使用されます)
    • pip freeze(現在の環境にインストールされているモジュールをリストします。モジュール名とバージョン番号は等号で接続されます)
      • (このコマンドを使用して、現在のサーバーにインストールされているすべてのパッケージのリストをファイルrequirements.txtにエクスポートおよびリダイレクトし、そのリストを使用してターゲットサーバーにインストールできます)
    • pip install -r requirements.txt(インストールするにはrequirements.txtファイルの内容を読んでください)
    • pip install <包名> -i <包源地址>(一時的な変更、pip は指定されたパッケージのソース アドレスから指定されたパッケージをダウンロードします)
      • pip のダウンロード場所を永続的に変更します。
        • 現在のシステム ユーザー フォルダーの下に新しい pip フォルダーを作成し、pip フォルダーの下に新しい pip.ini 構成ファイルを作成し、次の内容を書き込みます
[global]
index-url=https://pypi.douban.com/simple
[install]
trusted-host=pypi.douban.com

カスタムモジュールを使用する

  • モジュールは本質的には py ファイルです
  • 自分でモジュールを定義するということは、実際には自分で py ファイルを書くことになります
  • py ファイルをインポートする場合、ファイル名は命名規則に従う必要があります。
    • 数字、文字、アンダースコアで構成されます
    • 数字で始めることはできません
  • モジュールをインポートした後、このモジュールの変数とメソッドを使用できるようになります
  • このモジュール内の「すべての」変数と関数をインポートするために使用しますfrom <module_name> import *。これらは直接使用できます。
  • 基本的に、モジュール内の属性を読み取り、_all_その属性にどの変数や関数が定義されているかを確認します。
  • _all_モジュール内で属性が定義されていない場合、_次で始まらないすべての変数と関数
# module_1
__all__ = ['n','test']
n = 100 
m = 1

def test():
    print('我是test方法')

# 如果当前的模块被使用from <module_name> import * 方法进行调用
# 只能使用该模块中的n变量和test方法

# module_2
x = 1000
y = 'teszxt'

_age = 19

# 当前module_2在被导入时,由于没有设置_all_属性,以_开头的变量都不会呗引用
# _age变量不能被导入
# 使用import module_2  module_2._age
# 仍然可以对该变量进行调用
  • _ で始まる関数については、import <module_name>メソッドを使用した場合でも呼び出すことができますが、
  • カスタム モジュールの最後で使用できるメソッドはdel <module_name>、このモジュールの外でこの変数を呼び出すことは禁止されています

__name__ の使用

  • __name__この py ファイルを直接実行する場合、値は次のようになります。__main__
  • モジュールとしてインポートされた場合、__name__値はファイル名になります。
  • したがって、モジュール内でデバッグする必要がある場合は、__name__次の例に示すように、これを使用して、現在のモジュールが実行されているときにのみデバッグが実行されるようにすることができます。
if __name__ == '__main__':
    print('这是一个测试')

パッケージの使用

  • モジュールのインポート構文と同様に、システムのさまざまな組み込みまたは外部パッケージをインポートできます。

おすすめ

転載: blog.csdn.net/Lz__Heng/article/details/130192234