メインコンテンツまでスキップ

asdfでPythonをバージョン管理

· 約8分
Mikyan
白い柴犬

Pythonのバージョン管理にasdfを使用することで、複数のPythonバージョンを簡単に管理できるようになりました。

asdfはPythonだけでなく、Node.js、Javaなど複数のランタイムを統一的に管理できる非常に便利なツールです。

以下の手順はasdf v0.18.0に基づいて説明します。

asdfとは

asdfは複数のプログラミング言語のランタイムバージョンを管理するためのツールです。pyenv、nvm、rbenvなどの個別のバージョン管理ツールを統一的に置き換えることができます。

主な利点

  • 複数の言語を一つのツールで管理
  • プロジェクトごとのバージョン設定
  • 豊富なプラグインエコシステム

asdfとvenvの違い

asdf: Pythonインタープリター自体のバージョン管理

  • Python 3.11.7、3.12.1など異なるPythonバージョンを切り替え

venv: パッケージ(ライブラリ)の分離管理

  • 同じPythonバージョンでもプロジェクトごとに異なるパッケージセットを使用
  • 依存関係の競合を防ぐ

両方を組み合わせることで、Pythonバージョンとパッケージの両方を適切に管理できます。

asdfとvenvの違い

asdf: Pythonインタープリター自体のバージョン管理

  • Python 3.11.7、3.12.1など異なるPythonバージョンを切り替え

venv: パッケージ(ライブラリ)の分離管理

  • 同じPythonバージョンでもプロジェクトごとに異なるパッケージセットを使用
  • 依存関係の競合を防ぐ

両方を組み合わせることで、Pythonバージョンとパッケージの両方を適切に管理できます。

asdfのインストール

macOSの場合

公式ガイドに従ってインストールします。

brew install asdf

zshの設定

~/.zshrcファイルに以下を追加:

# asdfの設定
export PATH="${ASDF_DATA_DIR:-$HOME/.asdf}/shims:$PATH"
export ASDF_DATA_DIR="$HOME/.asdf/data"

補完機能の設定

# 補完ディレクトリの作成
mkdir -p "${ASDF_DATA_DIR:-$HOME/.asdf}/completions"

# zsh補完ファイルの生成
asdf completion zsh > "${ASDF_DATA_DIR:-$HOME/.asdf}/completions/_asdf"

再度~/.zshrcに以下を追加:

# asdf補完の有効化
fpath=(${ASDF_DATA_DIR:-$HOME/.asdf}/completions $fpath)
autoload -Uz compinit && compinit

設定を反映:

source ~/.zshrc

Pythonプラグインのインストールと設定

プラグインの追加

# Pythonプラグインを追加
asdf plugin add python

# インストール済みプラグインの確認
asdf plugin list

利用可能なPythonバージョンの確認

# インストール可能なPythonバージョンを表示
asdf list all python

Pythonのインストール

# 最新版をインストール
asdf install python latest

# 特定バージョンをインストール(例)
asdf install python 3.11.7

# インストール済みバージョンの確認
asdf list python

バージョンの設定

asdf v0.18.0ではasdf setコマンドを使用します:

# グローバル設定(HOMEフォルダ以下全体で使用)
asdf set --home python latest

# 現在の設定確認
asdf current python

出力例:

Name            Version         Source
python 3.13.5 /Users/username/.tool-versions
# Pythonコマンドの場所確認
which python3

出力例:

/Users/username/.asdf/data/shims/python3

プロジェクト固有の設定

プロジェクトディレクトリで特定のPythonバージョンを使用する場合:

# プロジェクトディレクトリに移動
cd /path/to/your/project

# プロジェクト用のPythonバージョンを設定
asdf set python 3.11.7

# .tool-versionsファイルが作成される
cat .tool-versions

出力例:

python 3.11.7

このファイルがあるディレクトリとその配下では、指定されたPythonバージョンが自動的に使用されます。

よく使うコマンド一覧

