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

问题描述 投票:2回答:5

我有一个类,在实例化(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中的代码检查,以便对象上仍然可以使用自动完成等。

python pycharm
5个回答
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
投票

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字典即可。


0
投票

你可以使用locals()来实现你想要的:

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

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这是一个类成员,并且还有输入信息。


-1
投票

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

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

self.first = first
self.second = second

到很长的路线:

self.first, self.second = first, second

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

© www.soinside.com 2019 - 2024. All rights reserved.