Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 创建一级对象,包括所有对象';s实例属性是只读的,类似于切片?_Python_Python 2.7_Metaclass_Readonly Attribute - Fatal编程技术网

Python 创建一级对象,包括所有对象';s实例属性是只读的,类似于切片?

Python 创建一级对象,包括所有对象';s实例属性是只读的,类似于切片?,python,python-2.7,metaclass,readonly-attribute,Python,Python 2.7,Metaclass,Readonly Attribute,我的问题是如何创建像slice这样的类 slice(内置类型)没有\u dict\u属性 甚至这个切片的元类也是类型 而且它没有使用\uuuuuuuuuuuuuuuuuu,并且它的所有属性都是只读的,并且它没有覆盖 \uuuuu setattr\uuuuuuuu(我对此不确定,但看看我的代码,看看我是否正确) 检查此代码: # how slice is removing the __dict__ from the class object # and the metaclass is type!

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

slice
(内置类型)没有
\u dict\u
属性 甚至这个
切片的
元类
也是
类型

而且它没有使用
\uuuuuuuuuuuuuuuuuu
,并且它的所有属性都是只读的,并且它没有覆盖
\uuuuu setattr\uuuuuuuu
(我对此不确定,但看看我的代码,看看我是否正确)

检查此代码:

# 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?!!!!
如何制作此类一级对象它的所有属性都是只读的,您无法
添加新属性。

问题在于Python内置的
切片
类是用C语言编程的。当您使用C-Python API进行编码时,您可以编写等价的属性,这些属性可以通过
\uuuuuuu插槽
访问,而无需使用Python端可见的任何机制。(您甚至可以拥有“真正的”私有属性,这在纯Python代码中几乎是不可能的)

Python代码用来防止类实例出现
\uuuuuuuuuuuuuuuuuuuu
以及后续的“可以设置任何属性”的机制就是
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu slots>属性。
但是,与实际使用该类时必须出现的magic dunder方法不同,在创建该类时才使用
\uuuuuuuuuuuuuuuu插槽
上的信息。因此,如果您关心的是在最后一个类中有一个可见的
\uuuuuuu\uuuuuu\uuuuu
,您可以在公开它之前将其从类中删除:

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__'
或者,您可以使用元类自动创建和自动销毁Python visible
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

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\uuuuu
方法,以便在需要时不会看到
\ux
阴影属性。

。。。“一级对象”是什么意思?我想你指的是内置类型。但如果你指的是不重写
setattr
或使用
\uuuuuuuuuuuuuuuuuu
,则可以创建具有相同行为的类?写一个C扩展名。或者使用
属性
或其他描述符,而不实现
\uuuuuu set\uuuuuuuu
@juanpa.arrivillaga谢谢您的评论我编辑了我的问题以消除冲突。问题是,我如何创建一个行为类似于切片的类?它实际上什么都不做,只是让
\uu插槽\uu
不可见。我之所以添加它,是因为在所创建的类中,
\uuuuuu slots\uuuuu
的“不存在”是问题中的一个问题。对不起,刚才我看到您有“Python2.7”标记。然而,上面唯一应该改变的是如何使用元类(我猜,te元类“kw”属性将是无用的);无论如何,现在研究Python 2中的高级Python功能毫无意义,我建议您更新到3.6。@jsbueno我不知道我可以从calss对象中删除插槽,因此基本上,如果class对象没有dict属性,也没有子类,您就不能向其添加新属性。我说的对吗?@jsbueno-sill这里缺少一件事:如何使该属性为只读。我认为如果不重写
\uuuu setattr\uuuu
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