# 現在使用中のバージョン確認
asdf current

# 特定言語の現在バージョン
asdf current python

# インストール済みバージョン一覧
asdf list python

# 利用可能バージョン一覧(最新10件)
asdf list all python | tail -10

# プラグインの更新
asdf plugin update python


# 古いバージョンの削除
asdf uninstall python 3.10.0

トラブルシューティング

Pythonが見つからない場合

# shimの再作成
asdf reshim python

# パスの確認
echo $PATH | grep asdf

権限エラーが発生する場合

# asdfディレクトリの権限確認
ls -la ~/.asdf/

# 必要に応じて権限修正
chmod -R 755 ~/.asdf/

設定が反映されない場合

# .zshrcの再読み込み
source ~/.zshrc

# 現在のシェル設定確認
echo $ASDF_DATA_DIR
echo $PATH | grep asdf

実際の使用例

新しいプロジェクトでの設定

# プロジェクトディレクトリを作成
mkdir my-python-project
cd my-python-project

# プロジェクト用のPythonバージョンを指定
asdf set --local python 3.11.7

# 仮想環境の作成
python -m venv venv
source venv/bin/activate

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

チームでの.tool-versionsファイル共有

# .tool-versionsファイルをGitで共有
echo "python 3.11.7" > .tool-versions
echo "nodejs 18.19.0" >> .tool-versions

# チームメンバーは以下でバージョンをインストール
asdf install

設定が反映されない場合

# .zshrcの再読み込み
source ~/.zshrc

# 現在のシェル設定確認
echo $ASDF_DATA_DIR
echo $PATH | grep asdf

実際の使用例

新しいプロジェクトでの設定

# プロジェクトディレクトリを作成
mkdir my-python-project
cd my-python-project

# 1. asdfでPythonバージョンを指定(インタープリター管理)
asdf set python 3.11.7

# 2. venvで仮想環境を作成(パッケージ管理)
python -m venv venv
source venv/bin/activate

# 3. プロジェクト固有のパッケージをインストール
pip install requests flask

# 結果:Python 3.11.7 + 独立したパッケージ環境

なぜvenvも必要なのか?

問題:venvを使わない場合

# プロジェクトA
cd project-a
asdf set python 3.11.7
pip install django==4.2.0 requests==2.28.0

# プロジェクトB(同じPython 3.11.7)
cd ../project-b
pip install flask==2.3.0 requests==2.31.0 # ← requests 2.28.0が上書きされる

# プロジェクトAに戻ると...
cd ../project-a
# django が requests 2.31.0 で動作しない可能性!

解決:asdf + venv

# プロジェクトA: Python 3.11.7 + 独立した環境
project-a/ → django 4.2.0 + requests 2.28.0

# プロジェクトB: Python 3.11.7 + 独立した環境
project-b/ → flask 2.3.0 + requests 2.31.0

チームでの.tool-versionsファイル共有

# .tool-versionsファイルをGitで共有
echo "python 3.11.7" > .tool-versions
echo "nodejs 18.19.0" >> .tool-versions

# チームメンバーは以下でバージョンをインストール
asdf install

まとめ

asdfを使用することで以下のメリットが得られます:

  • 統一的な管理: 複数の言語のバージョン管理を一つのツールで実現
  • プロジェクト固有設定: .tool-versionsファイルでプロジェクトごとの環境を管理
  • 簡単な切り替え: コマンド一つでバージョン切り替えが可能
  • チーム開発: .tool-versionsファイルでチーム全体の環境を統一

Python開発での環境構築が大幅に簡素化されるため、特に複数のプロジェクトを扱う開発者にはぜひ活用していただきたいツールです。

ECR

· 約2分
Mikyan
白い柴犬

Amazon ECR は、フルマネージドのコンテナイメージレジストリサービスです。Docker ImageをPrivateで保存、管理できます。

