python中base属性_python – 使用动态base_class在__new__子类中设置属性

我有一个类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: descriptor ‘dict‘ for ‘B’ objects doesn’t apply to ‘B’ object

B('test', meta=10)

-----------------------------------------------------------------------

TypeError Traceback (most recent call last)

in ()

----> 1 B('tes', a=10).a

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

我可以使用setattr代替C语言,这很好.

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

你能帮我理解我在B级上错过了什么以及如何使用__dict__吗?

最佳答案 发生此错误的原因是您创建新类型的方式:

new_type = type(cls.__name__, (base_class,), dict(cls.__dict__))

如果你看一下裸课的__dict__:

class A(object):

pass

print(dict(A.__dict__))

{

'__dict__': ,

'__module__': '__main__',

'__weakref__': ,

'__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__描述符.

Python的抽象基类(Abstract Base Class,简称ABC)是一种特殊的类,它定义了一组抽象方法,这些方法必须在子类实现。ABC的一个主要用途是为了检查子类是否符合某个接口的规范。 在ABC,可以使用`__subclasshook__`方法来判断一个类是否是该ABC的虚拟子类。具体来说,如果一个类没有直接继承该ABC,但是它的基类有`__subclasshook__`方法,而且该方法返回True,则该类就被视为该ABC的虚拟子类。 下面是一个例子,我们定义了一个ABC `MyABC`,其定义了一个抽象方法`my_method`。然后定义了一个普通类`MyClass`,它继承自`object`,并且实现了`my_method`方法。最后,我们在`MyClass`定义了`__subclasshook__`方法,它判断一个类是否实现了`my_method`方法。 ```python from abc import ABC, abstractmethod class MyABC(ABC): @abstractmethod def my_method(self): pass class MyClass(object): def my_method(self): print("MyClass.my_method() is called") @classmethod def __subclasshook__(cls, C): if cls is MyABC: if hasattr(C, 'my_method'): return True return NotImplemented print(issubclass(MyClass, MyABC)) # True ``` 在上面的代码,我们使用`issubclass`函数来检查`MyClass`是否是`MyABC`的子类。由于`MyClass`实现了`my_method`方法,而且定义了`__subclasshook__`方法,因此`issubclass(MyClass, MyABC)`返回True。 接下来我们实现一个自己的虚拟子类。我们定义一个普通类`MyClass2`,它没有直接继承自`MyABC`,但是它的基类定义了`__subclasshook__`方法,该方法判断一个类是否实现了`my_method`方法。然后我们通过`register`方法将`MyClass2`注册为`MyABC`的虚拟子类。 ```python class MyClass2(object): def my_method(self): print("MyClass2.my_method() is called") @classmethod def __subclasshook__(cls, C): if cls is MyABC: if hasattr(C, 'my_method'): return True return NotImplemented MyABC.register(MyClass2) print(issubclass(MyClass2, MyABC)) # True ``` 在上面的代码,我们使用`register`方法将`MyClass2`注册为`MyABC`的虚拟子类。然后我们再次使用`issubclass`函数来检查`MyClass2`是否是`MyABC`的子类。由于`MyClass2`实现了`my_method`方法,并且已经被注册为`MyABC`的虚拟子类,因此`issubclass(MyClass2, MyABC)`返回True。 总之,`__subclasshook__`方法是ABC的一个重要方法,它可以让我们方便地判断一个类是否符合某个接口的规范。同时,我们也可以通过`register`方法将一个普通类注册为ABC的虚拟子类
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值