在 python 的方法调用中有选择地设置一些 class 属性的简便方法
convenient way to optionally set some class properties in method call in python
我主要使用 python 作为数值模拟的胶水语言。
通常我会创建一些包装器 class 来初始化一些合理的默认参数,并且与其他地方相比,在更大的脚本中我会调用 run()
方法,该方法可以选择性地覆盖一些参数,然后执行实际的模拟。
它可能看起来像这样:
class MyCalculationClass():
def __init__():
# set some defaults
self.A = 45454
self.B = np.zeros(16,11)
self.C = (1.0,2.5,30.0)
def runRaw():
return whatever(self.A,self.B,self.C)
def run( A=None, B=None, C=None ):
# optionally override some defaults
if A is not None:
self.A = A
if B is not None:
self.B = B
if C is not None:
self.C = C
# run the actual calculation
return self.runRaw()
mycalc1 = MyClaculationClass()
# .... Over the Hills and Far Away
mycalc1.run(B=np.zeros(11,12) )
但我真的讨厌到处都是样板 if A is not None: self.A = A
。通常有几十个参数。
这样会好一点
def run( A=self.A, B=self.B, C=self.C ):
# optionally override some defaults
self.A = A
self.B = B
self.C = C
# run the actual calculation
self.runRaw()
但是:
- 没用
- 仍然是太多的样板文件
注意:我真的希望 self.A
等继续存储为 class 属性,以便能够在以后的较大的计算中恢复我在哪个计算中使用的参数脚本
您可以使用关键字参数并使用 update()
方法更新对象字典(仅当变量不是 class 的属性时才有效。如果是这种情况,请使用 setattr()
方法)。
class MyCalculationClass():
def __init__(self):
# set some defaults
self.A = 45454
self.B = [0, 0, 0, 0, 0]
self.C = (1.0,2.5,30.0)
def runRaw(self):
print(self.A, self.B, self.C)
def run(self, **kwargs):
self.__dict__.update(kwargs)
return self.runRaw()
c = MyCalculationClass()
c.run(B=[1, 1, 1])
打印:
45454 [1, 1, 1] (1.0, 2.5, 30.0)
如果您不介意丢失一些检查提供的自动文档,您可以这样做:
class Foo(object):
def __init__(self):
self._set(A=42, B=[], C="something")
def _set(self, **kw):
for name, val in kw.items():
if val is not None:
setattr(self, name, val)
def run(self, **kw):
self._set(**kw)
self.runRaw()
如果你想保持 run()
签名完整,这是可能的,但不会那么通用(因为 run()
必须知道它的参数):
def run(self, A=None, B=None, C=None):
self._set(A=A, B=B, C=C)
self.runRaw()
另请注意,可以通过声明 __call__
方法使 Python 对象可调用:
class NotAFunc(object):
def __call__(self, arg):
print("{} called with {}".format(self, arg))
f = NotAFunc()
f(42)
装饰器也可以做到这一点:
import functools
def set_if_none(method):
@functools.wraps(method)
def wrapper(self, **kwargs): # no *args without inspect.signature
for k, v in kwargs.items():
if v is not None and hasattr(self, k):
setattr(self, k, v)
result = method(self, **kwargs) # no *args
return result
return wrapper
注意:以上示例仅适用于(使用和强制执行)关键字参数。要合并位置参数,您可能需要 inspect.signature
.
示例:
class MyClass(object):
def __init__(self, a=1, b=2):
self.a = a
self.b = b
def __repr__(self):
return 'MyClass(%s)' % self.__dict__
@set_if_none
def meth(self, a=None, b=None):
pass
>>> mc = MyClass()
>>> mc
MyClass({'a': 1, 'b': 2})
>>> mc.meth(a=10)
>>> mc
MyClass({'a': 10, 'b': 2})
感谢 提醒您可以通过在装饰器中将 self
(实例)传递给 wrapper()
来修改 class 实例。
我主要使用 python 作为数值模拟的胶水语言。
通常我会创建一些包装器 class 来初始化一些合理的默认参数,并且与其他地方相比,在更大的脚本中我会调用 run()
方法,该方法可以选择性地覆盖一些参数,然后执行实际的模拟。
它可能看起来像这样:
class MyCalculationClass():
def __init__():
# set some defaults
self.A = 45454
self.B = np.zeros(16,11)
self.C = (1.0,2.5,30.0)
def runRaw():
return whatever(self.A,self.B,self.C)
def run( A=None, B=None, C=None ):
# optionally override some defaults
if A is not None:
self.A = A
if B is not None:
self.B = B
if C is not None:
self.C = C
# run the actual calculation
return self.runRaw()
mycalc1 = MyClaculationClass()
# .... Over the Hills and Far Away
mycalc1.run(B=np.zeros(11,12) )
但我真的讨厌到处都是样板 if A is not None: self.A = A
。通常有几十个参数。
这样会好一点
def run( A=self.A, B=self.B, C=self.C ):
# optionally override some defaults
self.A = A
self.B = B
self.C = C
# run the actual calculation
self.runRaw()
但是:
- 没用
- 仍然是太多的样板文件
注意:我真的希望 self.A
等继续存储为 class 属性,以便能够在以后的较大的计算中恢复我在哪个计算中使用的参数脚本
您可以使用关键字参数并使用 update()
方法更新对象字典(仅当变量不是 class 的属性时才有效。如果是这种情况,请使用 setattr()
方法)。
class MyCalculationClass():
def __init__(self):
# set some defaults
self.A = 45454
self.B = [0, 0, 0, 0, 0]
self.C = (1.0,2.5,30.0)
def runRaw(self):
print(self.A, self.B, self.C)
def run(self, **kwargs):
self.__dict__.update(kwargs)
return self.runRaw()
c = MyCalculationClass()
c.run(B=[1, 1, 1])
打印:
45454 [1, 1, 1] (1.0, 2.5, 30.0)
如果您不介意丢失一些检查提供的自动文档,您可以这样做:
class Foo(object):
def __init__(self):
self._set(A=42, B=[], C="something")
def _set(self, **kw):
for name, val in kw.items():
if val is not None:
setattr(self, name, val)
def run(self, **kw):
self._set(**kw)
self.runRaw()
如果你想保持 run()
签名完整,这是可能的,但不会那么通用(因为 run()
必须知道它的参数):
def run(self, A=None, B=None, C=None):
self._set(A=A, B=B, C=C)
self.runRaw()
另请注意,可以通过声明 __call__
方法使 Python 对象可调用:
class NotAFunc(object):
def __call__(self, arg):
print("{} called with {}".format(self, arg))
f = NotAFunc()
f(42)
装饰器也可以做到这一点:
import functools
def set_if_none(method):
@functools.wraps(method)
def wrapper(self, **kwargs): # no *args without inspect.signature
for k, v in kwargs.items():
if v is not None and hasattr(self, k):
setattr(self, k, v)
result = method(self, **kwargs) # no *args
return result
return wrapper
注意:以上示例仅适用于(使用和强制执行)关键字参数。要合并位置参数,您可能需要 inspect.signature
.
示例:
class MyClass(object):
def __init__(self, a=1, b=2):
self.a = a
self.b = b
def __repr__(self):
return 'MyClass(%s)' % self.__dict__
@set_if_none
def meth(self, a=None, b=None):
pass
>>> mc = MyClass()
>>> mc
MyClass({'a': 1, 'b': 2})
>>> mc.meth(a=10)
>>> mc
MyClass({'a': 10, 'b': 2})
感谢 self
(实例)传递给 wrapper()
来修改 class 实例。