アクセス制御:各リポジトリに対してリソースベースのIAMポリシーを設定し、プッシュ・プルの許可を細かくコントロールでいます。 保存:AWS S3上に保存されます。 ライフサイクル管理:自動削除ルールを定義可能。 脆弱性スキャン:プッシュ時に自動的に脆弱性スキャンを実行し、結果を取得できます。

ワークフロー

リポジトリの作成

aws ecr create-repository \
--repository-name my-org \
--region ap-northeast-1

認証&Dockerログイン

aws ecr get-login-password \
--region ap-northeast-1 \
--username AWS \
--password-stdin <account-id>.dkr.erc.ap-northeast-1.amazonaws.com

イメージのビルド、タグ付け、プッシュ

docker build -t myapp:v1 .
docker tag my-app:v1 \
<account-id>.dkr.erc.ap-northeast-1.amazonaws.com/my-app:v1
docker push <account-id>.dkr.erc.ap-northeast-1.amazonaws.com/my-app:v1

イメージのプル

docker pull <account-id>.dkr.erc.ap-northeast-1.amazonaws.com/my-app:v1

kubectlによるEKSにデプロイ

KubernetesマニフェストにそのデプロイしたイメージのURLを設定し、下記コマンドで適用したら簡単にEKSにデプロイできます。

# deploy
kubectl apply -f deployment.yaml

# status confirm
kubectl get pods -l app=my-app

Python FAISSでベクトル検索

· 約6分
Mikyan
白い柴犬
  • FAISSを使って高次元ベクトルの中から、クエリベクトルに最も「似ている」ベクトルを高速に検索できる
  • RAGにおいて、FAISSを使って、関連文書を検出ことができる

詳細

高次元の課題 (Curse of Dimensionality): 次元数が増えると(例えば、数千次元のベクトル)、ベクトル間の距離計算は非常に高コストになり、従来のデータベース手法では効率的に検索できなくなります。FAISSは、この高次元空間での非効率性を克服するための様々な工夫(近似検索アルゴリズム)を提供します。

類似性検索のニーズ: 「意味的に似ているものを探す」「内容が近い画像を見つける」「類似する推薦アイテムを提案する」といった、人間の直感的な「似ている」を数値データから見つけ出すニーズが、AI/MLの発展とともに爆発的に増加しました。FAISSは、このニーズに応えるための高速なソリューションです。

スケーラビリティ: データ量が膨大になっても、秒単位やミリ秒単位で検索結果を返すことが求められます。FAISSは、インデックス構造の工夫や並列処理、GPU活用などにより、このスケーラビリティを実現します。

FAISSは、基本的にメモリ内で高速な類似検索を行いますが、大規模なデータセットに対応するために、メモリ管理やストレージとの連携に関する様々な機能や戦略を持っています。

利用

FAISSのAPIは、大きく分けてインデックスの作成と検索の2つのフェーズで構成されます。

  1. インデックスの作成(Add / Train) まず、検索対象となるベクトルデータをFAISSのインデックス構造に「追加」します。
import faiss
import numpy as np

# 1. ベクトルデータの準備
# 例として、128次元のベクトルが1000個あると仮定
dimension = 128
num_vectors = 1000
data_vectors = np.random.rand(num_vectors, dimension).astype('float32')

# 2. インデックスの選択と初期化
# 最もシンプルなインデックス: IndexFlatL2
# L2 はユークリッド距離を意味し、最も厳密な(近似ではない)検索を行う
index = faiss.IndexFlatL2(dimension)

print(f"インデックスが空か?: {index.is_trained}") # IndexFlatL2は訓練不要なのでTrue
print(f"インデックスのベクトルの数: {index.ntotal}") # 初期状態では0

# 3. インデックスへのベクトルの追加
index.add(data_vectors)

print(f"インデックスのベクトルの数: {index.ntotal}") # 1000

