我有一个类,在实例化(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中的代码检查,以便对象上仍然可以使用自动完成等。
你可以简单地用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
的结果复制粘贴并缩进到实际功能中即可完成。
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
字典即可。
你可以使用locals()
来实现你想要的:
class SomeObject:
def __init__(self, first, second):
kwargs = locals()
kwargs.pop('self') # remove `self` keywork from the dict
self.__dict__.update(kwargs)
使用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")
请注意,带有注释的类字段(如first
和second
)就像实例成员一样。虽然像class_member1
这样未被注释的领域仍然是班级成员。
但是如果你想要一些字段作为类成员但仍想要输入信息,那么使用注释typing.ClassVar
。这允许你拥有class_member2
这是一个类成员,并且还有输入信息。
编辑:现在python 3.7已经出来了,@ dataclass类装饰器非常优雅地解决了这个问题。
原始答案:使用PyCharm中的多个游标,您可以轻松转换
self.first = first
self.second = second
到很长的路线:
self.first, self.second = first, second
这就是我为保持PyCharm智能而做的事情