Python getattr() 的基本用法

1. getattr基本语法

getattr() 是 Python 内置的一个函数,可以用来获取一个对象的属性值或方法。其基本语法为:

getattr(object, name[, default])

其中,object 是要获取属性值或方法的对象;name 是要获取的属性名或方法名;default 是可选参数,当指定的属性或方法不存在时,会返回 default 的值。

2. 基本用法

getattr() 可以通过对象实例或类名来获取属性值或方法,也可以获取内置函数、内置类型和标准库中的属性和方法。

下面是一些常见的使用 getattr() 的案例:

2.1 获取对象的属性值

class MyClass:
	def __init__(self):
		self.x = 1
		self.y = 2

obj = MyClass()

print(getattr(obj, 'x')) # 输出 1
print(getattr(obj, 'y')) # 输出 2

2.2 获取对象的方法

class MyClass:
	def my_method(self):
		print('Hello, world!')

obj = MyClass()

method = getattr(obj, 'my_method')
method() # 输出 "Hello, world!"

2.3 获取内置函数和类型

func = getattr(__builtins__, 'abs')
print(func(-1)) # 输出 1

type_name = 'str'
type_obj = getattr(__builtins__, type_name)
print(type_obj('Hello, world!')) # 输出 "Hello, world!"

2.4 获取标准库中的属性和方法

import datetime

now = datetime.datetime.now()

attr_name = 'year'
attr_value = getattr(now, attr_name)
print(attr_value) # 输出当前年份

method_name = 'strftime'
method_args = ['%Y-%m-%d %H:%M:%S']
method = getattr(now, method_name)
formatted = method(*method_args)
print(formatted) # 输出格式化后的时间字符串,如 "2023-05-06 10:30:00"

在实际开发中,getattr() 还可以用于实现动态调用函数或方法的功能,以及在需要处理大量类似属性或方法的代码时,简化代码的编写。

3. 开源代码的实际使用

getattr() 还可以结合 import_module() 函数,实现动态执行某个文件中某个类的方法的功能。这一点在 Uvicorn [2]的代码 importer.py 中得到了应用,用于对应用程序的加载,具体的代码如下:

import importlib
from typing import Any

class ImportFromStringError(Exception):
	pass
	
def import_from_string(import_str: Any) -> Any:
	if not isinstance(import_str, str):
		return import_str

	module_str, _, attrs_str = import_str.partition(":")
	if not module_str or not attrs_str:
		message = 'Import string "{import_str}" must be in format "<module>:<attribute>".'
		raise ImportFromStringError(message.format(import_str=import_str))
	
	try:
		module = importlib.import_module(module_str)
	except ModuleNotFoundError as exc:
		if exc.name != module_str:
			raise exc from  None
		message = 'Could not import module "{module_str}".'
		raise ImportFromStringError(message.format(module_str=module_str))

	instance = module
	try:
		for attr_str in attrs_str.split("."):
			instance = getattr(instance, attr_str)
	except AttributeError:
		message = 'Attribute "{attrs_str}" not found in module "{module_str}".'
		raise ImportFromStringError(message.format(attrs_str=attrs_str, module_str=module_str))
	return instance

那么上面的方法怎么使用呢?写一个最简单的加法和减法计算的模块,并命名为 module_a.py,该模块代码如下:

def add(a:int, b:int):
	return a+b
def minus(a:int, b:int):
	return a-b

调用处的代码如下:

from importer import import_from_string

# 加载模块并找到属性,模块为module_a,属性为add
app_add = import_from_string('module_a:add')
app_minus = import_from_string('module_a:minus')

print(app_add(1, 2)) # 3
print(app_minus(3, 1)) # 2

这样,就实现了动态的模块加载

参考文献

[1] https://www.runoob.com/python/python-func-getattr.html
[2] https://github.com/encode/uvicorn