假设我有一个这样的课程:
class Test(object):
prop = property(lambda self: "property")
每当我尝试访问Test().prop
时,描述符都会优先。这样会返回'property'
。如果我想访问对象的实例存储,我可以这样做:
x = Test()
x.__dict__["prop"] = 12
print(x.__dict__["prop"])
但是,如果我将课程改为:
class Test(object):
__slots__ = ("prop",)
prop = property(lambda self: "property")
我如何执行相同操作并访问x
的内部存储空间,以便写12
并将其读回,因为x.__dict__
已不存在?
我对Python很新,但我理解Python的理念是完全控制,为什么实现细节阻止我这样做呢?
Python是否缺少可从内部存储实例读取的内置函数,如:
instance_vars(x)["prop"] = 12
print(instance_vars(x)["prop"])
可以像vars
一样工作,但它也适用于__slots__
,内置类型没有__dict__
?
答案 0 :(得分:3)
简短回答,你不能
问题在于插槽本身是根据描述符实现的。给出:
class Test(object):
__slots__ = ("prop",)
t = Test()
短语:
t.prop
翻译成大约:
Test.prop.__get__(t, Test)
其中Test.prop
是由运行时制作的<type 'member_descriptor'>
,专门用于从prop
个实例中加载Test
个值。
如果您向类主体定义添加另一个描述符,它会屏蔽member_descriptor
,这将使您可以访问slotted属性;没有办法要求它,它就不再存在了。这有点像说:
class Test(object):
@property
def prop(self):
return self.__dict__['prop']
@property
def prop(self):
return "property"
你已经定义了两次。没有办法“了解”第一个prop
定义。
但:
答案很长,你不能以一般方式。 你可以
你仍然可以滥用python类型系统来使用另一个类定义来获取它。您可以更改python对象的类型,只要它具有完全相同的类布局,这大致意味着它具有所有相同的插槽:
>>> class Test1(object):
... __slots__ = ["prop"]
... prop = property(lambda self: "property")
...
>>> class Test2(object):
... __slots__ = ["prop"]
...
>>> t = Test1()
>>> t.prop
'property'
>>> t.__class__ = Test2
>>> t.prop = 5
>>> t.prop
5
>>> t.__class__ = Test1
>>> t.prop
'property'
但是没有通用的方法来反省一个实例来计算它的类布局;你只需要从上下文中了解。您可以查看它的__slots__
类属性,但这不会告诉您超类中提供的插槽(如果有的话),如果该属性已更改,它也不会给您任何提示由于某种原因,在课程定义后。
答案 1 :(得分:1)
我不太明白你想做什么以及为什么这样做,但这对你有帮助吗?
>>> class Test(object):
__slots__ = ("prop",)
prop = property(lambda self: "property")
>>> a = Test()
>>> b = Test()
>>> a.prop
'property'
>>> tmp = Test.prop
>>> Test.prop = 23
>>> a.prop
23
>>> Test.prop = tmp; del tmp
>>> b.prop
'property'
当然,你无法在每个实例的基础上覆盖该属性,这就是时隙描述符的重点。
请注意,__slots__
的类的子类确实有__dict__
,除非您手动定义__slots__
,所以您可以这样做:
>>> class Test2(Test):pass
>>> t = Test2()
>>> t.prop
'property'
>>> t.__dict__['prop'] = 5
>>> t.__dict__['prop']
5
>>> Test2.prop
<property object at 0x00000000032C4278>
但仍然:
>>> t.prop
'property'
并且这不是因为__slots__
,而是描述符的工作方式。
您的__dict__
在属性查找时被绕过,您只是滥用它作为存储状态的数据结构。
它相当于这样做:
>>> class Test(object):
__slots__ = ("prop", "state")
prop = property(lambda self: "property")
state = {"prop": prop}
>>> t.prop
'property'
>>> t.state["prop"] = 5
>>> t.state["prop"]
5
>>> t.prop
'property'
答案 2 :(得分:0)
如果你真的想做类似的事情,而你真的需要这样的东西,你总是可以覆盖__getattribute__
和__setattribute__
,这就像愚蠢...这只是为了向你证明:
class Test(object):
__slots__ = ("prop",)
prop = property(lambda self: "property")
__internal__ = {}
def __getattribute__(self, k):
if k == "__dict__":
return self.__internal__
else:
try:
return object.__getattribute__(self, k)
except AttributeError, e:
try:
return self.__internal__[k]
except KeyError:
raise e
def __setattribute__(self, k, v):
self.__internal__[k] = v
object.__setattribute__(self, k, v)
t = Test()
print t.prop
t.__dict__["prop"] = "test"
print "from dict", t.__dict__["prop"]
print "from getattr", t.prop
import traceback
# These won't work: raise AttributeError
try:
t.prop2 = "something"
except AttributeError:
print "see? I told you!"
traceback.print_exc()
try:
print t.prop2
except AttributeError:
print "Haha! Again!"
traceback.print_exc()
(在Python 2.7上尝试过) 这正是你所期待的。不要这样做,这没用。