如何使从列表继承并使用关键字参数的 class 同时在 Python 2 和 Python 3 中工作?
How can a class that inherits from list and uses keyword arguments be made to work in both Python 2 and Python 3?
我有一个 class 在 Python 3 中工作的类似下面的东西。我怎样才能让它在 Python 2 中也工作?
class Palette(list):
def __init__(
self,
name = None, # string name
description = None, # string description
colors = None, # list of colors
*args
):
super().__init__(self, *args)
self._name = name
self._description = description
self.extend(colors)
def name(
self
):
return self._name
def set_name(
self,
name = None
):
self._name = name
def description(
self
):
return self._description
def set_description(
self,
description = None
):
self._description = description
palette1 = Palette(
name = "palette 1",
colors = [
"#F1E1BD",
"#EEBA85",
"#E18D76",
"#9C837E",
"#5B7887"
]
)
palette1.set_description("This is palette 1.")
print(palette1.name())
print(palette1.description())
print(palette1)
您只需将 super()
调用更改为使用显式参数:
super(Palette, self).__init__(*args)
并且您的代码在 Python 2 和 Python 3 中都可以正常工作。请参阅 Why is Python 3.x's super() magic? 了解为什么以上等同于 super().__init__(*args)
的背景信息。此外,不要 再次传入 self
,否则您将在列表内容中包含 self
时创建循环引用。
请注意,使用 property
对象而不是显式的 getter 和 setter 更符合 pythonic:
class Palette(list):
def __init__(self, name=None, description=None, colors=None, *args):
super(Palette, self).__init__(args)
self.name = name
self.description = description
self.extend(colors)
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
@name.deleter
def name(self):
self.name = None
@property
def description(self):
return self._description
@description.setter
def description(self, description):
self._description = description
@description.deleter
def description(self):
self.description = None
然后使用
palette1.description = "This is palette 1."
我还冒昧地减少了函数定义中的空格数量;将每个参数都放在一个新行上使得很难获得 class 的概述,因为函数体被不必要地向下推。
由于这些属性实际上 做 除了用下划线包裹同名属性之外的任何东西,你最好 把它们放在外面一共。与 Java 不同,在 Python 中,您可以在直接使用属性和稍后为 属性 对象交换属性之间自由切换;你不属于其中之一。
请注意,在Python 2 和Python 3 中,您不能传入位置参数;以下不起作用:
Palette('#F1E1BD', '#EEBA85', name='palette2')
因为第一个位置参数将分配给 name
参数:
>>> Palette('#F1E1BD', '#EEBA85', name='palette2')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __init__() got multiple values for argument 'name'
要支持该用例,您需要不 命名签名中的关键字参数,并且仅使用**kwargs
,然后从中检索您的关键字参数。将任何位置参数作为 一个参数 传递,以便 list()
将任意数量的位置参数作为新列表的内容:
class Palette(list):
def __init__(self, *args, **kwargs):
super(Palette, self).__init__(args)
self.name = kwargs.pop('name', None)
self.description = kwargs.pop('description', None)
self.extend(kwargs.pop('colors', []))
if kwargs:
raise TypeError('{} does not take {} as argument(s)'.format(
type(self).__name__, ', '.join(kwargs)))
演示:
>>> class Palette(list):
... def __init__(self, *args, **kwargs):
... super(Palette, self).__init__(args)
... self.name = kwargs.pop('name', None)
... self.description = kwargs.pop('description', None)
... self.extend(kwargs.pop('colors', []))
... if kwargs:
... raise TypeError('{} does not take {} as argument(s)'.format(
... type(self).__name__, ', '.join(kwargs)))
...
>>> palette1 = Palette(
... name = "palette 1",
... colors = [
... "#F1E1BD",
... "#EEBA85",
... "#E18D76",
... "#9C837E",
... "#5B7887"
... ]
... )
>>> palette2 = Palette("#F1E1BD", "#EEBA85", "#E18D76", "#9C837E", "#5B7887",
... name="palette 2")
>>> palette1
['#F1E1BD', '#EEBA85', '#E18D76', '#9C837E', '#5B7887']
>>> palette2
['#F1E1BD', '#EEBA85', '#E18D76', '#9C837E', '#5B7887']
>>> palette1.name
'palette 1'
>>> palette2.name
'palette 2'
>>> palette1.description = 'This is palette 1.'
>>> palette2.description = 'This is palette 2.'
>>> Palette(foo='bar', spam='eggs')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 9, in __init__
TypeError: Palette does not take foo, spam as argument(s)
我有一个 class 在 Python 3 中工作的类似下面的东西。我怎样才能让它在 Python 2 中也工作?
class Palette(list):
def __init__(
self,
name = None, # string name
description = None, # string description
colors = None, # list of colors
*args
):
super().__init__(self, *args)
self._name = name
self._description = description
self.extend(colors)
def name(
self
):
return self._name
def set_name(
self,
name = None
):
self._name = name
def description(
self
):
return self._description
def set_description(
self,
description = None
):
self._description = description
palette1 = Palette(
name = "palette 1",
colors = [
"#F1E1BD",
"#EEBA85",
"#E18D76",
"#9C837E",
"#5B7887"
]
)
palette1.set_description("This is palette 1.")
print(palette1.name())
print(palette1.description())
print(palette1)
您只需将 super()
调用更改为使用显式参数:
super(Palette, self).__init__(*args)
并且您的代码在 Python 2 和 Python 3 中都可以正常工作。请参阅 Why is Python 3.x's super() magic? 了解为什么以上等同于 super().__init__(*args)
的背景信息。此外,不要 再次传入 self
,否则您将在列表内容中包含 self
时创建循环引用。
请注意,使用 property
对象而不是显式的 getter 和 setter 更符合 pythonic:
class Palette(list):
def __init__(self, name=None, description=None, colors=None, *args):
super(Palette, self).__init__(args)
self.name = name
self.description = description
self.extend(colors)
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
@name.deleter
def name(self):
self.name = None
@property
def description(self):
return self._description
@description.setter
def description(self, description):
self._description = description
@description.deleter
def description(self):
self.description = None
然后使用
palette1.description = "This is palette 1."
我还冒昧地减少了函数定义中的空格数量;将每个参数都放在一个新行上使得很难获得 class 的概述,因为函数体被不必要地向下推。
由于这些属性实际上 做 除了用下划线包裹同名属性之外的任何东西,你最好 把它们放在外面一共。与 Java 不同,在 Python 中,您可以在直接使用属性和稍后为 属性 对象交换属性之间自由切换;你不属于其中之一。
请注意,在Python 2 和Python 3 中,您不能传入位置参数;以下不起作用:
Palette('#F1E1BD', '#EEBA85', name='palette2')
因为第一个位置参数将分配给 name
参数:
>>> Palette('#F1E1BD', '#EEBA85', name='palette2')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __init__() got multiple values for argument 'name'
要支持该用例,您需要不 命名签名中的关键字参数,并且仅使用**kwargs
,然后从中检索您的关键字参数。将任何位置参数作为 一个参数 传递,以便 list()
将任意数量的位置参数作为新列表的内容:
class Palette(list):
def __init__(self, *args, **kwargs):
super(Palette, self).__init__(args)
self.name = kwargs.pop('name', None)
self.description = kwargs.pop('description', None)
self.extend(kwargs.pop('colors', []))
if kwargs:
raise TypeError('{} does not take {} as argument(s)'.format(
type(self).__name__, ', '.join(kwargs)))
演示:
>>> class Palette(list):
... def __init__(self, *args, **kwargs):
... super(Palette, self).__init__(args)
... self.name = kwargs.pop('name', None)
... self.description = kwargs.pop('description', None)
... self.extend(kwargs.pop('colors', []))
... if kwargs:
... raise TypeError('{} does not take {} as argument(s)'.format(
... type(self).__name__, ', '.join(kwargs)))
...
>>> palette1 = Palette(
... name = "palette 1",
... colors = [
... "#F1E1BD",
... "#EEBA85",
... "#E18D76",
... "#9C837E",
... "#5B7887"
... ]
... )
>>> palette2 = Palette("#F1E1BD", "#EEBA85", "#E18D76", "#9C837E", "#5B7887",
... name="palette 2")
>>> palette1
['#F1E1BD', '#EEBA85', '#E18D76', '#9C837E', '#5B7887']
>>> palette2
['#F1E1BD', '#EEBA85', '#E18D76', '#9C837E', '#5B7887']
>>> palette1.name
'palette 1'
>>> palette2.name
'palette 2'
>>> palette1.description = 'This is palette 1.'
>>> palette2.description = 'This is palette 2.'
>>> Palette(foo='bar', spam='eggs')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 9, in __init__
TypeError: Palette does not take foo, spam as argument(s)