Pythonプログラミング:基本から応用までの包括的ガイド

目次

  • 関連リソース
  • Webフレームワーク
  • 学習プラットフォーム
  • 統合開発環境(IDE)
  • パッケージ管理
  • 仮想環境
  • 基本構文
  • データ型
  • 制御構造
  • モジュールとパッケージ
  • 関数
  • オブジェクト指向プログラミング
  • 正規表現
  • JSON処理
  • 列挙型
  • クロージャ
  • ラムダ式
  • デコレータ
  • 例外処理
  • コマンドライン操作
  • 一般的な誤解
  • ユーティリティ関数

関連リソース

公式サイト: Python.org

ドキュメント: Python 3.x ドキュメント

パッケージリポジトリ: PyPI

Webフレームワーク

  • Django: 大規模アプリケーション向けのフルスタックフレームワーク
  • Flask: 軽量で柔軟性の高いマイクロフレームワーク
  • FastAPI: 高速なAPI構築に特化したモダンなフレームワーク

学習プラットフォーム

  • Python OJ: オンラインジャッジシステムによる実践的学習
  • AtCoder: プログラミングコンテストプラットフォーム
  • Paiza: スキルアップと就職支援を兼ねた学習サイト

統合開発環境(IDE)

PyCharm

JetBrains社が提供する専門開発者向けのPython統合開発環境。コード補完、デバッガ、バージョン管理統合など多くの機能を備えています。

PyCharmのダウンロード

VSCodeのPython設定

Visual Studio CodeをPython開発用に設定する方法:

  1. Python拡張機能をインストール
  2. Pylintによるコード品質チェックを有効化
  3. コードフォーマッター(blackやautopep8)を設定
# Pylintのインストール
pip install pylint

パッケージ管理

pipの基本操作

パッケージのインストールとアンインストール

# パッケージのインストール
pip install requests

# パッケージのアンインストール
pip uninstall requests

ミラーサイトの利用

# 一時的にミラーサイトを指定してインストール
pip install -i https://pypi.doubanio.com/simple/ --trusted-host pypi.doubanio.com numpy

特定バージョンのインストール

# バージョンを指定してインストール
pip install pandas==1.3.0

仮想環境

virtualenvwrapperの利用

Windows環境での設定

注意: Windows環境ではGit Bashではなく、コマンドプロンプトを使用してください。

# virtualenvwrapper-winのインストール
pip install virtualenvwrapper-win

# 仮想環境の作成
mkvirtualenv -p C:\Python39\python.exe myproject

# 仮想環境の削除
rmvirtualenv myproject

仮想環境のデフォルト保存場所変更

  1. システム環境変数に WORKON_HOME を追加
  2. 値として仮想環境を保存したいパスを設定
  3. 指定したディレクトリを手動で作成
# コマンドプロンプトでテスト
workon

仮想環境の基本コマンド

# 仮想環境一覧表示
workon

# 新規仮想環境作成
mkvirtualenv プロジェクト名

# 仮想環境の有効化/切り替え
workon プロジェクト名

# 仮想環境の無効化
deactivate

基本構文

演算子

除算演算子

# 通常の除算(結果は浮動小数点数)
result = 10 / 3  # 3.333...

# 整数除算(結果は整数)
result = 10 // 3  # 3

べき乗演算子

# 2の3乗
result = 2 ** 3  # 8

比較演算子

# 値とデータ型の両方を比較
result = 5 == '5'  # False

論理演算子

# or演算子 - いずれかがTrueの場合、最初のTrue値を返す
result = False or True or False  # True

# and演算子 - すべてがTrueの場合、最後の値を返す
result = True and 10 and 'hello'  # 'hello'

数値リテラル

各進数の表現

# 2進数
binary_num = 0b1010  # 10

# 8進数
octal_num = 0o12  # 10

# 16進数
hex_num = 0xA  # 10

進数変換

# 10進数から他の進数へ
decimal_num = 42
binary_repr = bin(decimal_num)  # '0b101010'
octal_repr = oct(decimal_num)   # '0o52'
hex_repr = hex(decimal_num)     # '0x2a'

# 他の進数から10進数へ
decimal_from_binary = int('0b101010', 2)  # 42
decimal_from_octal = int('0o52', 8)       # 42
decimal_from_hex = int('0x2a', 16)        # 42

データ型

基本データ型

