blog

知っておくと便利なPythonの関数と機能

長年Pythonを使ってきて、昔は知らなかった機能や特徴に出くわしました。いくつかはとても便利だと考えられますが、十分に活用されていません。それを念頭に置いて、Pyghonの知っておくべき機能をいくつ...

Jul 9, 2015 · 13 min. read
シェア

Pythonを何年も使っているうちに、以前は知らなかった機能や関数に出くわしました。その中にはとても便利なのにあまり活用されていないものもあります。このことを念頭に置いて、Pyghonの知っておくべき機能をいくつかまとめてみました。

任意の数の引数を持つ関数

Pythonではオプショナルパラメータを定義できることはすでにご存知でしょう。しかし、関数に任意の数のパラメータを定義する別の方法があります。

まず、オプショナル・パラメーターだけを定義する例を以下に示します。

def function(arg1="",arg2=""): 
        print "arg1: {0}".format(arg1) 
        print "arg2: {0}".format(arg2) 
       
    function("Hello", "World") 
    # prints args1: Hello 
    # prints args2: World 
       
    function() 
    # prints args1: 
    # prints args2: 

それでは、任意の引数を取ることができる関数を定義する方法を見てみましょう。これにはタプルを使います。

def foo(*args): # just use "*" to collect all remaining arguments into a tuple 
        numargs = len(args) 
        print "Number of arguments: {0}".format(numargs) 
        for i, x in enumerate(args): 
            print "Argument {0} is: {1}".format(i,x) 
       
    foo() 
    # Number of arguments: 0 
       
    foo("hello") 
    # Number of arguments: 1 
    # Argument 0 is: hello 
       
    foo("hello","World","Again") 
    # Number of arguments: 3 
    # Argument 0 is: hello 
    # Argument 1 is: World 
    # Argument 2 is: Again 

Glob() によるファイルの検索

ほとんどのPython関数は長くて説明的な名前を持っています。しかし、glob()名前の関数は、他の場所ですでに馴染みがない限り、何をする関数なのかわからないかもしれません。

listdir()より強力にしたようなものです。パターンマッチを使ってファイルを検索することができます。

import glob 
       
    # get all py files 
    files = glob.glob('*.py') 
    print files 
       
    # Output 
    # ['arg.py', 'g.py', 'shut.py', 'test.py'] 

以下のような複数のファイルタイプを探すことができます:

import itertools as it, glob 
   
def multiple_file_types(*patterns): 
    return it.chain.from_iterable(glob.glob(pattern) for pattern in patterns) 
   
for filename in multiple_file_types("*.txt", "*.py"): # add as many filetype arguements 
    print filename 
   
# output 
#=========# 
# test.txt 
# arg.py 
# g.py 
# shut.py 
# test.py 

各ファイルの絶対パスを取得したい場合は、戻り値に対してrealpath()呼び出します:

    import itertools as it, glob, os 
 
def multiple_file_types(*patterns): 
return it.chain.from_iterable(glob.glob(pattern) for pattern in patterns) 
       
for filename in multiple_file_types("*.txt", "*.py"): # add as many filetype arguements 
 realpath = os.path.realpath(filename) 
print realpath 
       
# output 
#=========# 
# C:\xxx\pyfunc\test.txt 
# C:\xxx\pyfunc\arg.py 
# C:\xxx\pyfunc\g.py 
# C:\xxx\pyfunc\shut.py 
# C:\xxx\pyfunc\test.py 

テスト中のコンポーネントの調整

以下の例では inspect モジュールを使用しています。このモジュールはデバッグにとても便利で、ここで説明したこと以外にもいろいろなことができます。

この記事では、このモジュールのすべての詳細をカバーするわけではありませんが、いくつかの使用例を紹介します。

import logging, inspect  
        
    logging.basicConfig(level=logging.INFO,  
        format='%(asctime)s %(levelname)-8s %(filename)s:%(lineno)-4d: %(message)s',  
        datefmt='%m-%d %H:%M',  
        )  
    logging.debug('A debug message')  
    logging.info('Some information')  
    logging.warning('A shot across the bow')  
        
    def test():  
        frame,filename,line_number,function_name,lines,index=\  
            inspect.getouterframes(inspect.currentframe())[1]  
        print(frame,filename,line_number,function_name,lines,index)  
        
    test()  
        
    # Should print the following (with current date/time of course)  
    #10-19 19:57 INFO     test.py:9   : Some information  
    #10-19 19:57 WARNING  test.py:10  : A shot across the bow  
    #(, 'C:/xxx/pyfunc/magic.py', 16, '', ['test()
'], 0)  

ユニークIDの生成

一意な文字列を生成する必要がある場合があります。この目的のために md5() 関数を使っている人をよく見かけますが、実はこれはこの目的のためのものではありません。

実際には、uuid()と呼ばれるPython関数があり、この目的で使用されます。

import uuid 
result = uuid.uuid1() 
print result 
       
# output => various attempts 
# 9e177ec0-65b6-11e3-b2d0-e4d53dfcf61b 
# be57b880-65b6-11e3-a04d-e4d53dfcf61b 
# c3b2b90f-65b6-11e3-8c86-e4d53dfcf61b 

文字列は一意であるにもかかわらず、その後ろの数文字が似ていることにお気づきでしょう。これは、生成された文字列がコンピュータのMACアドレスにリンクされているためです。

重複を減らすために、両方の機能を使用することができます。

import hmac,hashlib 
key='1' 
data='a' 
print hmac.new(key, data, hashlib.sha256).hexdigest() 
   
m = hashlib.sha1() 
m.update("The quick brown fox jumps over the lazy dog") 
print m.hexdigest() 
   
