Ei vielä käännetty
Tätä sivua ei ole vielä käännetty suomeksi, joten se näytetään englanniksi. Auta kääntämään
Pkgutil Module¶
The pkgutil module provides utilities for working with packages and module search paths.
Complexity Reference¶
| Operation | Time | Space | Notes |
|---|---|---|---|
iter_modules(path) |
O(n) | O(1) per item | n = modules in path |
walk_packages() |
O(n) | O(n) | n = all subpackages/modules (tracks seen paths) |
find_spec(name) |
O(1) avg, O(p) worst | O(1) | p = sys.meta_path length (import hooks) |
get_data(name) |
O(n) | O(n) | n = file size (plus import overhead) |
extend_path() |
O(p + k) | O(p + k) | p = search path entries, k = .pkg entries |
Common Operations¶
Finding Modules in a Path¶
import pkgutil
# O(n) where n = modules in directory
for importer, modname, ispkg in pkgutil.iter_modules(['./plugins']):
print(f"{'Package' if ispkg else 'Module'}: {modname}")
# ispkg = True if subpackage, False if module
# importer = loader for the module
Walking Package Tree¶
import pkgutil
import sys
# O(n) where n = all subpackages/modules recursively
for importer, modname, ispkg in pkgutil.walk_packages(
path=['./mypackage'],
prefix='mypackage.'
):
print(modname)
# Example output:
# mypackage.module1
# mypackage.module2
# mypackage.subpkg
# mypackage.subpkg.module3
Getting Package Data Files¶
import pkgutil
# O(n) where n = file size
data = pkgutil.get_data('mypackage', 'data.txt')
# Returns bytes
# Can also work with nested paths - O(n)
data = pkgutil.get_data('mypackage.subpackage', 'resource.json')
# Example: loading JSON data
import json
try:
raw_data = pkgutil.get_data('myapp', 'config.json')
config = json.loads(raw_data) # O(n) to parse
except (ImportError, FileNotFoundError):
config = {}
Common Use Cases¶
Discovering Plugins¶
import pkgutil
import importlib
def load_plugins(plugin_package):
"""Load all modules in plugin package - O(n*m)"""
plugins = {}
# O(n) to iterate modules
for importer, modname, ispkg in pkgutil.iter_modules(
plugin_package.__path__
):
if not ispkg: # Skip sub-packages
# O(m) to import each module
full_name = f"{plugin_package.__name__}.{modname}"
module = importlib.import_module(full_name)
# Assume each plugin has a 'Plugin' class
if hasattr(module, 'Plugin'):
plugins[modname] = module.Plugin()
return plugins
# Usage - O(n*m) where n = plugins, m = avg module size
import plugins as plugin_package
loaded = load_plugins(plugin_package)
Checking Package Contents¶
import pkgutil
def get_submodules(package_name):
"""Get list of submodules - O(n)"""
import importlib
package = importlib.import_module(package_name)
submodules = []
# O(n) where n = direct submodules
for importer, modname, ispkg in pkgutil.iter_modules(
package.__path__
):
submodules.append(modname)
return submodules
# Usage
modules = get_submodules('email')
print(modules) # ['mime', 'parser', 'generator', ...]
Extending Path for Namespace Packages¶
import pkgutil
import sys
# Extend path for namespace packages - O(n)
extended = pkgutil.extend_path(
__path__, # Current package path
__name__ # Current package name
)
# Allows finding modules in multiple locations
# Useful for plugin directories
Gathering Metadata¶
import pkgutil
import importlib
def analyze_package(package_name):
"""Analyze package structure - O(n)"""
import importlib
package = importlib.import_module(package_name)
analysis = {
'modules': [],
'subpackages': [],
'module_count': 0,
'has_init': hasattr(package, '__file__')
}
# O(n) to iterate
for importer, modname, ispkg in pkgutil.iter_modules(
package.__path__
):
if ispkg:
analysis['subpackages'].append(modname)
else:
analysis['modules'].append(modname)
analysis['module_count'] += 1
return analysis
# Usage
info = analyze_package('collections')
print(f"Modules: {info['module_count']}")
print(f"Subpackages: {info['subpackages']}")
Performance Tips¶
Cache pkgutil Results¶
import pkgutil
import importlib
class PackageCache:
def __init__(self):
self._cache = {}
def get_modules(self, package_name):
"""Get modules with caching - O(1) after first call"""
if package_name not in self._cache:
# O(n) first time
package = importlib.import_module(package_name)
modules = []
for _, modname, _ in pkgutil.iter_modules(package.__path__):
modules.append(modname)
self._cache[package_name] = modules
# O(1) subsequent calls
return self._cache[package_name]
# Usage
cache = PackageCache()
modules = cache.get_modules('email') # O(n)
modules = cache.get_modules('email') # O(1)
Lazy Load Heavy Modules¶
import pkgutil
import importlib
def lazy_load_plugins(plugin_package):
"""Return loader dict instead of loading - O(n)"""
import importlib
package = importlib.import_module(plugin_package)
loaders = {}
# O(n) to setup loaders, O(1) per load
for importer, modname, ispkg in pkgutil.iter_modules(
package.__path__
):
full_name = f"{plugin_package}.{modname}"
# Store loader, don't import yet
loaders[modname] = lambda fn=full_name: importlib.import_module(fn)
return loaders
# Usage - O(n) setup, O(1) per lazy load
plugins = lazy_load_plugins('myapp.plugins')
# Load only when needed - O(m) for each plugin
plugin1 = plugins['plugin1']() # Loads on demand
plugin2 = plugins['plugin2']() # Loads on demand
Limit Walk Depth for Large Trees¶
import pkgutil
import importlib
def walk_packages_limited(package_name, max_depth=2):
"""Walk package tree with depth limit - O(n)"""
package = importlib.import_module(package_name)
def walk(path, prefix, depth):
if depth > max_depth:
return
# O(k) at each depth
for _, modname, ispkg in pkgutil.iter_modules(path):
yield f"{prefix}.{modname}"
if ispkg:
subpackage = importlib.import_module(
f"{prefix}.{modname}"
)
yield from walk(
subpackage.__path__,
f"{prefix}.{modname}",
depth + 1
)
return list(walk(package.__path__, package_name, 0))
Version Notes¶
- Python 2.6+: Basic functionality
- Python 3.3+: Namespace packages support
- Python 3.9+: Enhanced path handling
- Python 3.10+: Various optimizations
Related Documentation¶
- Importlib Module - Dynamic importing
- Sys Module - sys.path management
- Pathlib Module - Path operations