如何确保附带名称不会在类定义中结束,代码既适用于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上正确运行的代码中?
答案 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'>, {})