Python 动态定义依赖于先前定义的属性的属性
我想要一个表示路径Python 动态定义依赖于先前定义的属性的属性,python,python-attrs,Python,Python Attrs,我想要一个表示路径根的对象,以及用os.path.join(root)构造的任意数量的子目录。我想以self.root、self.path\u a、self.path\u b等形式访问这些路径。。。除了通过self.path\u a直接访问它们之外,我还希望能够对它们进行迭代。不幸的是,下面的方法不允许通过attr.astuple(路径) 下面的第一段代码是我想到的。它能用,但我觉得有点不舒服。由于这是我第一次使用,我想知道是否有更直观/惯用的方法来实现这一点。我花了很长时间才弄明白如何编写下面
根
的对象,以及用os.path.join(root)
构造的任意数量的子目录。我想以self.root
、self.path\u a
、self.path\u b
等形式访问这些路径。。。除了通过self.path\u a
直接访问它们之外,我还希望能够对它们进行迭代。不幸的是,下面的方法不允许通过attr.astuple(路径)
下面的第一段代码是我想到的。它能用,但我觉得有点不舒服。由于这是我第一次使用,我想知道是否有更直观/惯用的方法来实现这一点。我花了很长时间才弄明白如何编写下面这个相当简单的类,所以我想我可能遗漏了一些明显的东西
我的方法
输出
p=路径(子路径=['a','b','c',根路径='/tmp')
>>>p
路径(subdirs=['a','b','c'],root='/tmp')
>>>私人助理
“/tmp/a”
>>>p.b
“/tmp/b”
>>>p.c
“/tmp/c”
以下是我的第一次尝试,但没有成功
失败的尝试
输出
------------------------------------------------------------------
TypeError回溯(最近一次调用上次)
在()
1@attr.s
---->2类路径(对象):
3 root=attr.ib(默认值=os.getcwd())
4 subdir_1=attr.ib(os.path.join(root,'a'))
5 subdir_2=attr.ib(os.path.join(root,'b'))
在路径()中
2类路径(对象):
3 root=attr.ib(默认值=os.getcwd())
-->4 subdir_1=attr.ib(os.path.join(root,'a'))
5 subdir_2=attr.ib(os.path.join(root,'b'))
6.
连接中的~/miniconda3/lib/python3.6/posixpath.py(a,*p)
76个将被丢弃。最后一部分为空将导致路径
77以分隔符结尾
-->78 a=os.fspath(a)
79年9月=获得9月(a)
80路径=a
TypeError:应为str、bytes或os.PathLike对象,而不是_CountingAttr
猜不出您为什么要以self.paths.path
的身份访问。但是,下面是我要做的:
class D(object):
root = os.getcwd()
paths = dict()
def __init__(self, paths=[]):
self.paths.update({'root': self.root})
for path in paths:
self.paths.update({path: os.path.join(self.root, path)})
def __str__(self):
return str(self.paths)
d = D(paths=['static', 'bin', 'source'])
print(d)
print(d.paths['bin'])
输出
{'root': '/home/runner', 'static': '/home/runner/static', 'bin': '/home/runner/bin', 'source': '/home/runner/source'}
/home/runner/bin
您可以将其变得更复杂。这只是一个示例。希望它能有所帮助。第一次尝试:您不能只将随机数据附加到类,而希望attrs(在本例中是一个tuple)将其拾取。attrs特别尝试避免魔术和猜测,这意味着您必须确实在类上定义属性 第二次尝试:不能在类作用域中使用属性名称(即在
类路径中:
,但在方法之外),因为正如Python告诉您的那样,此时它们仍然是@attr.s
使用的内部数据
我能想到的最优雅的方法是将路径作为参数并构建完整路径的通用工厂:
In [1]: import attr
In [2]: def make_path_factory(path):
...: def path_factory(self):
...: return os.path.join(self.root, path)
...: return attr.Factory(path_factory, takes_self=True)
您可以这样使用:
In [7]: @attr.s
...: class C(object):
...: root = attr.ib()
...: a = attr.ib(make_path_factory("a"))
...: b = attr.ib(make_path_factory("b"))
In [10]: C("/tmp")
Out[10]: C(root='/tmp', a='/tmp/a', b='/tmp/b')
In [11]: attr.astuple(C("/tmp"))
Out[11]: ('/tmp', '/tmp/a', '/tmp/b')
attr作为attr,您当然可以进一步定义自己的attr.ib包装器:
In [12]: def path(p):
...: return attr.ib(make_path_factory(p))
In [13]: @attr.s
...: class D(object):
...: root = attr.ib()
...: a = path("a")
...: b = path("b")
...:
In [14]: D("/tmp")
Out[14]: D(root='/tmp', a='/tmp/a', b='/tmp/b')
这并不是
attrs
的真正目的。你到底想做什么?@roeen30我对代码示例做了重大修改,希望这些修改能更清楚地说明我试图解决的问题。你想做什么更清楚,但不清楚为什么。优秀的pathlib-如果还没有,请查看一下。由于attrs
的主要目标是创建快速记录类,因此在这里它并没有真正帮助您,因为您有一个具有一个预定义属性的类(root
)。看起来像是试图通过一个圆孔来安装一个方形的销钉。顺便说一句,如果你不能避免使用\uu get/setattribute\uu()。
In [7]: @attr.s
...: class C(object):
...: root = attr.ib()
...: a = attr.ib(make_path_factory("a"))
...: b = attr.ib(make_path_factory("b"))
In [10]: C("/tmp")
Out[10]: C(root='/tmp', a='/tmp/a', b='/tmp/b')
In [11]: attr.astuple(C("/tmp"))
Out[11]: ('/tmp', '/tmp/a', '/tmp/b')
In [12]: def path(p):
...: return attr.ib(make_path_factory(p))
In [13]: @attr.s
...: class D(object):
...: root = attr.ib()
...: a = path("a")
...: b = path("b")
...:
In [14]: D("/tmp")
Out[14]: D(root='/tmp', a='/tmp/a', b='/tmp/b')