当前位置: 首页 > 知识库问答 >
问题:

创建一级对象它的所有实例属性都是只读的,比如slice?

计弘
2023-03-14

我的问题是如何创建像slice这样的类?

(内置类型)没有__dict__属性,即使这个元类type

而且它没有使用\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。

检查此代码:

# how slice is removing the __dict__ from the class object
# and the metaclass is type!!

class sliceS(object):
    pass

class sliceS0(object):

    def __setattr__(self, name, value):
        pass

# this means that both have the same
# metaclass type.
print type(slice) == type(sliceS) # prints True

# from what i understand the metaclass is the one
# that is responsible for making the class object
sliceS2 = type('sliceS2', (object,), {})
# witch is the same
# sliceS2 = type.__new__(type, 'sliceS2', (object,), {})
print type(sliceS2) # prints type

# but when i check the list of attribute using dir
print '__dict__' in dir(slice)  # prints False
print '__dict__' in dir(sliceS) # prints True

# now when i try to set an attribute on slice
obj_slice = slice(10)
# there is no __dict__  here
print '__dict__' in dir(obj_slice) # prints False
obj_sliceS = sliceS()
try:
    obj_slice.x = 1
except AttributeError as e:
    # you get AttributeError
    # mean you cannot add new properties
    print "'slice' object has no attribute 'x'"

obj_sliceS.x = 1 # Ok: x is added to __dict__ of obj_sliceS
print 'x' in obj_sliceS.__dict__ # prints True

# and slice is not using __slots__ because as you see it's not here
print '__slots__' in dir(slice) # print False

# and this why i'm saying it's not overriding the __settattr__
print id(obj_slice.__setattr__) == id(obj_sliceS.__setattr__) # True: it's the same object
obj_sliceS0 = sliceS0()
print id(obj_slice.__setattr__) == id(obj_sliceS0.__setattr__) # False: it's the same object

# so slice have only start, stop, step and are all readonly attribute and it's not overriding the __setattr__
# what technique it's using?!!!!

如何使这种一级对象的所有属性都是只读的,不能添加新属性。


共有1个答案

端木兴国
2023-03-14

问题是Python内置的slice类是用C语言编程的。当您使用C-Python API编码时,您可以编写与\uuuuuuu slots\uuuuu相当的属性,而无需使用Python端可见的任何机制。(您甚至可以拥有“真正的”私有属性,这在纯Python代码中几乎是不可能的)。

Python代码用来防止类实例的__dict__和随后的"任何属性都可以设置"的机制正是__slots__的属性。然而,与实际使用类时必须存在的神奇dunder方法不同,在创建类时才会使用__slots__上的信息。所以,如果你关心的是在你的最终类中有一个可见的__slots__,你可以在公开它之前把它从类中删除:

In [8]: class A:
   ...:     __slots__ = "b"
   ...:     

In [9]: del A.__slots__

In [10]: a = A()

In [11]: a.b = 5

In [12]: a.c = 5
------------------------
AttributeError   
...

In [13]: A.__slots__
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-13-68a69c802e74> in <module>()
----> 1 A.__slots__

AttributeError: type object 'A' has no attribute '__slots__'

如果您不喜欢delmyclass__slots_u;line要在声明类的任何位置都可见,它是一个单行类装饰器

def slotless(cls):
   del cls.__slots__
   return cls

@slotless
class MyClass:
   __slots__ = "x y".split()

或者,您可以使用元类来自动创建和自动销毁Python可见的__slots__,这样您就可以在类主体中声明您的描述符和属性,并保护类免受额外属性的影响:

class AttrOnly(type):
   def __new__(metacls, name, bases, namespace, **kw):
        namespace["__slots__"] = list(namespace.keys())  # not sure if "list(" is needed
        cls = super().__new__(metacls, name, bases, namespace, **kw)
        del cls.__slots__
        return cls

class MyClass(metaclass=AttrOnly):
    x = int
    y = int