faiss.IndexFlatL2(dimension): これは最も基本的なインデックスで、全てのベクトルをそのままメモリに格納し、クエリが来たら総当たりで距離を計算します(ブルートフォース検索)。L2 はユークリッド距離(二点間の直線距離)を意味します。これは厳密な最近傍探索を行いますが、データ量が増えると非常に遅くなります。

index.is_trained: インデックスによっては、データを追加する前に「訓練(train)」が必要なものがあります(例: IndexIVFFlat, IndexPQ)。これは、ベクトル空間を効率的に分割するためのクラスタリングなどを行います。IndexFlatL2 は訓練不要なので最初から True です。

index.add(vectors): 訓練が終わった(または不要な)インデックスに、実際にベクトルデータを追加します。

# 1. クエリベクトルの準備
# 例として、1つのクエリベクトルを準備
query_vector = np.random.rand(1, dimension).astype('float32') # 1つのクエリは (1, dimension) 形状

# 2. 検索の実行
# k=5: 最も近い5つのベクトルを検索
k = 5
distances, indices = index.search(query_vector, k)

print(f"検索されたベクトルのインデックス (元の data_vectors での): {indices}")
print(f"検索されたベクトルの距離: {distances}")

index.search(query_vectors, k):

query_vectors: 検索したいベクトル。複数個のクエリを一度に渡すことも可能です(例: (num_queries, dimension) のNumPy配列)。

k: 取得したい最近傍ベクトルの数。

戻り値:

distances: 検索された k 個のベクトルとクエリベクトルとの間の距離。

indices: 検索された k 個のベクトルが、インデックス追加時に持っていた元のインデックス(add したときの順番)を示します。

3. インデックスの保存とロード

作成したインデックスはファイルに保存し、後でロードして再利用できます。

# インデックスの保存
faiss.write_index(index, "my_faiss_index.bin")
print("インデックスを 'my_faiss_index.bin' に保存しました。")

# インデックスのロード
loaded_index = faiss.read_index("my_faiss_index.bin")
print(f"ロードされたインデックスのベクトルの数: {loaded_index.ntotal}")

Common Used Javascript Patterns for Screening Questions

· 約3分
Mikyan
白い柴犬

短時間で、LeetCode問題を解決するスクリーニング面接はあります。 そのスクリーニング面接で使われている書き方は効率を重視し、代わりに、readability をTradeoffしても。 プロジェクトコーディングと全く別物で、よく使っているパターンをここでまとめます。

計算

Javascript において、除算は小数ついているため、整除ははMath.truncで、小数部分を切り捨てましょう。 また、Math.floor()は正数を正しく処理できますが、負数の処理は数学上の整除定義と異なるので、使わないでください。

Math.trunc(3 / 2)  // → 1
Math.trunc(-3 / 2) // → -1

配列

配列の作成

const a = [];            // empty
const b = [1,2,3]; // with elements
const c = new Array(n); // [ <n × empty> ]
const d = Array(n).fill(0); // [0,0,…,0]
const e = Array.from({ length: n }, (_, i) => i*2);
const f = [...someOtherArray]; // shallow copy

注意しなければないこと: 以下はReference作成で、おかしい挙動になります。

const d = Array(n).fill([]);

その他の配列の操作:


// find the index
["hello", "world"].indexOf("world")

// sort, O(nlgn)
arr.sort((a, b) => a - b);

// reverse in place
arr.reverse()

// non destructive subarray
arr.slice(start, end)


// unshift
// output: 5 length of new array
// array1 to be: [10, 11, 1, 2, 3]
const array1 = [1, 2, 3];
array1.unshift(10,11)

使ってはいけない操作:

shift

// shift
// remove the first element and returns that removed element
// However the time complexity is O(n), so
const array1 = [1,2,3];
while (firstElement = array1.shift()) {
// ❌
}

代わりに headを使って、先頭の位置だけメモし、Queueの操作を実現しましょう。

const array1 = [1,2,3];
const head = 0;
while (firstElement = array1[head++]) {
// ✅
}

文字列

charを取得

'abcde'.charAt(2); // 'c'

