python - 如何优雅/高效地为需要大量实例变量的 Python 类编写 __init__ 函数?

标签 python class

假设您有一个带有许多(关键字)参数的类,其中大部分要存储为实例变量:

class ManyInitVariables():
    def __init__(a=0, b=2, c=1, d=0, e=-1, ... , x=100, y=0, z=9):

如何在 __init__ 中初始化它们?你可以这样做:

class ManyInitVariables():
    def __init__(a=0, b=2, c=1, d=0, e=-1, ... , x=100, y=0, z=9):
        self.a = a
        self.b = b
        self.c = c
        ...
        self.z = z

...但这需要大量输入!我怎样才能让 __init__ 自动一些它需要的参数,注意其他参数可能不需要分配为实例变量?

最佳答案

我敢肯定,对于这个非常常见的问题,网络上还有许多其他类似的解决方案,但这是一个,例如:

import functools
import inspect

def absorb_args(f):
    args, _, _, defs = inspect.getargspec(f)
    args = args[1:]  # ignore the leading `self`
    @functools.wraps(f)
    def do_absorb(self, *a, **k):
        ndefs = len(args) - len(a) + 2
        for name, value in zip(args, a + defs[-ndefs:]):
            setattr(self, name, value)
        for name, value in k.items():
            setattr(self, name, value)
        return f(self, *a, **k)
    return do_absorb

补充:我被要求进一步解释这一点,但是,如果你不擅长 Python,这里有很多事情要做!-)。

functools.wraps 是一个装饰器,可以帮助制作更好的装饰器,参见 https://docs.python.org/2/library/functools.html#functools.wraps -- 与问题没有直接关系,但有助于支持交互式 help 和基于函数文档字符串的工具。在编写(最常见的情况)包装被装饰函数的函数装饰器时,养成总是使用它的习惯,您不会后悔的。

inspect 模块是在现代 Python 中进行内省(introspection)的唯一正确方法。 inspect.getargspec 特别为您提供有关函数接受哪些参数的信息,以及它们的默认值是什么(如果有的话)(我忽略的两位信息,通过将它们分配给 _,是关于 *a**k 特殊参数,这个装饰器不支持)。参见 https://docs.python.org/2/library/inspect.html?highlight=getargspec#inspect.getargspec了解更多。

按照惯例,

self 始终是方法的第一个参数(并且此装饰器仅用于方法:-)。因此,第一个 for 循环处理位置参数(无论是在调用中明确给出还是默认为默认值);然后,第二个 for 循环处理命名参数(我希望那个更容易掌握:-)。 setattr 当然是珍贵的内置函数,它用变量名设置属性,https://docs.python.org/2/library/functions.html?highlight=setattr#setattr了解更多。

顺便说一句,如果你只关心在 __init__ 中使用它(正如你在下面的例子中看到的,absorb_attrs 本身没有这样的约束),那么写一个 < strong>class 装饰器,它为这种处理挑选出类的 __init__,并将该类装饰器应用于类本身。

此外,如果您的类的 __init__ 一旦以这种方式“吸收”了 args 就没有工作要做,您仍然必须定义(修饰的)__init__,但是它的主体可以限制为解释参数的文档字符串(我个人更喜欢在这种情况下总是也有一个 pass 语句,但这是个人风格问题)。

现在,回到原来的答案,举个例子...!-)

然后,例如,类似

class Struggle(object):

    @absorb_args
    def __init__(self, a, b, c, bab='bo', bip='bop'):
        self.d = a + b

    @absorb_args
    def setit(self, x, y, z, u=23, w=45):
        self.t = x + y

    def __str__(self):
        attrs = sorted(self.__dict__)
        r = ['%s: %s' % (a, getattr(self, a)) for a in attrs]
        return ', '.join(r)

s = Struggle('fee', 'fie', 'foo', bip='beeeeeep')
s.setit(1, 2, 3, w=99)
print(s)

会打印

a: fee, b: fie, bab: bo, bip: beeeeeep, c: foo, d: feefie, t: 3, u: 23, w: 99, x: 1, y: 2, z: 3

根据需要。

我以这种方式“重新发明轮子”(而不是在网上搜索解决方案)的唯一借口是那天晚上我的妻子和合著者安娜(唯一一位因对Python 社区,顺便说一句:-) 问了我这个问题(我们正在慢慢写“Python in a Nutshell”的第 3 版)——我花了 10 分钟来编写这个代码(抱歉,还没有测试:- ) 而在同样的 10 分钟内,她(尽管她是一个非常熟练的网络搜索者:-) 无法在网络上找到现有的解决方案。而且,这样我就不必担心版权问题,如果我想在这里发布它,将它包含在下一个 Nutshell 中,在 OSCON 或 Pycon 上展示它,等等...:-)

关于python - 如何优雅/高效地为需要大量实例变量的 Python 类编写 __init__ 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28004358/

相关文章:

python - 如何在 Keras 中使用类权重进行图像分割

python - 如何在 Django ORM 查询中进行日期数学运算?

python - 自定义字典在施放时丢弃键

javascript - 获取 Javascript 中某个类内链接的 HREF 值

java - 为什么java允许在方法体中定义类?

PHP可以将类嵌套在两个文件中吗?

javascript - javascript类中的静态异步函数

python - Scikit-优化如何将收敛图保存到文件

python - 错误权限错误: [Errno 13] Permission denied: '/var/task/main.py'

python - 在python中覆盖 'to boolean'运算符?