整数型 (int)

count = 100
large_number = 10**100  # Pythonでは任意精度の整数をサポート

浮動小数点数型 (float)

pi = 3.14159
scientific = 1.23e-4  # 0.000123

ブール型 (bool)

is_active = True
is_complete = False

複素数型 (complex)

complex_num = 3 + 4j
real_part = complex_num.real  # 3.0
imaginary_part = complex_num.imag  # 4.0

シーケンス型

文字列 (str)

# 文字列の定義
single_line = 'Hello'
multi_line = """複数行にわたる
文字列の例"""

# 文字列の連結
greeting = 'こんにちは' + '世界'

# 文字列の繰り返し
repeated = 'あ' * 5  # 'あああああ'

# 文字列のスライシング
text = 'Pythonプログラミング'
substring = text[0:6]  # 'Python'
char = text[7]  # 'プ'

リスト (list)

# リストの定義
fruits = ['りんご', 'ばなな', 'みかん']

# リストの連結
more_fruits = fruits + ['いちご', 'ぶどう']

# リストの繰り返し
repeated_list = [1, 2] * 3  # [1, 2, 1, 2, 1, 2]

# リストのスライシング
subset = more_fruits[1:4]  # ['ばなな', 'みかん', 'いちご']
element = more_fruits[2]  # 'みかん'

# 要素の追加
fruits.append('もも')
fruits.insert(1, 'かき')

タプル (tuple)

# タプルの定義
coordinates = (35.6895, 139.6917)  # 東京の緯度経度

# 単一要素のタプル
single_element = (42,)  # カンマが必要

# タプルは変更不可能(イミュータブル)
# coordinates[0] = 36.0  # エラーが発生

コレクション型

集合 (set)

# 集合の定義
unique_numbers = {1, 2, 3, 3, 4}  # {1, 2, 3, 4}

# 集合演算
set_a = {1, 2, 3, 4}
set_b = {3, 4, 5, 6}

# 和集合
union_set = set_a | set_b  # {1, 2, 3, 4, 5, 6}

# 積集合
intersection_set = set_a & set_b  # {3, 4}

# 差集合
difference_set = set_a - set_b  # {1, 2}

# 対称差集合
symmetric_diff = set_a ^ set_b  # {1, 2, 5, 6}

辞書 (dict)

# 辞書の定義
student = {
    '名前': '田中太郎',
    '年齢': 20,
    '学部': '工学部'
}

# 値へのアクセス
name = student['名前']  # '田中太郎'
age = student.get('年齢', 0)  # 20

# 要素の追加と更新
student['学年'] = 2
student['年齢'] = 21

# 要素の削除
del student['学部']

制御構造

条件分岐

score = 75

if score >= 90:
    grade = 'A'
elif score >= 80:
    grade = 'B'
elif score >= 70:
    grade = 'C'
else:
    grade = 'D'

print(f'評価: {grade}')

ループ構造

whileループ

count = 0
while count < 5:
    print(f'カウント: {count}')
    count += 1
else:
    print('ループが正常に完了しました')

forループ

# リストの反復処理
fruits = ['りんご', 'ばなな', 'みかん']
for fruit in fruits:
    print(f'果物: {fruit}')

# range()を使用した反復処理
for i in range(1, 6):
    print(f'数字: {i}')

# 辞書の反復処理
student = {'名前': '田中', '年齢': 20, '学部': '工学'}
for key, value in student.items():
    print(f'{key}: {value}')

ループ制御

# continueの使用例
for num in range(1, 11):
    if num % 2 == 0:
        continue  # 偶数をスキップ
    print(num)

# breakの使用例
for num in range(1, 11):
    if num > 5:
        break  # 5を超えたらループを終了
    print(num)

三項演算子

# 条件式の値による分岐
age = 20
status = '成人' if age >= 20 else '未成年'
print(f'ステータス: {status}')

モジュールとパッケージ

モジュールのインポート

# モジュール全体のインポート
import math
print(f'円周率: {math.pi}')

# モジュールの別名を付けてインポート
import numpy as np
array = np.array([1, 2, 3])

# モジュールから特定の関数やクラスをインポート
from datetime import datetime
now = datetime.now()

# モジュールからすべてをインポート(推奨されない)
from math import *
print(f'平方根: {sqrt(16)}')

パッケージの作成

