使用lambda:None函数作为命名空间的优点?

时间:2016-05-30 19:02:38

标签: python lambda namespaces names

我看到了以下code

eris = lambda:None
eris.jkcpp = np.einsum('iipq->ipq', eriaa[:ncore[0],:ncore[0],:,:])
eris.jc_PP = np.einsum('iipq->pq', eriab[:ncore[0],:ncore[0],:,:])

我们可以为lambda:None定义的函数定义任意属性吗?

我正在阅读一个casscf代码,这是量子化学中的算法,作者使用这个lambda函数来获得2电子积分。 然后显然是decided against it

2 个答案:

答案 0 :(得分:16)

这看起来像是一个创建一个简单对象来保存一行中的值的技巧。大多数内置对象不允许您在它们上设置任意属性:

>>> object().x = 0
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'object' object has no attribute 'x'
>>> ''.x = 0
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'str' object has no attribute 'x'
>>> [].x = 0
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'list' object has no attribute 'x'

如果您创建自己的类,则可以添加所需的任何属性。在这种情况下,您可以创建一个__init__方法分配属性的类,但这可能不值得使用样板。所以你可以做一个空课:

>>> class Data(object): pass
>>> d = Data()
>>> d.x = 0
>>> d.x
0

显然,程序员要么不知道这个,要么不想要声明类的额外行,并且已经提出了自己的存储数据解决方法。虽然是内置类型 do 允许你为它们添加属性,但事实证明它是函数:

>>> def foo(): pass
>>> foo.x = 0
>>> foo.x
0

上述和lambda都允许您在单个语句中创建这样的容器。我其实认为这是一个很好的主意。

答案 1 :(得分:11)

  

使用lambda:None函数有什么好处?

这里发生了什么

eris = lambda:None
eris.jkcpp = ...

是作者使用其__dict__的函数对象创建名称空间。

命名空间是合法的Python名称映射到对象的域,当您执行上述操作时,命名空间的优点是名称是不在本地和全球范围内,他们可以覆盖或覆盖相同名称指向不同对象的地方。

表面上没有任何问题,但是如果其他人试图阅读代码以了解正在传递的这个功能正在发生什么,那么他们可能正在思考:

  

会被叫到吗?为什么我们绕过一个可赎回的人?返回None的callable并不是非常有用,这必定是某种黑客攻击。

为避免混淆,请使用将在语义上理解为命名空间的对象。

命名空间

我们在Python 3的标准库中有一个SimpleNamespace对象:

from types import SimpleNamespace
eris = SimpleNamespace()
eris.jkcpp = ...

在Python 2中,通常会执行以下操作:

class NS(object): 
    pass

eris = NS()
eris.jkcpp = ...

如果您需要一个简单的命名空间,这些都是可以选择的。

缺点

但是,我还没有使用这些形式的命名空间。我要么发现一个namedtuple就足以让我想要在数据中携带语义(特别是在有很多这些数据时很有用)或者我使用的是一个多于pass的可变对象。

就像它们一样,它们在编程上与简单的字典完全不同。名称指向的值存储在对象__dict__中。您也可以传递dict个实例。虚线查找增加了一点开销(在查看对象的字典之前检查对象的类型是否具有数据描述符)。

结论:

命名空间实例可能有一些缺点,但它可能更具可读性。可读性很重要。如果您认为您的程序需要一个简单的命名空间,请使用它。

但是不要对命名空间使用do-nothing函数。这是误导性的,对任何人都没有意义。