【问题标题】:Referencing Class Methods inside Class Variables在类变量中引用类方法
【发布时间】:2015-03-25 21:25:23
【问题描述】:

如何在类变量中引用类方法?

例如:

我有

class UU(object):

  map = {
    'username': get_username
  }

  @classmethod
  def get_username(cls):
    pass

但是,get_username 找不到。

我尝试了UU.get_username,但这似乎不起作用。

【问题讨论】:

  • 你为什么要这样做?
  • UU.get_username "works",它什么也没做。 map 应该做什么?它只是让您编写像UU.map['username'] 这样的冗长内容作为对类方法的引用。 (或者它会,如果 get_username 还没有定义,它不是。)
  • 在另一个函数中,我想将某些键传递给地图并运行与值对应的函数。但是,这些函数可以是无状态的。地图可以从课堂中取出,但主要是为了便于阅读。
  • 我在回答中添加了一些关于使用getattr 的内容,这可能对您有用。

标签: python


【解决方案1】:

类体像函数一样被执行,然后本地命名空间变成类属性。

因此适用正常的命名顺序要求;您不能引用get_username(),因为它尚未定义

此外,即使您将map 定义移到get_username() 定义下方,您也会得到未绑定的classmethod 对象

因此,您需要在创建类之后将该方法添加到映射中:

class UU(object):
    @classmethod
    def get_username(cls):
        pass

UU.map = {
    'username': UU.get_username
}

请注意,这意味着从那里开始UU.map['username'] 正在使用绑定到UU 类的classmethod。如果您曾经对 UU 进行子类化并提供了对该方法的覆盖,那么您将不会获得子类上的版本。

你必须跳更多的圈子才能使这个对子类起作用;您必须将 map 设为 descriptor object 以便在映射中查找值时绑定类方法,而不是在定义映射时:

class BindingMap(dict):
    def __get__(self, instance, cls=None):
        return {k: v.__get__(instance, cls) if hasattr(v, '__get__') else v for k, v in self.items()}

class UU(object):
    @classmethod
    def get_username(cls):
        pass

    map = BindingMap({
        'username': get_username,
    })

然后地图将根据需要生成绑定的类方法,并扩展到子类:

>>> class BindingMap(dict):
...     def __get__(self, instance, cls=None):
...         return {k: v.__get__(instance, cls) if hasattr(v, '__get__') else v for k, v in self.items()}
... 
>>> class UU(object):
...     @classmethod
...     def get_username(cls):
...         pass
...     map = BindingMap({
...         'username': get_username,
...     })
... 
>>> UU.map
{'username': <bound method type.get_username of <class '__main__.UU'>>}
>>> UU.map['username']
<bound method type.get_username of <class '__main__.UU'>>
>>> UU.map['username']()
>>> class UU(object):
...     @classmethod
...     def get_username(cls):
...         print('Username for class {}'.format(cls.__name__))
...     map = BindingMap({
...         'username': get_username,
...     })
... 
>>> UU.map
{'username': <bound method type.get_username of <class '__main__.UU'>>}
>>> UU.map['username']
<bound method type.get_username of <class '__main__.UU'>>
>>> UU.map['username']()
Username for class UU
>>> class Foo(UU):
...     pass
... 
>>> Foo.map
{'username': <bound method type.get_username of <class '__main__.Foo'>>}
>>> Foo.map['username']
<bound method type.get_username of <class '__main__.Foo'>>
>>> Foo.map['username']()
Username for class Foo

【讨论】:

  • unubutu 的代码似乎不同意“此外,即使您将地图定义移到 get_username() 定义下方,您也会得到未绑定的 classmethod 对象。”,如果我理解正确的话。跨度>
  • @sweeneyrod:不,他的代码显示你只得到了未绑定的 classmethod 对象。绑定的方法看起来像&lt;bound method type.get_username of &lt;class '__main__.UU'&gt;&gt;
  • @sweeneyrod:如果您尝试使用我的代码调用未绑定的类方法,则会遇到TypeError: 'classmethod' object is not callable。没用,所以我把我的答案删了。
【解决方案2】:

您的代码不起作用的原因是因为 UU 的方法是在类变量之后定义的 - 因此,当您尝试将其添加到字典时,get_username 不存在。

试试这个:

class UU(object):

  @classmethod
  def get_username(cls):
    pass

UU.map = {
    'username': UU.get_username
  }

从您对该问题的评论来看,您可能会发现 getattr 很有用。

例子:

method_name = "get_username"
method = getattr(UU, method_name)
method()

或者只是

getattr(UU, "get_username")()

不需要字典!

【讨论】:

    猜你喜欢
    • 2011-08-10
    • 1970-01-01
    • 2011-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多