React Error Boundary

· 約2分
Mikyan
白い柴犬

Error boundaries are React components that catch Javascript errors, in their child component tree, log those errors, and display a fallback UI instead of crashing the entire app. Without them, an error in one component can bring down your whole application.

The word "boundary" emphasizes that these components create a containment zone for errors:

Error Boundaries are specifically for:

React component lifecycle errors Render method errors Constructor errors in child components

How error boundaries works

How React Rendering works

React rendering happens in two phases:

// 1. Render Phase - React calls your components
function MyComponent() {
// If error happens here...
return <div>{undefined.toString()}</div>; // 💥 Crash!
}

// 2. Commit Phase - React updates the DOM
// (If render phase succeeds)

What Makes Component Errors Special

  1. They Happen Inside React's Control
// React controls this execution:
function BrokenComponent() {
const user = null;
return <h1>{user.name}</h1>; // React catches this error
}

// React DOESN'T control this:
<button onClick={() => {
throw new Error(); // Happens outside React's render cycle
}}>
  1. Synchronous Execution
// Error boundaries can catch this (synchronous):
function Component() {
throw new Error('Sync error');
return <div />;
}

// But NOT this (asynchronous):
function Component() {
setTimeout(() => {
throw new Error('Async error'); // Outside React's try/catch
}, 1000);
return <div />;
}

Why Error Boundaries work

Usage

✅ Use Error Boundaries For

  1. Unexpected Runtime Errors
  2. Third-Party Component Errors
  3. Dynamic/Complex Components

❌ DON'T Use Error Boundaries For

  1. Expected Errors (Handle These Explicitly)
  2. Event Handler Errors
  3. Async Errors

Best Practices

  1. Strategic Placement
function App() {
return (
<ErrorBoundary> {/* App-level boundary */}
<Header />
<ErrorBoundary> {/* Feature-level boundary */}
<RiskyFeature />
</ErrorBoundary>
<Footer />
</ErrorBoundary>
);
}
  1. Granular for Isolation
<div>
{widgets.map(widget => (
<ErrorBoundary key={widget.id}> {/* Each widget isolated */}
<Widget {...widget} />
</ErrorBoundary>
))}
</div>
  1. Not for Control Flow
// ❌ Bad: Using error boundary for expected cases
<ErrorBoundary fallback={<LoginForm />}>
<AuthenticatedApp />
</ErrorBoundary>

// ✅ Good: Explicit control flow
{isAuthenticated ? <AuthenticatedApp /> : <LoginForm />}

React 19 Ref

· 約3分
Mikyan
白い柴犬

In React 19, ref can directly be passed to a component as a property, and forwardRef become unrecommanded.

About ref

In React, a ref (reference) let you operate lower-level imperative API on the following elements:

  • DOM nodes
  • Class component instances

Usually it is created with useRef hook.

function Chat() {
const endRef = useRef();
useEffect(() => {
endRef.current.scrollIntoView({ behavior: 'smooth' });
}, [messages]);
return (
<div className="chat-window">
{messages.map(m => <Message key={m.id} />)}
<div ref={endRef} />
</div>
);
}

Sometimes we need to pass ref down to point to one component of a child component, below are suitable situations:

  • When you build a HOC component
  • When you wrapping a core component with customized design (like wrapping a material UI Input)

Note that usually it is not a good practice, since it increase the complicity and voilate the capsluating philosoph, we should be careful about the usecases.

Improved ref API in React.19

Before React 19, it is not allowed to pass ref as a property, Instead, forwardRef is needed:

import React, { forwardRef, useRef, useImperativeHandle } from 'react';

const FancyInput = forwardRef(function FancyInput(_, ref) {
const inputRef = useRef();

useImperativeHandle(ref, () => ({
focus: () => inputRef.current?.focus(),
clear: () => { if (inputRef.current) inputRef.current.value = ''; }
}), []);

return <input ref={inputRef} className="border rounded p-2" />;
});