パッケージは、__init__.pyファイルを含むディレクトリとして定義されます。

# mypackage/__init__.py
# このファイルは空でも良いが、パッケージの初期化コードを含めることができる

# mypackage/module1.py
def function1():
    return "モジュール1の関数"

# mypackage/module2.py
def function2():
    return "モジュール2の関数"

モジュールの特殊変数

# __name__ - モジュールの名前
if __name__ == '__main__':
    print('このスクリプトは直接実行されました')
else:
    print(f'このモジュールは {__name__} としてインポートされました')

# __file__ - モジュールのファイルパス
print(f'モジュールのパス: {__file__}')

# __package__ - モジュールが属するパッケージ
print(f'パッケージ名: {__package__}')

関数

関数の定義

def calculate_rectangle_area(width, height):
    """長方形の面積を計算する関数"""
    area = width * height
    return area

# 関数の呼び出し
result = calculate_rectangle_area(5, 8)
print(f'長方形の面積: {result}')

複数の戻り値

def calculate_statistics(numbers):
    """数値リストの基本統計量を計算"""
    total = sum(numbers)
    count = len(numbers)
    average = total / count if count > 0 else 0
    maximum = max(numbers) if numbers else 0
    minimum = min(numbers) if numbers else 0
    return total, average, maximum, minimum

# 戻り値の受け取り
data = [3, 7, 2, 9, 4]
total, avg, max_val, min_val = calculate_statistics(data)
print(f'合計: {total}, 平均: {avg}, 最大: {max_val}, 最小: {min_val}')

引数の種類

位置引数とキーワード引数

def create_profile(name, age, country='日本'):
    """ユーザープロファイルを作成"""
    return f'名前: {name}, 年齢: {age}, 国: {country}'

# 位置引数のみ
profile1 = create_profile('山田太郎', 30)

# キーワード引数を使用
profile2 = create_profile(name='佐藤花子', age=25, country='アメリカ')

# 混合使用(位置引数は先に)
profile3 = create_profile('鈴木一郎', country='イギリス', age=35)

可変長引数

def process_data(*args, **kwargs):
    """可変長の位置引数とキーワード引数を処理"""
    print(f'位置引数: {args}')
    print(f'キーワード引数: {kwargs}')
    
    for i, value in enumerate(args):
        print(f'位置引数{i+1}: {value}')
    
    for key, value in kwargs.items():
        print(f'{key}: {value}')

# 呼び出し例
process_data(1, 2, 3, name='テスト', active=True)

変数のスコープ

# グローバル変数
global_var = 'グローバル'

def scope_example():
    # ローカル変数
    local_var = 'ローカル'
    print(f'関数内 - グローバル: {global_var}')
    print(f'関数内 - ローカル: {local_var}')

def modify_global():
    # globalキーワードを使用してグローバル変数を変更
    global global_var
    global_var = '変更されたグローバル'

scope_example()
print(f'関数外 - グローバル: {global_var}')

modify_global()
print(f'変更後 - グローバル: {global_var}')

オブジェクト指向プログラミング

クラスの定義

class Person:
    """人物クラス"""
    
    # クラス変数
    species = 'ホモ・サピエンス'
    
    def __init__(self, name, age):
        """コンストラクタ"""
        # インスタンス変数
        self.name = name
        self.age = age
        self._private_data = '非公開データ'  # アンダースコア1つは慣習的な非公開
    
    def introduce(self):
        """自己紹介メソッド"""
        return f'私の名前は{self.name}で、{self.age}歳です。'
    
    def celebrate_birthday(self):
        """誕生日を祝うメソッド"""
        self.age += 1
        return f'{self.name}は{self.age}歳になりました!'
    
    @classmethod
    def get_species(cls):
        """クラスメソッド"""
        return f'種: {cls.species}'
    
    @staticmethod
    def is_adult(age):
        """スタティックメソッド"""
        return age >= 20

クラスの使用

# インスタンスの作成
person1 = Person('田中太郎', 25)
person2 = Person('佐藤花子', 18)

# インスタンスメソッドの呼び出し
print(person1.introduce())
print(person2.celebrate_birthday())

# クラスメソッドの呼び出し
print(Person.get_species())

# スタティックメソッドの呼び出し
print(f'田中さんは成人ですか: {Person.is_adult(person1.age)}')
print(f'佐藤さんは成人ですか: {Person.is_adult(person2.age)}')

