使用Python';非类属性的s__获取__描述符

使用Python';非类属性的s__获取__描述符,python,class,attributes,python-descriptors,Python,Class,Attributes,Python Descriptors,使用\uuuu get\uuuuu描述符,我希望实现如下目标: class Wrapper: def __init__(self, wrapped_value): self._wrapped_value = wrapped_value def __get__(self, instance, owner): return self._wrapped_value wrapper = Wrapper('foo') assert type(wrappe

使用
\uuuu get\uuuuu
描述符,我希望实现如下目标:

class Wrapper:
    def __init__(self, wrapped_value):
        self._wrapped_value = wrapped_value

    def __get__(self, instance, owner):
        return self._wrapped_value

wrapper = Wrapper('foo')
assert type(wrapper) == type('foo')
事实证明,只有当
包装器
实例是某个其他类的类属性时,
包装器
实例是独立对象(未绑定到任何类属性)时,
获取描述符才会被调用

有没有一种方法可以使
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
描述符在非类属性中工作


主要目标是实现wrapper,当使用它时,它的行为就像它所包装的值一样(我知道乍一看它听起来并不有用,但在一些用例中这会很有用)。因此,也许有其他方法可以实现这一点,而无需使用
\uuu get\uuu
描述符?

如果希望包装类控制对包装类属性的访问,可以使用magic方法

假设我们有一个类
Foo

class Foo(object):

    def bar(self):
        return 'bar'

    def baz(self):
        return 'baz'
假设我们正在与一些我们无法控制的代码交互,这些代码要求
Foo.bar()
的输出为大写,我们不希望在代码中显式调用
.upper()

我们可以创建一个包装器类来拦截对
Foo.bar()
的调用,但透明地允许访问
Foo
的其他方法(这基本上是最简单的方法)

此包装类不会通过
type
isinstance
检查报告为
Foo
,但如果调用代码依赖于显式类型检查而不是(非音速)显式类型检查,则可以使用它代替
Foo

拦截魔法方法,如
\uuu str\uu
必须明确执行。这是因为这些方法总是直接在实例的类上,所以绕过了
\uuuuGetAttr\uuuuuuu
\uuuuuuuuGetAttribute\uuuuuu

因此,要覆盖
Foo.\uuu str\uuu
,您需要执行以下操作:

class Foo(object):

    ...

    def __str__(self):
        return 'I am a Foo'


class Wrapper(object):

    ...

    def __str__(self):
        return str(self._wrapped)

>>> wrapper = Wrapper(Foo())
>>> print wrapper
I am a Foo

我不确定你是否能得到
type(wrapper)
返回错误的值,更不确定这是否是个好主意。您能否提供更多使用
包装器的示例?可能还有其他方法可以获得您想要的行为。好吧,
\uuuuu get\uuuuu
描述符的存在正是为了达到这个目的,即“隐藏”对象的真实身份,并让它充当不同类型的对象。这是Python2官方文档中的一个示例:在上面的示例中,以下代码不会引发AssertOnError:
AssertIsInstance(m.x,int)
,但这仅在
RevealAccess
类的实例是
MyClass
的类属性时才有效。如果
revealacess
实例是一个独立的对象,我希望它也能工作。描述符代码工作是因为
type()
是在描述符返回的对象上调用的,而不是描述符本身。我想了解的是,您是否需要
type()
返回包装对象的类型,或者它是否足以让包装控制访问包装对象的方法/属性,这可以使用
\uuuu getattribute\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu通过
getattr
函数处理对包装器的调用,如
wrapper.\uuuu str\uuuu
并将其重定向到
self.\uu wrapped.\uuu str\uuuu
。如果这是可能的,那么
Wrapper
实例上的所有dunder方法调用都可以重定向到
self.\u wrapped
的dunder方法调用。不幸的是,这是不可能的。您知道为什么通过
\uuuu getattr\uuuu
方法无法获取属性,即
\uuu str\uuu
?这是因为
\uuuu str\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。这正是我所担心的——我需要手动重写每个dunder方法,不要忘记它们中的任何一个,否则我的
包装器
的行为将与包装对象(我的目标)不完全相同。所以我需要找到可用dunder方法的完整列表并覆盖它们。但是仍然-覆盖
是持续的
类型
检查是不可能的,对吗?或者,在执行此类检查时,可能会调用相应的魔术方法?@KonradKocik,AFAIK,
,并且不能拦截
类型
。您可以看看模块中的工具。但老实说,这种程度的模仿似乎毫无意义;如果您想要与原始对象行为完全相同的对象,只需使用原始对象即可。行为完全相同,但有一个例外:
Wrapper
本身在包装不可变对象时是可变的:)
class Foo(object):

    ...

    def __str__(self):
        return 'I am a Foo'


class Wrapper(object):

    ...

    def __str__(self):
        return str(self._wrapped)

>>> wrapper = Wrapper(Foo())
>>> print wrapper
I am a Foo