export default FancyInput;

// Parent.jsx
import React, { useRef } from 'react';
import FancyInput from './FancyInput';

function Parent() {
const fancyRef = useRef();

return (
<>
<FancyInput ref={fancyRef} />
<button onClick={() => fancyRef.current.focus()}>Focus</button>
<button onClick={() => fancyRef.current.clear()}>Clear</button>
</>
);
}

Note in the example, useImperativeHandle is used to defines the customer handler of ref. By declaring useImperativeHandle in the component, we can:

  • rewrite the ref handler behavior
  • safely limit the handlers of the ref

By using useImperativeHandle, the original ref donot directly pass to the input, instead in the component we define a new ref, to let the ref operates indirectly.

However, from React 19, forwardRef is not recommended, and ref can be passed directly, which is more concise and have better readability:

import React, { forwardRef, useRef, useImperativeHandle } from 'react';

function FancyInput({ ref }) {
const inputRef = useRef();

useImperativeHandle(ref, () => ({
focus: () => inputRef.current?.focus(),
clear: () => { if (inputRef.current) inputRef.current.value = ''; }
}), []);

return <input ref={inputRef} className="border rounded p-2" />;
});

export default FancyInput;

// Parent.jsx
import React, { useRef } from 'react';
import FancyInput from './FancyInput';

function Parent() {
const fancyRef = useRef();

return (
<>
<FancyInput ref={fancyRef} />
<button onClick={() => fancyRef.current.focus()}>Focus</button>
<button onClick={() => fancyRef.current.clear()}>Clear</button>
</>
);
}

Java Optional Best Practices

· 約6分
Mikyan
白い柴犬

JavaのOptionalは、値が存在する場合も存在しない場合もあるコンテナオブジェクトです。これにより、nullチェックの手間を減らし、メソッドの戻り値として「値があるかどうか」を明示的に伝えることができます。Optionalは以下のような利点があります:

明確な意図: メソッドが値を返さない可能性があることを示す。 安全な操作: 明示的なnullチェックを回避し、NullPointerExceptionのリスクを減少させる。 関数型スタイル: map, filter, flatMap などを活用したチェーン処理が可能。

Optionalの作成

Optionalは主に2つのファクトリーメソッドを使って生成します。

  • Optional.of(T value):
    • 値が必ず非nullであることを期待します。
    • nullを渡すと、NullPointerExceptionが発生します。
  • Optional.ofNullable(T value):
    • 値がnullの場合は空のOptional(Optional.empty())を返し、非nullの場合は値を保持します。

作成例:

// Method that processes an input string and returns an Optional.
public static Optional<String> processValue(String input) {
// Return empty if input is null or blank
if (input == null || input.trim().isEmpty()) {
return Optional.empty();
}
// Otherwise, return a trimmed value wrapped in an Optional
return Optional.of(input.trim());
}

Optionalの利用方法

Optionalの利用は主に以下のユースケースに分類されます。

  1. 値の存在チェック

    • isPresent() / isEmpty():
      • 値が存在するかどうかを確認する。
      • 例: if (optional.isPresent()) { ... }
  2. 値の取得

    • get():
      • 値が存在する場合に返すが、存在しない場合はNoSuchElementExceptionをスローします。
      • 注意: 直接get()を使うのはリスクがあるため、他のメソッドと組み合わせることが望ましい。
    • orElse(defaultValue):
      • 値が存在しない場合にデフォルト値を返します。
    • orElseThrow(exceptionSupplier):
      • Optionalが空の場合に、指定した例外をスローします。
  3. 値の処理

    • ifPresent(Consumer):
      • 値が存在する場合に、Consumer(値を受け取って何らかの処理を行うラムダ式)を実行します。
    • ifPresentOrElse(Consumer, Runnable):
      • 値が存在する場合はConsumerを、存在しない場合はRunnable(引数を取らない処理)を実行します。
  4. Optionalのチェーン処理

    • map(Function):
      • 値が存在する場合に、Functionを適用し結果を新しいOptionalとして返します。
    • filter(Predicate):
      • 値が条件を満たすかどうかをチェックし、満たさない場合は空のOptionalを返します。
    • flatMap(Function):
      • ネストされたOptionalの解除に利用します。
    • or(Supplier):
      • Optionalが空の場合に、新たなOptionalを返すために利用します。

利用例:

String value1 = "  Hello, World!  ";
Optional<String> opt1 = processValue(value1);

// 存在チェック
if (opt1.isPresent()) {
System.out.println("Value exists!");
} else {
System.out.println("Value is empty.");
}

// 値の取得
try {
// 値がなければ例外がスローされる
String result = opt1.orElseThrow(() -> new IllegalStateException("Value is empty"));
System.out.println("Result: " + result);
} catch (IllegalStateException ex) {
System.err.println(ex.getMessage());
}

// デフォルト値を利用
String defaultResult = opt1.orElse("Default Value");
System.out.println("Default Result: " + defaultResult);

// 値の処理
opt1.ifPresent(val -> System.out.println("Processed value1: " + val));

// ifPresentOrElseを使用して、存在する場合は処理し、存在しない場合は別の処理を実行
opt1.ifPresentOrElse(
val -> System.out.println("Processed value1: " + val),
() -> System.out.println("Value is empty")
);

// チェーン処理:変換とフィルタ
Optional<Integer> lengthOpt = opt1
.map(String::toUpperCase) // 値を大文字に変換
.filter(val -> val.length() > 10) // 長さが10より大きいかフィルター
.map(String::length); // 文字列の長さを取得

lengthOpt.ifPresent(len -> System.out.println("Length of processed value: " + len));

// orを使用して、Optionalが空の場合に代替値を提供
Optional<String> opt2 = opt1.or(() -> Optional.of("Default Greeting"));
System.out.println("Result from opt2: " + opt2.get());

Optionalのベストプラクティス

  1. 戻り値としての利用:

    • Optionalはメソッドの戻り値に利用し、値が存在しない可能性を明示する。
  2. メソッド引数としては使用しない:

    • Optionalを引数にすると、呼び出し側に無駄なラッピングを強いるため、シンプルなnullチェックやオーバーロード、あるいは別のパラメータ設計を検討する。
  3. 直接get()の使用を避ける:

    • 値の取得はorElse, orElseThrow, ifPresentなどのメソッドを利用して、安全に扱う。
  4. 不必要なオブジェクト生成を避ける:

    • チェーン操作を利用して、コードをシンプルに保つ。

Python Development Setup, pyenv, uv

· 約2分
Mikyan
白い柴犬

This article introduce how to setup python development environment for Web development.

For data science / machine learning development environment, you might prefer other approaches, like anaconda.

Details

Install uv

US is the modern solution and handles both Python versions AND package management. It's like having nvm + npm in one tool.

curl -LsSf https://astral.sh/uv/install.sh | sh

source $HOME/.local/bin/env

Use uv

# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install and use Python
uv python install 3.12
uv python pin 3.12 # Sets Python version for project

Use uv to initialize the project

cd my-project

uv init --python 3.12

Then the following files are generated:

tree
├── main.py
├── pyproject.toml
└── README.md

pyproject.toml is just like package.json

Initialize venv:

% uv venv
Using CPython 3.12.11
Creating virtual environment at: .venv
Activate with: source .venv/bin/activate
% source .venv/bin/activate

You can use venv in this project now.

# install deps
# it automatically use venv
uv sync

# add new package
uv add fastapi sqlalchemy alembic

Check the pyproject.toml file's

If want to init a fastapi project, using fastapi's template here might be a better choice.

git clone [email protected]:fastapi/full-stack-fastapi-template.git my-full-stack
cd my-full-stack
git remote set-url origin [email protected]:octocat/my-full-stack.git
git push -u origin master