如何在python中自动向类中添加属性?

时间:2016-03-31 06:18:18

标签: python pycharm

我有一个类,在实例化时提供了很多属性( init )。

看起来像这样,但还有大约30个attr:

class SomeObject:
    def __init__(self,
                 first,
                 second):
        self.first = first
        self.second = second

工作正常,但重复性很长,很难更新。

在我使用更小的课程之前:

class SomeObject:
    def __init__(self, **attr):
        self.__dict__.update(attr)

工作正常,更容易,但很难跟踪。当使用IDE(我使用PyCharm)时,我在编写对象时没有提示,自动完成提示通常不起作用。

我会寻找两个类的混合,例如:

class SomeObject:
    def __init__(self,
                 first,
                 second):
    self.__dict__.update(???)  # I would like to do it in a single line, so I dont have to write a new attr two (three...) times.

有谁知道这是否可行?非常感谢

Python 3.4 + PyCharm 2016.1 CommunityEdition

...编辑/补充......

问题似乎主要在于"保留" IDE中的代码检查,以便对象上仍然可以使用自动完成等。

5 个答案:

答案 0 :(得分:2)

您只需使用locals内置函数获取本地变量的字典,然后删除self并更新:

class test:
    def __init__(self,
                 a,b,c,d,e,f,g,h,i,j,k,l,m,
                 n,o,p,q,r,s,t,u,v,w,x,y,z):
        args = locals()
        del args["self"]
        if "args" in args:
            del args["args"]
        self.__dict__.update(args)

args = list(range(26))

x = test(*args)

from string import ascii_lowercase as letters
assert args == [getattr(x,c) for c in letters]
print("worked")

虽然如果你真的想让你的IDE开心,它需要看到显式的属性赋值,所以你可以编写代码来编写代码:

def write_init_code(func):
    self,*args = func.__code__.co_varnames
    return "\n".join(["{0}.{1} = {1}".format(self,a)
                      for a in args])

class test:
    def __init__(self,a,b,c,d,e,f,*v,**kw):
        pass #just a moment...


print(write_init_code(test.__init__))

然后只需将write_init_code的结果复制粘贴并缩进到实际功能中即可完成。

答案 1 :(得分:1)

模块inspect允许您查询正在运行的程序。以下示例演示了它的用法:

import inspect

class Test:
        def __init__(self, a, b, c, d):
                argInfo = inspect.getargvalues(inspect.currentframe())
                print(argInfo)
                # Print argument values in order of parameters
                print([ argInfo.locals[paramName] for paramName in argInfo.args[1:] ])

t = Test(1,2,3,4)

输出:

ArgInfo(args=['self', 'a', 'b', 'c', 'd'], varargs=None, keywords=None, locals={'c': 3, 'self': <__main__.Test object at 0x7fb2d9c0ce10>, 'b': 2, 'd': 4, 'a': 1})
[1, 2, 3, 4]

如您所见,您可以通过ArgInfo.locals访问参数字典及其相应的参数名称。

第二个打印出来的例子是如何按参数声明的顺序放置参数值。

您可以使用它来填充实例变量,或者只需复制ArgInfo.locals字典。

答案 2 :(得分:0)

您可以使用locals()来实现您的目标:

class SomeObject:
    def __init__(self, first, second):
        kwargs = locals()
        kwargs.pop('self')  # remove `self` keywork from the dict
        self.__dict__.update(kwargs)

答案 3 :(得分:0)

有了dataclasses,PyCharm现在很容易并且完全支持。通过添加键入注释并使用修饰符@dataclasses.dataclass,我们使类成员充当实例成员。

import dataclasses
import typing

@dataclasses.dataclass
class SomeObject:
    first: str
    second: str
    class_member1 = None
    class_member2: typing.ClassVar[str] = None

SomeObject(first="first", second="second")

请注意,带有诸如firstsecond之类的注释的类字段的作用类似于实例成员。而诸如class_member1之类的未注释字段仍保留为类成员。

但是,如果您想将某个字段用作类成员,但仍然希望拥有键入信息,请使用注释typing.ClassVar。这样,您就可以拥有class_member2这是一个班级成员,并且还具有键入信息。

答案 4 :(得分:-1)

编辑:现在python 3.7已经出来了,@ dataclass类装饰器非常优雅地解决了这个问题。

原始答案: 使用PyCharm中的多个游标,您可以轻松转换

self.first = first
self.second = second

到很长的一行,如:

self.first, self.second = first, second

这就是我为保持PyCharm智能而做的事情