我可以在初始化属性本身时传递属性名称吗?
Can I pass the name of an attribute when it itself is being initialised?
我有一个 class,我在其中将几个 class 属性定义为对象。属性本身的名称是需要传递给对象的参数之一。目前它们是手动编写的,如下例所示:
class Beatles:
john = Guitar(name='john')
paul = Bass(name='paul')
george = Guitar(name='george')
ringo = Drums(name='ringo')
class Musician:
def __init__(self)
class Guitar(Musician):
def __init__(self, name)
class Bass(Musician):
def __init__(self, name)
class Drums(Musician):
def __init__(self, name)
我找到了一个解决方法,它使用元class 来构建使用 Foo 对象的命名空间字典的对象:
class Meta(type):
def __new__(cls, name, bases, dict_):
for k, v in dict_.items():
if isinstance(v, Musician):
dict_[k] = type(v)(k)
return super().__new__(cls, name, bases, dict_)
这仅在 'name' 参数是唯一的参数时有效,而事实并非如此。有没有更好的方法?
对象本身尚不存在,但构造函数最终是一个函数,因此您可以将需要的内容作为函数参数传递。
在这种情况下,示例可能没有传达您想问的问题。你没有名字是因为你是鼓手,你有名字是因为你是人。作为层次结构的顶层,Musician 将具有 属性,而不是 Drummer,它应该是 Musician 构造函数中的一个参数:
class Musician:
def __init__(self, name):
self.name = name
class Guitar(Musician):
def __init__(self, name):
super().__init__(name)
class Bass(Musician):
def __init__(self, name):
super().__init__(name)
class Drums(Musician):
def __init__(self, name):
super().__init__(name)
Beatles = {
Guitar(name='john'),
Bass(name='paul'),
Guitar(name='george'),
Drums(name='ringo'),
}
for m in Beatles:
print (m.name)
在 Python 3.6 中,有一项新功能可以解决此模式,并减少对 meta类 的需求,因为这些几乎总是会导致混淆。
所需要的只是要成为属性的对象的类有一个__set_name__
方法(在你的例子中,这些都是[=的子类 13=],所以,你所要做的就是给它添加一个def __set_name__(self, owner, name): ...
方法)。
因此,您的情况只需要:
class Musician:
def __init__(self, ...):
# no need to get a 'name' parameter here
...
# This is called automatically by Python:
def __set_name__(self, owner, name):
# 'owner' is the class object where the attributes are defined in.
# in this case, "Beatles". It is usually not needed, but available.
self.name = name
class Guitar(Musician):
pass
class Bass(Musician):
pass
class Drums(Musician):
pass
class Beatles(metaclass=Meta):
john = Guitar()
paul = Bass()
george = Guitar()
ringo = Drums()
现在,如果出于某种原因你想通过使用 meta类 来实现它(假设你必须在 Python 3.5 上工作,或者不能更改 Musician
类) - 您可以使用 functools.partial 来存储其他属性,只需在上面的相同元类代码中传递缺少的 name
属性:
from functools import partial
class Beatles:
john = partial(Guitar, other_attribute='')
paul = partial(Bass, wearing_shoes=False)
george = partial(Guitar)
ringo = partial()
(请记住,如果需要,您可以缩短 partial
以提高可读性,就像 from functools import partial as P
一样简单)
我有一个 class,我在其中将几个 class 属性定义为对象。属性本身的名称是需要传递给对象的参数之一。目前它们是手动编写的,如下例所示:
class Beatles:
john = Guitar(name='john')
paul = Bass(name='paul')
george = Guitar(name='george')
ringo = Drums(name='ringo')
class Musician:
def __init__(self)
class Guitar(Musician):
def __init__(self, name)
class Bass(Musician):
def __init__(self, name)
class Drums(Musician):
def __init__(self, name)
我找到了一个解决方法,它使用元class 来构建使用 Foo 对象的命名空间字典的对象:
class Meta(type):
def __new__(cls, name, bases, dict_):
for k, v in dict_.items():
if isinstance(v, Musician):
dict_[k] = type(v)(k)
return super().__new__(cls, name, bases, dict_)
这仅在 'name' 参数是唯一的参数时有效,而事实并非如此。有没有更好的方法?
对象本身尚不存在,但构造函数最终是一个函数,因此您可以将需要的内容作为函数参数传递。
在这种情况下,示例可能没有传达您想问的问题。你没有名字是因为你是鼓手,你有名字是因为你是人。作为层次结构的顶层,Musician 将具有 属性,而不是 Drummer,它应该是 Musician 构造函数中的一个参数:
class Musician:
def __init__(self, name):
self.name = name
class Guitar(Musician):
def __init__(self, name):
super().__init__(name)
class Bass(Musician):
def __init__(self, name):
super().__init__(name)
class Drums(Musician):
def __init__(self, name):
super().__init__(name)
Beatles = {
Guitar(name='john'),
Bass(name='paul'),
Guitar(name='george'),
Drums(name='ringo'),
}
for m in Beatles:
print (m.name)
在 Python 3.6 中,有一项新功能可以解决此模式,并减少对 meta类 的需求,因为这些几乎总是会导致混淆。
所需要的只是要成为属性的对象的类有一个__set_name__
方法(在你的例子中,这些都是[=的子类 13=],所以,你所要做的就是给它添加一个def __set_name__(self, owner, name): ...
方法)。
因此,您的情况只需要:
class Musician:
def __init__(self, ...):
# no need to get a 'name' parameter here
...
# This is called automatically by Python:
def __set_name__(self, owner, name):
# 'owner' is the class object where the attributes are defined in.
# in this case, "Beatles". It is usually not needed, but available.
self.name = name
class Guitar(Musician):
pass
class Bass(Musician):
pass
class Drums(Musician):
pass
class Beatles(metaclass=Meta):
john = Guitar()
paul = Bass()
george = Guitar()
ringo = Drums()
现在,如果出于某种原因你想通过使用 meta类 来实现它(假设你必须在 Python 3.5 上工作,或者不能更改 Musician
类) - 您可以使用 functools.partial 来存储其他属性,只需在上面的相同元类代码中传递缺少的 name
属性:
from functools import partial
class Beatles:
john = partial(Guitar, other_attribute='')
paul = partial(Bass, wearing_shoes=False)
george = partial(Guitar)
ringo = partial()
(请记住,如果需要,您可以缩短 partial
以提高可读性,就像 from functools import partial as P
一样简单)