如果希望纯Python只读属性在实例本身中没有可见的对应项(如\ux属性描述符使用以保持x属性的值),那么简单的方法是自定义\uuu setattr\uuuu。另一种方法是让元类在类创建阶段为每个属性自动添加只读属性。下面的元类就是这样做的,并使用\uuuu slots\uuu类属性来创建所需的描述符:

class ReadOnlyAttrs(type):
    def __new__(metacls, name, bases, namespace, **kw):
        def get_setter(attr):
            def setter(self, value):
                if getattr(self, "_initialized", False): 
                    raise ValueError("Can't set "  + attr)
                setattr(self, "_" + attr, value)
            return setter

        slots = namespace.get("__slots__", [])
        slots.append("initialized")
        def __new__(cls, *args, **kw):
            self = object.__new__(cls)  # for production code that could have an arbitrary hierarchy, this needs to be done more carefully
            for attr, value in kw.items():
                setattr(self, attr, value)
            self.initialized = True
            return self

        namespace["__new__"] = __new__
        real_slots = []
        for attr in slots:
            real_slots.append("_" + attr)
            namespace[attr] = property(
                (lambda attr: lambda self: getattr(self, "_" + attr))(attr), # Getter. Extra lambda needed to create an extra closure containing each attr
                get_setter(attr)
            )
        namespace["__slots__"] = real_slots
        cls = super().__new__(metacls, name, bases, namespace, **kw)
        del cls.__slots__
        return cls

请记住,您还可以自定义类“\uuuuu dir\uuuu方法,以便在需要时不会看到\ux阴影属性。

 类似资料:
  • 问题内容: 用Javascript将是: 但是Python中相同的语法会创建一个字典,那不是我想要的 问题答案: 有两种功能用途。

  • 本文向大家介绍JS获得一个对象的所有属性和方法实例,包括了JS获得一个对象的所有属性和方法实例的使用技巧和注意事项,需要的朋友参考一下 今天遇到一个比较棘手的问题,需要了解一个JS对象的所有属性和方法,在网上发现这段代码,帮我解决了问题,记录下来,核心代码和原理如下: 以上这篇JS获得一个对象的所有属性和方法实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持呐喊教程。

  • 问题内容: 不可变对象是否必须具有所有属性final? 据我说不是。但是我不知道我是否正确。 问题答案: 不可变对象(所有属性都是final)和有效不可变对象(属性不是final,但不能更改)之间的主要区别是安全发布。 由于Java内存模型为最终字段提供了保证,因此您可以在多线程上下文中安全地发布不可变对象,而不必担心添加同步: final字段还允许程序员无需同步即可实现线程安全的不可变对象。即使

  • 问题内容: 我在学习基本的Java课程,但遇到一个问题:仅在将有效参数传递给构造函数后,才如何创建对象? 验证完成后,我应该做一个替代类并从那里调用构造函数吗? 还是应该/应该在类中使用静态方法进行验证? 在这种情况下,最佳做法是什么? 问题答案: 标准做法是验证构造函数中的参数。例如: 旁注:要验证参数不为null(这很常见),可以使用: 更新 答复您对社会保险号的特定评论。一种方法是向类添加方

  • 考虑一个图的实现。考虑图节点的一个实现,,正确地覆盖和以镜像两个节点之间的逻辑相等。 现在,假设我们想给一个节点添加一些属性p。这样的属性绑定到节点的逻辑实例,即对于,暗示p()=p() 如果我只是将属性作为类的字段添加,则发生了以下情况: null 总结一下,当前行为: 以下所有的说法在我看来都是有道理的。没有一个能让我完全信服,所以我正在寻找基于软件工程规范的最佳实践指南。 S1-图形实现很差

  • 问题内容: 如何遍历对象的所有属性?现在,我必须编写新的代码行以打印对象的每个属性 我可以使用foreach循环或任何循环遍历对象的所有属性吗? 像这样 问题答案: 如果这仅用于调试输出,则可以使用以下内容查看所有类型和值。 如果要对输出进行更多控制,可以使用以下命令: