使用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