# インスタンス変数へのアクセス
print(f'名前: {person1.name}, 年齢: {person1.age}')

継承

class Employee(Person):
    """従業員クラス - Personクラスを継承"""
    
    def __init__(self, name, age, employee_id, department):
        # 親クラスのコンストラクタを呼び出し
        super().__init__(name, age)
        
        # 従業員固有の属性
        self.employee_id = employee_id
        self.department = department
    
    def introduce(self):
        """親クラスのメソッドをオーバーライド"""
        base_intro = super().introduce()
        return f'{base_intro} 所属部署は{self.department}です。'
    
    def work(self):
        """仕事をするメソッド"""
        return f'{self.name}は{self.department}で働いています。'

# Employeeクラスのインスタンス作成
employee = Employee('鈴木一郎', 30, 'E12345', '開発部')
print(employee.introduce())
print(employee.work())
print(f'成人判定: {employee.is_adult(employee.age)}')

多重継承とメソッド解決順序

class A:
    def method(self):
        return "Aのメソッド"

class B(A):
    def method(self):
        return "Bのメソッド"

class C(A):
    def method(self):
        return "Cのメソッド"

class D(B, C):
    pass

# メソッド解決順序(MRO)の確認
print(D.__mro__)  # (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

d = D()
print(d.method())  # Bのメソッド

正規表現

基本的なパターンマッチング

import re

# テキストデータ
text = "連絡先: 電話 03-1234-5678, 携帯 090-9876-5432, メール info@example.com"

# 電話番号パターン
phone_pattern = r'\d{2,4}-\d{2,4}-\d{4}'
phone_numbers = re.findall(phone_pattern, text)
print(f'電話番号: {phone_numbers}')

# メールアドレスパターン
email_pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
email = re.search(email_pattern, text)
if email:
    print(f'メールアドレス: {email.group()}')

タグ間のテキスト抽出

html = '<div class="content"><h1>見出し</h1><p>これは段落のテキストです。</p></div>'

# タグ間のテキストを抽出
title_pattern = r'<h1>(.*?)</h1>'
title_match = re.search(title_pattern, html)
if title_match:
    print(f'見出し: {title_match.group(1)}')

paragraph_pattern = r'<p>(.*?)</p>'
paragraph_match = re.search(paragraph_pattern, html)
if paragraph_match:
    print(f'段落: {paragraph_match.group(1)}')

JSON処理

JSONの読み書き

import json

# PythonオブジェクトからJSON文字列へ(シリアライズ)
person = {
    "name": "田中太郎",
    "age": 30,
    "is_employee": True,
    "address": {
        "street": "中央区1-2-3",
        "city": "東京"
    },
    "hobbies": ["読書", "旅行", "写真"]
}

json_string = json.dumps(person, ensure_ascii=False, indent=2)
print("JSON文字列:")
print(json_string)

# JSON文字列からPythonオブジェクトへ(デシリアライズ)
json_data = '{"name": "佐藤花子", "age": 25, "is_employee": false}'
python_obj = json.loads(json_data)
print("\nPythonオブジェクト:")
print(f'名前: {python_obj["name"]}')
print(f'年齢: {python_obj["age"]}')
print(f'従業員: {python_obj["is_employee"]}')

JSONファイルの操作

# JSONファイルへの書き込み
with open('person.json', 'w', encoding='utf-8') as f:
    json.dump(person, f, ensure_ascii=False, indent=2)

# JSONファイルからの読み込み
with open('person.json', 'r', encoding='utf-8') as f:
    loaded_person = json.load(f)
    print(f'読み込んだデータ: {loaded_person["name"]}')

列挙型

列挙型の定義と使用

from enum import Enum, auto

class Weekday(Enum):
    MONDAY = auto()
    TUESDAY = auto()
    WEDNESDAY = auto()
    THURSDAY = auto()
    FRIDAY = auto()
    SATURDAY = auto()
    SUNDAY = auto()

class Status(Enum):
    ACTIVE = "有効"
    INACTIVE = "無効"
    PENDING = "保留"

# 列挙型の使用
print(f'月曜日: {Weekday.MONDAY}')
print(f'月曜日の値: {Weekday.MONDAY.value}')
print(f'月曜日の名前: {Weekday.MONDAY.name}')

# 値からの列挙メンバーの取得
status = Status("有効")
print(f'ステータス: {status}')

# 列挙型の反復処理
print("\nすべての曜日:")
for day in Weekday:
    print(f'{day.name}: {day.value}')

クロージャ

クロージャの基本

def make_multiplier(factor):
    """乗算関数を作成するクロージャ"""
    
    def multiplier(number):
        """外側の関数の変数を参照する内部関数"""
        return number * factor
    
    return multiplier

# クロージャの使用
double = make_multiplier(2)
triple = make_multiplier(3)

print(f'5の2倍: {double(5)}')  # 10
print(f'5の3倍: {triple(5)}')  # 15

# クロージャの環境変数へのアクセス
print(f'クロージャの環境変数: {double.__closure__[0].cell_contents}')  # 2

状態を保持するクロージャ

def make_counter():
    """カウンター関数を作成するクロージャ"""
    count = 0
    
    def counter():
        nonlocal count  # 外側のスコープの変数を変更するために必要
        count += 1
        return count
    
    return counter

# カウンターの作成と使用
counter1 = make_counter()
print(f'カウント1: {counter1()}')  # 1
print(f'カウント2: {counter1()}')  # 2
print(f'カウント3: {counter1()}')  # 3

# 別のカウンターを作成
counter2 = make_counter()
print(f'別カウンター1: {counter2()}')  # 1
print(f'別カウンター2: {counter2()}')  # 2

ラムダ式

匿名関数の基本

# 基本的なラムダ式
square = lambda x: x ** 2
print(f'5の二乗: {square(5)}')  # 25

# 複数の引数を持つラムダ式
add = lambda x, y: x + y
print(f'3 + 7 = {add(3, 7)}')  # 10

# 条件式を含むラムダ式
max_value = lambda x, y: x if x > y else y
print(f'10と20の最大値: {max_value(10, 20)}')  # 20

高階関数との組み合わせ

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# map()との組み合わせ
squared_numbers = list(map(lambda x: x ** 2, numbers))
print(f'二乗された数値: {squared_numbers}')

# filter()との組み合わせ
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(f'偶数のみ: {even_numbers}')

# sorted()との組み合わせ
people = [
    {'name': '田中', 'age': 30},
    {'name': '佐藤', 'age': 25},
    {'name': '鈴木', 'age': 35}
]
sorted_by_age = sorted(people, key=lambda person: person['age'])
print(f'年齢でソート: {[p["name"] for p in sorted_by_age]}')

デコレータ

デコレータの基本

def logger(func):
    """関数の実行をログに記録するデコレータ"""
    
    def wrapper(*args, **kwargs):
        print(f'関数 {func.__name__} を実行します')
        result = func(*args, **kwargs)
        print(f'関数 {func.__name__} の実行が完了しました')
        return result
    
    return wrapper

@logger
def greet(name):
    """挨拶をする関数"""
    return f'こんにちは、{name}さん!'

# デコレータ付き関数の呼び出し
message = greet('田中')
print(message)

引数を持つデコレータ

def repeat(times):
    """関数を指定回数繰り返し実行するデコレータ"""
    
    def decorator(func):
        
        def wrapper(*args, **kwargs):
            results = []
            for _ in range(times):
                results.append(func(*args, **kwargs))
            return results
        
        return wrapper
    
    return decorator

@repeat(times=3)
def say_hello(name):
    return f'こんにちは、{name}さん!'

# デコレータ付き関数の呼び出し
greetings = say_hello('佐藤')
for i, greeting in enumerate(greetings, 1):
    print(f'{i}回目: {greeting}')

例外処理

基本的な例外処理

def divide_numbers(a, b):
    """2つの数値を割り算する関数"""
    try:
        result = a / b
        return result
    except ZeroDivisionError:
        print('エラー: 0で割ることはできません')
        return None
    except TypeError:
        print('エラー: 数値を指定してください')
        return None
    finally:
        print('割り算処理を終了します')

# 正常なケース
print(f'10 ÷ 2 = {divide_numbers(10, 2)}')

# 0で割るケース
print(f'10 ÷ 0 = {divide_numbers(10, 0)}')

# 型が異なるケース
print(f'10 ÷ "2" = {divide_numbers(10, "2")}')

例外の発生と伝播