# c6e693d0b35805080632bc2469e1154a8d1072a86557778c27a01329630f8917 
# 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12 

シリアライズ

複雑な変数をデータベースやテキストファイルに格納する必要が生じたことはありませんか?配列やオブジェクトグリッドをフォーマットされた文字列に変換するための派手な方法を思いつく必要はありません。

import pickle 
   
variable = ['hello', 42, [1,'two'],'apple'] 
       
    # serialize content 
    file = open('serial.txt','w') 
serialized_obj = pickle.dumps(variable) 
    file.write(serialized_obj) 
file.close() 
 
# unserialize to produce original content 
target = open('serial.txt','r') 
myObj = pickle.load(target) 
   
print serialized_obj 
print myObj 
   
#output 
# (lp0 
# S'hello' 
# p1 
# aI42 
# a(lp2 
# I1 
# aS'two' 
# p3 
# aaS'apple' 
# p4 
# a. 
# ['hello', 42, [1, 'two'], 'apple'] 

これは Python ネイティブのシリアライズ方法です。しかし、近年JSONが普及し、PythonはJSONのサポートを追加しました。JSONを使ってエンコードやデコードができるようになりました。

    import json 
       
    variable = ['hello', 42, [1,'two'],'apple'] 
print "Original {0} - {1}".format(variable,type(variable)) 
       
    # encoding 
    encode = json.dumps(variable) 
    print "Encoded {0} - {1}".format(encode,type(encode)) 
   
    #deccoding 
    decoded = json.loads(encode) 
    print "Decoded {0} - {1}".format(decoded,type(decoded)) 
   
# output 
   
# Original ['hello', 42, [1, 'two'], 'apple'] - <type 'list'=""> 
# Encoded ["hello", 42, [1, "two"], "apple"] - <type 'str'=""> 
# Decoded [u'hello', 42, [1, u'two'], u'apple'] - <type 'list'=""> 

これはよりコンパクトで、最も重要なことは、JavaScriptや他の多くの言語と互換性があるということです。しかし、複雑なオブジェクトの場合、この情報の一部が失われる可能性があります。

圧縮文字

圧縮というと、普通はZIP構造のようなファイルを思い浮かべます。Pythonでは、アーカイブファイルを介さずに長い文字を圧縮することが可能です。

import zlib 
   
    string =  """   Lorem ipsum dolor sit amet, consectetur 
                adipiscing elit. Nunc ut elit id mi ultricies 
                adipiscing. Nulla facilisi. Praesent pulvinar, 
                    sapien vel feugiat vestibulum, nulla dui pretium orci, 
                    non ultricies elit lacus quis ante. Lorem ipsum dolor 
                    sit amet, consectetur adipiscing elit. Aliquam 
                    pretium ullamcorper urna quis iaculis. Etiam ac massa 
                sed turpis tempor luctus. Curabitur sed nibh eu elit 
                    mollis congue. Praesent ipsum diam, consectetur vitae 
                    ornare a, aliquam a nunc. In id magna pellentesque 
                tellus posuere adipiscing. Sed non mi metus, at lacinia 
                augue. Sed magna nisi, ornare in mollis in, mollis 
                sed nunc. Etiam at justo in leo congue mollis. 
                Nullam in neque eget metus hendrerit scelerisque 
                eu non enim. Ut malesuada lacus eu nulla bibendum 
                    id euismod urna sodales. """ 
       
    print "Original Size: {0}".format(len(string)) 
       
    compressed = zlib.compress(string) 
    print "Compressed Size: {0}".format(len(compressed)) 
       
    decompressed = zlib.decompress(compressed) 
    print "Decompressed Size: {0}".format(len(decompressed)) 
       
    # output 
   
    # Original Size: 1022 
    # Compressed Size: 423 
    # Decompressed Size: 1022 

シャットダウン機能の登録

atexitと呼ばれるモジュールがあり、スクリプトの実行が終了した直後にコードを実行することができます。

スクリプトの実行終了時に、実行時間などのベースラインデータを測定したいとします:

import atexit 
import time 
import math 
   
def microtime(get_as_float = False) : 
    if get_as_float: 
        return time.time() 
    else: 
        return '%f %d' % math.modf(time.time()) 
start_time = microtime(False) 
atexit.register(start_time) 
   
def shutdown(): 
    global start_time 
    print "Execution took: {0} seconds".format(start_time) 
   
atexit.register(shutdown) 
   
# Execution took: 0.297000 1387135607 seconds 
# Error in atexit._run_exitfuncs: 
# Traceback (most recent call last): 
#   File "C:\Python27\lib\atexit.py", line 24, in _run_exitfuncs 
#     func(*targs, **kargs) 
# TypeError: 'str' object is not callable 
# Error in sys.exitfunc: 
# Traceback (most recent call last): 
#   File "C:\Python27\lib\atexit.py", line 24, in _run_exitfuncs 
#     func(*targs, **kargs) 
# TypeError: 'str' object is not callable 

一見とても簡単です。スクリプトの一番下にコードを追加するだけで、スクリプトが終了する前に実行されます。しかし、スクリプトに致命的なエラーがあったり、ユーザーによってスクリプトが終了させられたりすると、実行されないことがあります。

atexit.register()を使用すると、スクリプトが何のために実行を停止したかに関係なく、すべてのコードが実行されます。

はんけつをくだす

Read next

MentalTrotterは、GoogleのreCAPTCHAコードの解読に成功したと主張している。

文責\n「日本のAIギークスチームは、人間の脳をシミュレートする独自開発の画像認識アルゴリズムが、より少ないリソースで、より高い理想的な認識率を持つGoogleのreCAPTCHA CAPTCHAを解読することに成功したと発表しました。

Jul 8, 2015 · 1 min read