【问题标题】:Disable descriptor object in Python在 Python 中禁用描述符对象
【发布时间】:2016-06-19 21:54:25
【问题描述】:

下面是descriptor 在 Python 中使用的简单示例:

class MyDescriptor(object):
  def __get__(self, obj, objtype):
    return 42

class MyClass(object):
  d = MyDescriptor()

print MyClass().d  # 42

但是,如果我希望描述符对象成为类的 实际 属性,那么 MyClass().d 将是 MyDescriptor 实例,而不是 42。

【问题讨论】:

  • 你可以让__get__返回self。但是你为什么要这样做呢?描述符的全部目的是启用此行为。如果你不想要它,为什么不把这个类变成一个描述符呢?
  • 我可能想存储描述符以备将来使用,例如。在这种情况下,返回 self 不是一个选项:我显然不想更改描述符。
  • 您可以始终将它们存储在列表或其他东西中,而不是直接作为属性。此外,由于类中只存储了描述符的一份副本,因此存储描述符本身通常没那么有用(因为您可能只能在一个地方使用它而不会引起混淆行为)。您可以改为存储描述符 class 并在以后想要使用那种描述符时创建一个新实例。
  • “将其存储在列表中”是一个不错的答案。

标签: python metaprogramming descriptor


【解决方案1】:

有很多方法可以得到你想要的,这取决于你到底想要什么。

如果您只想访问描述符对象(即,您不关心它是否实际上直接作为属性存储在类上),那么只需将其存储在列表或其他东西中:

class Foo(object):
    descriptor = [MyDescriptor()]

这将需要一个额外的间接级别来访问它,但实际上这可能比替代方法少。

the documentation 中所述,描述符通过object.__getattribute__ 激活。所以如果你真的希望它是一个属性,你可以在包含描述符(MyClass)的类上覆盖__getattribute__,从而阻止描述符机制生效:

class MyClass(object):
  d = MyDescriptor()

  def __getattribute__(self, attr):
    if attr=='d':
        return self.__class__.__dict__['d']
    else:
        return super(MyClass, self).__getattribute__(attr)

>>> MyClass().d
<__main__.MyDescriptor object at 0x0000000002843E80>

【讨论】:

  • 哇,太好了。答案中建议的另一种解决方案,没有“额外的间接访问级别”:将我的描述符放入另一个微不足道的描述符中。您能否将其添加到您的答案中(或者如果您同意,我会这样做)。
  • @VadimPushtaev:不确定你的意思。我的示例中的两个解决方案都不涉及将您的描述符包装在另一个描述符中。
  • @VadimPushtaev 如果您有自己问题的解决方案,请随时将其作为答案发布。回答你自己的问题很好。
  • @BrenBarn,对不起,我的意思是“是我在问题中建议的”:) 但没关系,我会单独发布。
【解决方案2】:

使用inspect.getattr_static

getattr_static() 不解析描述符,例如 slot 用 C 实现的对象上的描述符或 getset 描述符。 返回描述符对象而不是基础属性。

>>> import inspect
>>> inspect.getattr_static(MyClass, 'd')
<__main__.MyDescriptor object at 0x105678c18>
>>> inspect.getattr_static(MyClass(),"d")
<__main__.MyDescriptor object at 0x105678c18>

如果您想将此设置为实例的默认行为,您可以将 __getattribute__ 覆盖为 getattr_static

class MyClass(object):
  from inspect import getattr_static as __getattribute__
  d = MyDescriptor()

>>> MyClass().d
<__main__.MyDescriptor object at 0x105678c18>

坦率地说,我不明白你为什么想要这个,将描述符存储在一个不调用像 dict 这样的描述符的数据结构中会更有意义:

descriptors = {"d": MyDescriptor()}

然后您可以查找descriptors["d"] 而不会调用描述符。

【讨论】:

  • 这是一个非常好的答案,谢谢。可悲的是,这是一种禁用所有描述符的方法,而不仅仅是其中一个。
  • 不是真的,第一部分是一种在不调用描述符的情况下查找描述符的方法(我认为你想要的)然后第二部分是禁用类中的所有描述符功能(不是一个好主意, 打破所有绑定的方法),这可能对描述符的容器很有用。无论如何,我仍然不明白你想用这个来完成什么。
【解决方案3】:

我最简单的想法是将这个描述符包装到另一个中。它会起作用,因为只会调用一个 __get__

class TrivialDescriptor(object):
  def __init__(self, data):
    self._data = data

  def __get__(self, obj, objtype):
    return self._data

class MyDescriptor(object):
  def __get__(self, obj, objtype):
    return 42

class MyClass(object):
  d = TrivialDescriptor(MyDescriptor())

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-30
    • 2021-07-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-01
    • 2020-08-12
    • 1970-01-01
    相关资源
    最近更新 更多