def validate_age(age):
    """年齢を検証する関数"""
    if age < 0:
        raise ValueError('年齢は0以上である必要があります')
    if age > 150:
        raise ValueError('年齢は150以下である必要があります')
    return True

def process_user_data(name, age):
    """ユーザーデータを処理する関数"""
    try:
        validate_age(age)
        return f'ユーザー名: {name}, 年齢: {age}'
    except ValueError as e:
        return f'エラー: {e}'
    except Exception as e:
        return f'予期せぬエラーが発生しました: {e}'

# 検証の実行
print(process_user_data('田中太郎', 30))  # 正常
print(process_user_data('佐藤花子', -5))  # 年齢が負の値
print(process_user_data('鈴木一郎', 200))  # 年齢が大きすぎる

カスタム例外

class InvalidEmailError(Exception):
    """無効なメールアドレスを表すカスタム例外"""
    pass

def validate_email(email):
    """メールアドレスを検証する関数"""
    if '@' not in email:
        raise InvalidEmailError('メールアドレスに@が含まれていません')
    if '.' not in email.split('@')[1]:
        raise InvalidEmailError('ドメイン名が無効です')
    return True

def register_user(email, password):
    """ユーザー登録を行う関数"""
    try:
        validate_email(email)
        return 'ユーザー登録が完了しました'
    except InvalidEmailError as e:
        return f'登録エラー: {e}'

# 登録の実行
print(register_user('user@example.com', 'password123'))  # 正常
print(register_user('invalid-email', 'password123'))  # @がない
print(register_user('user@invalid', 'password123'))  # ドメインが無効

コマンドライン操作

Pythonスクリプトの実行

# スクリプトファイルを直接実行
# python script.py

# モジュールとして実行
# python -m package.module

# 相対パスで実行
# python ./scripts/my_script.py

# 絶対パスで実行
# python C:/projects/my_script.py

コマンドライン引数の処理

import sys
import argparse

# sys.argvを使用した引数処理
def simple_args():
    print(f'スクリプト名: {sys.argv[0]}')
    if len(sys.argv) > 1:
        print(f'引数: {sys.argv[1:]}')
    else:
        print('引数が指定されていません')

# argparseを使用した高度な引数処理
def advanced_args():
    parser = argparse.ArgumentParser(description='サンプルプログラム')
    parser.add_argument('name', help='名前を指定')
    parser.add_argument('-a', '--age', type=int, help='年齢を指定', default=20)
    parser.add_argument('-v', '--verbose', action='store_true', help='詳細出力を有効化')
    
    args = parser.parse_args()
    
    if args.verbose:
        print(f'詳細モードが有効です')
    
    print(f'名前: {args.name}, 年齢: {args.age}')

# 以下はコマンドラインからの実行例
# python script.py 田中
# python script.py 田中 --age 30 --verbose

一般的な誤解

フォルダ名とパッケージ名の混同

Pythonでは、__init__.pyファイルを含まないフォルダは単なるディレクトリであり、パッケージとして認識されません。インポート時には、この違いを理解することが重要です。

トップレベルパッケージの指定

実行ファイルと同じ階層にあるディレクトリのみがトップレベルパッケージとして扱われます。実行ファイルの上位階層にあるディレクトリは自動的にはパッケージとして認識されません。

シーケンスのアンパックと連鎖代入

# シーケンスのアンパック
coordinates = (35.6895, 139.6917)  # 東京の緯度経度
latitude, longitude = coordinates
print(f'緯度: {latitude}, 経度: {longitude}')

# 連鎖代入
x = y = z = 0
print(f'x: {x}, y: {y}, z: {z}')

関数とメソッドの違い

関数は独立したコードブロックであり、メソッドはクラスに属する関数です。メソッドは通常、第一引数としてインスタンス(self)またはクラス(cls)を取ります。

可変長引数の定義

def flexible_function(*args, **kwargs):
    """任意の数の位置引数とキーワード引数を受け取る関数"""
    print(f'位置引数: {args}')
    print(f'キーワード引数: {kwargs}')

flexible_function(1, 2, 3, name='テスト', active=True)

ダックタイピング

ダックタイピングの概念

「もしもそれがアヒルのように歩き、アヒルのように鳴くのなら、それはアヒルに違いない」という考え方。オブジェクトの型よりも、そのオブジェクトが持つメソッドや属性に焦点を当てるプログラミングスタイルです。

ダックタイピングの実装例

