我可以在初始化属性本身时传递属性名称吗?

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 一样简单)