我有类A
,其子类str
通过kwargs
class A(str):
def __new__(cls, value, **kwargs):
obj = str.__new__(cls, value)
obj.__dict__.update(kwargs)
return obj
喜欢使用:
x = A('test', meta=10)
x.meta
10
现在,我也想处理unicode
类型,所以我采用了以下方法。要动态检查类型并将其用作base_class
class B(object):
def __new__(cls, value, **kwargs):
base_class = str if isinstance(value, str) else unicode
new_type = type(cls.__name__, (base_class,), dict(cls.__dict__))
obj = base_class.__new__(new_type, value)
obj.__dict__.update(kwargs)
return obj
然而,这似乎是不正确的做法。给我一个
TypeError:'B'对象的描述符' dict '不适用于'B'对象
B('test', meta=10)
-----------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-533-206366568616> in <module>()
----> 1 B('tes', a=10).a
<ipython-input-528-91dc8e50cb78> in __new__(cls, value, **kw)
11 new_type = type(cls.__name__, (base_class,), dict(cls.__dict__))
12 obj = base_class.__new__(new_type, value)
---> 13 obj.__dict__.update(kw)
14 return obj
15
TypeError: descriptor '__dict__' for 'B' objects doesn't apply to 'B' object
我可以使用C
来使用setattr
代替,这可以正常使用。
class C(object):
def __new__(cls, value, **kw):
base_class = str if isinstance(value, str) else unicode
new_type = type(cls.__name__, (base_class,), dict(cls.__dict__))
obj = base_class.__new__(new_type, value)
for k, v in kw.items():
setattr(obj, k, v)
return obj
x = C('test', meta=10)
x.meta
10
您能否帮我理解 class B
上错过的内容以及如何使用__dict__
?
答案 0 :(得分:1)
发生此错误的原因是您创建新类型的原因:
new_type = type(cls.__name__, (base_class,), dict(cls.__dict__))
如果你看一下裸班的__dict__
:
class A(object):
pass
print(dict(A.__dict__))
{
'__dict__': <attribute '__dict__' of 'A' objects>,
'__module__': '__main__',
'__weakref__': <attribute '__weakref__' of 'A' objects>,
'__doc__': None
}
__dict__
和__weakref__
是每个类的描述符,只有在必要时才创建__dict__
,以节省空间。它不适用于内置对象。它仅适用于创建它的特定类型,因为每个类在内存中的位置可能略有不同,无法存储__dict__
。
解决此问题的一种方法是删除它们:
class B(object):
def __new__(cls, value, **kwargs):
base_class = str if isinstance(value, str) else unicode
__dict__ = dict(cls.__dict__)
del __dict__['__dict__'], __dict__['__weakref__']
new_type = type(cls.__name__, (base_class,), __dict__)
obj = base_class.__new__(new_type, value)
obj.__dict__.update(kwargs)
return obj
b = B(u'b', meta=10)
print(b.meta) # 10
Python会自动添加它自己的__dict__
描述符。
答案 1 :(得分:0)
不太确定这里的最终目标是什么,但是根据初始值有一个具有不同基类的类,但仍然有__dict__
相关,你可以尝试多重继承,如:
class B(object):
def __new__(cls, value, **kwargs):
base_class = str if isinstance(value, str) else float
class X(base_class, B):
pass
new_type = type(cls.__name__, (X,), dict(cls.__dict__))
obj = base_class.__new__(new_type, value)
obj.__dict__.update(kwargs)
return obj
for val in ('test', 1.0):
x = B(val, meta=10)
print(x, x.meta, type(x), x.__dict__,
isinstance(x, str), isinstance(x, float))
test 10 <class '__main__.B'> {'meta': 10} True False
1.0 10 <class '__main__.B'> {'meta': 10} False True