class Duck:
    def quack(self):
        return 'ガーガー'
    
    def swim(self):
        return '泳いでいます'

class Person:
    def quack(self):
        return 'アヒルの真似をしています'
    
    def swim(self):
        return '泳いでいます'

def make_it_quack(duck_like):
    """アヒルのように鳴くオブジェクトを受け取り、鳴かせる関数"""
    print(duck_like.quack())

# 型は異なるが、同じメソッドを持つオブジェクト
duck = Duck()
person = Person()

# どちらもquackメソッドを持つため、同じ関数で処理できる
make_it_quack(duck)    # ガーガー
make_it_quack(person)  # アヒルの真似をしています

ユーティリティ関数

reduce関数

from functools import reduce

# リストの要素を累積的に処理
numbers = [1, 2, 3, 4, 5]

# 合計の計算
total = reduce(lambda x, y: x + y, numbers)
print(f'合計: {total}')  # 15

# 積の計算
product = reduce(lambda x, y: x * y, numbers)
print(f'積: {product}')  # 120

# 初期値を指定した場合
total_with_initial = reduce(lambda x, y: x + y, numbers, 10)
print(f'初期値10を加えた合計: {total_with_initial}')  # 25

filter関数

# 条件に合う要素を抽出
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 偶数のみを抽出
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(f'偶数: {even_numbers}')

# 5より大きい数値を抽出
greater_than_five = list(filter(lambda x: x > 5, numbers))
print(f'5より大きい数: {greater_than_five}')

# 文字列のリストから特定の長さの単語を抽出
words = ['Python', 'は', '楽しい', 'プログラミング', '言語', 'です']
long_words = list(filter(lambda word: len(word) > 3, words))
print(f'3文字より長い単語: {long_words}')

変数のIDと同一性

# 同じ値を持つ変数のID比較
a = 1000
b = 1000
print(f'a == b: {a == b}')  # True(値が等しい)
print(f'a is b: {a is b}')  # False(オブジェクトが異なる)

# 小さな整数(-5から256)はキャッシュされるため同じIDを持つ
c = 100
d = 100
print(f'c == d: {c == d}')  # True
print(f'c is d: {c is d}')  # True

# Noneは常に同じオブジェクト
e = None
f = None
print(f'e is f: {e is f}')  # True

部分適用(partial)

from functools import partial

def power(base, exponent):
    """べき乗を計算する関数"""
    return base ** exponent

# 関数の部分適用
square = partial(power, exponent=2)
cube = partial(power, exponent=3)

print(f'5の二乗: {square(5)}')  # 25
print(f'5の三乗: {cube(5)}')    # 125

# 複数の引数を部分適用
def greet(greeting, name, punctuation):
    return f'{greeting}, {name}{punctuation}'

excited_greet = partial(greet, punctuation='!')
formal_greet = partial(greet, punctuation='。')

print(excited_greet('こんにちは', '田中'))  # こんにちは, 田中!
print(formal_greet('はじめまして', '佐藤'))  # はじめまして, 佐藤。

特殊な機能

文字列フォーマット

name = '田中太郎'
age = 30
score = 85.678

# %演算子を使用したフォーマット(古い方法)
formatted1 = '名前: %s, 年齢: %d, スコア: %.2f' % (name, age, score)
print(formatted1)

# str.format()を使用したフォーマット
formatted2 = '名前: {}, 年齢: {}, スコア: {:.2f}'.format(name, age, score)
print(formatted2)

# f-stringを使用したフォーマット(推奨)
formatted3 = f'名前: {name}, 年齢: {age}, スコア: {score:.2f}'
print(formatted3)

文字列リテラルのプレフィックス

# f-string: 式を埋め込める文字列
x = 10
y = 20
f_string = f'x + y = {x + y}'
print(f_string)

# b-string: バイト列
byte_string = b'Hello'
print(f'バイト列: {byte_string}, 型: {type(byte_string)}')

# u-string: Unicode文字列(Python 3ではデフォルト)
unicode_string = u'こんにちは'
print(f'Unicode文字列: {unicode_string}')

# r-string: 生文字列(エスケープシーケンスを無視)
path = r'C:\Users\name\Documents'
print(f'生文字列: {path}')  # バックスラッシュがエスケープされない

タグ: Python プログラミング データ型 オブジェクト指向 関数

6月6日 18:39 投稿