- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
首先让我说我了解槽和元类在 Python 中的工作方式。玩弄这两个,我遇到了一个有趣的问题。这是一个最小的例子:
def decorator(cls):
dct = dict(cls.__dict__)
dct['__slots__'] = ('y',)
return type('NewClass', cls.__bases__, dct)
@decorator
class A(object):
__slots__= ('x',)
def __init__(self):
self.x = 'xx'
A()
这会产生以下异常:
Traceback (most recent call last):
File "p.py", line 12, in <module>
A()
File "p.py", line 10, in __init__
self.x = 'xx'
TypeError: descriptor 'x' for 'A' objects doesn't apply to 'NewClass' object
现在,我知道为什么会这样了:为插槽 x
创建的描述符必须能够引用插槽的保留空间。只有类 A 的实例或 A 的子类的实例才有此保留空间,因此只有那些实例可以使用描述符 x
。在上面的例子中,元类创建了一个新类型,它是 A 的基类的子类,但不是 A 本身的子类,所以我们得到了异常。很简单。
当然,在这个简单的例子中,decorator
的以下两个定义中的任何一个都可以解决这个问题:
def decorator(cls):
dct = dict(cls.__dict__)
dct['__slots__'] = ('y',)
return type('NewClass', (cls,) + cls.__bases__, dct)
def decorator(cls):
class NewClass(cls):
__slots__ = ('y',)
return NewClass
但是这些解决方法与原始方法并不完全相同,因为它们都将 A 添加为基类。他们可能会在更复杂的设置中失败。例如,如果继承树比较复杂,您可能会遇到以下异常:TypeError: multiple bases have instance lay-out conflict
。
所以我非常具体的问题是:
有没有办法通过调用 type
来创建一个新类,修改现有类的 __slots__
属性,但不添加现有类作为新类的基类?
编辑:
我知道严格的元类是我上面示例的另一种变通方法。有很多方法可以使最小示例工作,但我的问题是关于通过基于现有类的 new
创建一个类,而不是关于如何使示例工作。抱歉造成混淆。
编辑 2:
评论中的讨论让我提出了一个比我最初提出的问题更精确的问题:
是否可以通过调用 type
创建一个类,它使用现有类的槽和描述符而不是该类的后代?
如果答案是“否”,我将不胜感激有关为什么不这样做的消息来源。
最佳答案
不,不幸的是,在创建类之后无法对 __slots__
做任何事情(那是调用它们的装饰器的时候)。唯一的方法是使用元类,并在调用 type.__new__
之前修改/添加 __slots__
。
此类元类的示例:
class MetaA(type):
def __new__(mcls, name, bases, dct):
slots = set(dct.get('__slots__', ()))
slots.add('y')
dct['__slots__'] = tuple(slots)
return super().__new__(mcls, name, bases, dct)
class BaseA(metaclass=MetaA):
pass
class A(BaseA):
__slots__ = ('x',)
def __init__(self):
self.x = 1
self.y = 2
print(A().x, A().y)
如果没有元类,您可以施展魔法,从已定义的类中复制所有内容,然后即时创建一个新类,但该代码有异味 ;)
def decorator(cls):
slots = set(cls.__slots__)
slots.add('y')
dct = cls.__dict__.copy()
for name in cls.__slots__:
dct.pop(name)
dct['__slots__'] = tuple(slots)
return type(cls)(cls.__name__, cls.__bases__, dct)
@decorator
class A:
__slots__ = ('x',)
def __init__(self):
self.x = self.y = 42
print(A().x, A().y)
此类代码的主要缺点是,如果有人在您的装饰器之前应用了另一个装饰器,并且比方说,在某处创建了对装饰类的引用,那么他们最终将存储对不同类的引用。元类也是如此——它们将执行两次。因此,元类方法更好,因为没有副作用。
为什么在创建类后不能真正更改 __slots__
的最终答案取决于您正在使用的 python 解释器的实现细节。例如,在 CPython 中,对于您定义的每个槽,类都有一个描述符(请参阅 CPython 源代码中的 PyMemberDescr_Type
和 PyMemberDef
结构),它有一个偏移参数,其中插槽值在内部对象存储中对齐。而且您根本没有在公共(public) Python API 中操作这些东西的工具。您以灵 active 换取更少的内存使用(同样,在 CPython 中,就像在 PyPy 中一样,您会自动为所有类获得相同的内存效果)。
如果绝对需要修改 __slots__
,您可能可以编写一个 C 扩展(或使用 ctypes
)并执行它,但这不是一个可靠的解决方案.
关于python - 是否可以在已经定义了 __slots__ 的类的装饰器中添加 __slots__?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20086908/
首先让我说我了解槽和元类在 Python 中的工作方式。玩弄这两个,我遇到了一个有趣的问题。这是一个最小的例子: def decorator(cls): dct = dict(cls.__di
__slots__ 的目的是什么?在 Python 中——尤其是关于我什么时候想使用它,什么时候不想使用它? 最佳答案 In Python, what is the purpose of __slot
我在 Python 的输入系统和 __slots__ 之间有冲突。这是一个可重现的小例子。 from typing import TypeVar, Generic, Sequence T = Type
class Foo(object): __slots__ = ('a',) class Bar(Foo): @property def a(self): ret
我有一节课 __slots__ : class A: __slots__ = ('foo',) 如果我创建一个子类而不指定__slots__,子类将有一个__dict__: class B(A
我正在开发一个需要通过 __init__ 注入(inject)来为其赋予 __dict__ 属性的类,如下所示: class Torrent(Model): def __init__(self
我听说 __slots__ 通过避免字典查找使对象更快。我的困惑来自于 Python 是一种动态语言。在静态语言中,我们通过编译时优化将索引保存在我们运行的指令中,从而避免了对 a.test 的字典查
我需要用 None 初始化一个实例的所有插槽。如何获取派生类的所有插槽? 示例(不起作用): class A(object): __slots__ = "a" def __init__
所以,我正在阅读一些关于 Python 中元类的内容,以及如何使用 type()的三参数 alter-ego 用于动态创建类。但是,第三个参数通常是 dict。初始化要创建的类'__dict__变量。
考虑以下代码: from weakref import ref class Klass(object): # __slots__ = ['foo'] def __init__(self
通过学习《Python类变量和实例变量》一节,了解了如何动态的为单个实例对象添加属性,甚至如果必要的话,还可以为所有的类实例对象统一添加属性(通过给类添加属性)。 那么,Python 是否也允许动态地
早上好 我在尝试在我的一门类(class)中使用 __ 插槽 __ 时遇到问题。我想用它来优化 Classifier 对象的多个实例的创建。我正在使用 Python 3.7.1。 这行得通 class
当我运行这个(2.7.3)时,我得到这个输出: 'Slotted1' object has no attribute 'c' attribute c added to 我不明白 Slotted1 和
最近在学习Python,但是我有一个关于__slots__的问题。我认为是为了限制Class中的参数,同时也限制Class中的方法? 例如: from types import MethodType
最近给 friend 讲解了__slots__的用法。我想向他展示结果并使用了以下代码: import sys class Foo: __slots__ = 'a', 'b' def
我一直在玩弄 __slots__ 并稍微搜索一下,但我仍然对某些细节感到困惑: 我知道 __slots__ 生成某种描述符: >>> class C: ... __slots__ = ('x'
在类中创建结果对象时,是否可以在本例中使用__slots__?我想我可以通过将 '__slots__' 传递到 type 的第三个参数的字典中来让它工作: class GeocodeResult(ob
我读入了Usage of __slots__?在 Python 中使用 __slots__ 实际上可以节省时间。但是,当我尝试使用 datetime 查找所花费的时间时,结果却相反。 import d
我正在使用 Python 3.7 和 Django。我正在阅读 __slots__ .显然,__slots__ 可用于通过提前列出所有对象属性来优化大量此类对象的内存分配。 class MyClass
我正在编写一个配置卷的存储自动化模块。我没有传递在存储 Controller 上实际创建卷所需的六个或更多参数,而是使用 __slots__ 创建了一个参数类,它被传递到 create 方法中,如下所
我是一名优秀的程序员,十分优秀!