确保在类定义中删除不需要的名称

时间:2015-08-12 08:57:48

标签: python-3.x compatibility python-2.x

如何确保附带名称不会在类定义中结束,代码既适用于Python 2又适用于Python 3?

使用以下类定义,只有列表推导所需的附带名称'foo''bar'保留在Parrot名称空间中:

__metaclass__ = type

class Parrot:
    """ A parrot with beautiful plumage. """

    plumage = [
            (foo, bar) for (foo, bar) in feathers.items()
            if bar == "beautiful"]

assert hasattr(Parrot, 'plumage')  # ← okay, has the wanted name
assert not hasattr(Parrot, 'foo')  # ← FAILS, has an unwanted name
assert not hasattr(Parrot, 'bar')  # ← FAILS, has an unwanted name

所以我可以在使用它们后删除这些名称:

__metaclass__ = type

class Parrot:
    """ A parrot with beautiful plumage. """

    plumage = [
            (foo, bar) for (foo, bar) in feathers.items()
            if bar == "beautiful"]
    del foo, bar

assert hasattr(Parrot, 'plumage')  # ← okay, has the wanted name
assert not hasattr(Parrot, 'foo')  # ← okay, no unwanted name
assert not hasattr(Parrot, 'bar')  # ← okay, no unwanted name

但是在Python 3上失败了,因为名称​​不会从列表理解中继续存在:

__metaclass__ = type

class Parrot:
    """ A parrot with beautiful plumage. """

    plumage = [
            (foo, bar) for (foo, bar) in feathers.items()
            if bar == "beautiful"]
    del foo, bar  # ← FAILS, “NameError: name 'foo' is not defined”

如何使用列表推导编写类定义并且保留附带名称 - 在将在Python 2和Python 3上正确运行的代码中?

2 个答案:

答案 0 :(得分:2)

对于列表推导的特定情况,它将泄漏Python 2中的名称,并且不会泄漏Python 3中的名称。这是documented as deprecated behaviour

另一方面,generator expression不会泄漏Python 2或Python 3中的名称。因此列表可以从生成器构建:

__metaclass__ = type

class Parrot:
    """ A parrot with beautiful plumage. """

    plumage = list(
            (foo, bar) for (foo, bar) in feathers.items()
            if bar == "beautiful")

assert hasattr(Parrot, 'plumage')  # ← okay, has the wanted name
assert not hasattr(Parrot, 'foo')  # ← okay, no unwanted name
assert not hasattr(Parrot, 'bar')  # ← okay, no unwanted name

这将导致类名称空间中没有“泄露”的名称,在Python 2中也不会在Python 3中出现。

答案 1 :(得分:1)

您可以在类范围内捕获NameError以使其工作:

class Parrot:
    """ A parrot with beautiful plumage. """
    plumage = [
            (foo, bar) for (foo, bar) in feathers.items()
            if bar == "beautiful"]
    try:
        del foo, bar
    except NameError:
        pass

您可能需要稍微调整一下,以确保您尝试/捕捉每个变量名称。

不相关,但你可以用这种方式做出令人惊讶的事情:

>>> class A(object):
...     import collections
...
>>> A().collections.defaultdict(list)
defaultdict(<type 'list'>, {})