为什么Python决定反对常量引用?

时间:2022-05-12 01:44:10

Note: I'm not talking about preventing the rebinding of a variable. I'm talking about preventing the modification of the memory that the variable refers to, and of any memory that can be reached from there by following the nested containers.

注意:我不是在谈论阻止重新绑定变量。我正在谈论防止变量引用的内存的修改,以及通过跟随嵌套容器可以从那里到达的任何内存。

I have a large data structure, and I want to expose it to other modules, on a read-only basis. The only way to do that in Python is to deep-copy the particular pieces I'd like to expose - prohibitively expensive in my case.

我有一个大型数据结构,我想以只读方式将其公开给其他模块。在Python中执行此操作的唯一方法是深度复制我想要公开的特定部分 - 在我的情况下非常昂贵。

I am sure this is a very common problem, and it seems like a constant reference would be the perfect solution. But I must be missing something. Perhaps constant references are hard to implement in Python. Perhaps they don't quite do what I think they do.

我确信这是一个非常普遍的问题,它似乎是一个不变的参考将是完美的解决方案。但我必须遗漏一些东西。也许在Python中很难实现常量引用。也许他们并不像我认为的那样做。

Any insights would be appreciated.

任何见解将不胜感激。


While the answers are helpful, I haven't seen a single reason why const would be either hard to implement or unworkable in Python. I guess "un-Pythonic" would also count as a valid reason, but is it really? Python does do scrambling of private instance variables (starting with __) to avoid accidental bugs, and const doesn't seem to be that different in spirit.

虽然答案很有帮助,但我还没有看到为什么const难以实现或在Python中难以实现的原因。我猜“非Pythonic”也算是一个有效的理由,但它真的吗? Python确实对私有实例变量进行了加扰(从__开始)以避免意外错误,并且const在精神上似乎没有那么不同。


EDIT: I just offered a very modest bounty. I am looking for a bit more detail about why Python ended up without const. I suspect the reason is that it's really hard to implement to work perfectly; I would like to understand why it's so hard.

编辑:我刚刚提供了一个非常适度的赏金。我正在寻找更多关于为什么Python没有const结束的细节。我怀疑原因是实施起来真的很难;我想明白为什么这么难。

5 个解决方案

#1


10  

In PEP 351, Barry Warsaw proposed a protocol for "freezing" any mutable data structure, analogous to the way that frozenset makes an immutable set. Frozen data structures would be hashable and so capable being used as keys in dictionaries.

在PEP 351中,Barry Warsaw提出了一种“冻结”任何可变数据结构的协议,类似于freezeset制作不可变集的方式。冻结的数据结构可以是可清除的,因此可以用作字典中的键。

The proposal was discussed on python-dev, with Raymond Hettinger's criticism the most detailed.

该提议在python-dev上进行了讨论,Raymond Hettinger的批评最详细。

It's not quite what you're after, but it's the closest I can find, and should give you some idea of the thinking of the Python developers on this subject.

这不是你想要的,但它是我能找到的最接近的,应该让你对Python开发人员在这个主题上的想法有所了解。

#2


13  

It's the same as with private methods: as consenting adults authors of code should agree on an interface without need of force. Because really really enforcing the contract is hard, and doing it the half-assed way leads to hackish code in abundance.

它与私有方法相同:因为同意成人的代码作者应该在不需要武力的情况下就界面达成一致。因为真正真正强制执行合同很难,并且这种半合作的方式导致了大量的hackish代码。

Use get-only descriptors, and state clearly in your documentation that these data is meant to be read only. After all, a determined coder could probably find a way to use your code in different ways you thought of anyways.

使用get-only描述符,并在文档中清楚地说明这些数据是只读的。毕竟,一个坚定的编码人员可能会找到一种方法来以不同的方式使用你的代码。

#3


8  

There are many design questions about any language, the answer to most of which is "just because". It's pretty clear that constants like this would go against the ideology of Python.

关于任何语言都有很多设计问题,其中大多数的答案都是“仅仅因为”。很明显,像这样的常量会违背Python的意识形态。


You can make a read-only class attribute, though, using descriptors. It's not trivial, but it's not very hard. The way it works is that you can make properties (things that look like attributes but call a method on access) using the property decorator; if you make a getter but not a setter property then you will get a read-only attribute. The reason for the metaclass programming is that since __init__ receives a fully-formed instance of the class, you actually can't set the attributes to what you want at this stage! Instead, you have to set them on creation of the class, which means you need a metaclass.

但是,您可以使用描述符创建只读类属性。这不是微不足道的,但并不是很难。它的工作方式是你可以使用属性装饰器创建属性(看起来像属性但在访问时调用方法的东西);如果你制作一个getter而不是setter属性,那么你将获得一个只读属性。元类编程的原因是,由于__init__接收到一个完整形式的类实例,实际上你无法在这个阶段将属性设置为你想要的!相反,您必须在创建类时设置它们,这意味着您需要一个元类。

Code from this recipe:

这个食谱的代码:

# simple read only attributes with meta-class programming

# method factory for an attribute get method
def getmethod(attrname):
    def _getmethod(self):
        return self.__readonly__[attrname]

    return _getmethod

class metaClass(type):
    def __new__(cls,classname,bases,classdict):
        readonly = classdict.get('__readonly__',{})
        for name,default in readonly.items():
            classdict[name] = property(getmethod(name))

        return type.__new__(cls,classname,bases,classdict)

class ROClass(object):
    __metaclass__ = metaClass
    __readonly__ = {'a':1,'b':'text'}


if __name__ == '__main__':
    def test1():
        t = ROClass()
        print t.a
        print t.b

    def test2():
        t = ROClass()
        t.a = 2

    test1()

#4


1  

While one programmer writing code is a consenting adult, two programmers working on the same code seldom are consenting adults. More so if they do not value the beauty of the code but them deadlines or research funds.

虽然一个编写代码的程序员是同意的成年人,但是使用相同代码的两个程序员很少同意成年人。更重要的是,如果他们不重视代码的美丽,但他们的最后期限或研究基金。

For such adults there is some type safety, provided by Enthought's Traits.

对于这样的成年人,有一些类型安全,由Enthought的特征提供。

You could look into Constant and ReadOnly traits.

您可以查看Constant和ReadOnly特征。

#5


1  

For some additional thoughts, there is a similar question posed about Java here:
Why is there no Constant feature in Java?

对于一些额外的想法,这里提出了一个类似的问题:为什么Java中没有常量功能?

When asking why Python has decided against constant references, I think it's helpful to think of how they would be implemented in the language. Should Python have some sort of special declaration, const, to create variable references that can't be changed? Why not allow variables to be declared a float/int/whatever then...these would surely help prevent programming bugs as well. While we're at it, adding class and method modifiers like protected/private/public/etc. would help enforce compile-type checking against illegal uses of these classes. ...pretty soon, we've lost the beauty, simplicity, and elegance that is Python, and we're writing code in some sort of bastard child of C++/Java.

在问为什么Python决定反对不断引用时,我认为考虑如何在语言中实现它们是有帮助的。 Python是否应该使用某种特殊声明const来创建无法更改的变量引用?为什么不允许变量被声明为float / int /那么......这些肯定有助于防止编程错误。当我们在它的时候,添加类和方法修饰符,如protected / private / public / etc.将有助于强制执行编译类型检查以防止非法使用这些类。 ...很快,我们失去了Python的美丽,简洁和优雅,我们正在用C ++ / Java的某种混蛋编写代码。

Python also currently passes everything by reference. This would be some sort of special pass-by-reference-but-flag-it-to-prevent-modification...a pretty special case (and as the Tao of Python indicates, just "un-Pythonic").

Python目前也通过引用传递所有内容。这将是某种特殊的传递参考 - 但是 - 标志 - 它要防止 - 修改...一个非常特殊的情况(并且正如Python的道所指出的那样,只是“非Pythonic”)。

As mentioned before, without actually changing the language, this type of behaviour can be implemented via classes & descriptors. It may not prevent modification from a determined hacker, but we are consenting adults. Python didn't necessarily decide against providing this as an included module ("batteries included") - there was just never enough demand for it.

如前所述,在不实际更改语言的情况下,可以通过类和描述符实现此类行为。它可能无法阻止确定的黑客进行修改,但我们同意成年人。 Python并不一定决定不将其作为一个包含的模块(“包含电池”)提供 - 对它的需求从来没有。

#1


10  

In PEP 351, Barry Warsaw proposed a protocol for "freezing" any mutable data structure, analogous to the way that frozenset makes an immutable set. Frozen data structures would be hashable and so capable being used as keys in dictionaries.

在PEP 351中,Barry Warsaw提出了一种“冻结”任何可变数据结构的协议,类似于freezeset制作不可变集的方式。冻结的数据结构可以是可清除的,因此可以用作字典中的键。

The proposal was discussed on python-dev, with Raymond Hettinger's criticism the most detailed.

该提议在python-dev上进行了讨论,Raymond Hettinger的批评最详细。

It's not quite what you're after, but it's the closest I can find, and should give you some idea of the thinking of the Python developers on this subject.

这不是你想要的,但它是我能找到的最接近的,应该让你对Python开发人员在这个主题上的想法有所了解。

#2


13  

It's the same as with private methods: as consenting adults authors of code should agree on an interface without need of force. Because really really enforcing the contract is hard, and doing it the half-assed way leads to hackish code in abundance.

它与私有方法相同:因为同意成人的代码作者应该在不需要武力的情况下就界面达成一致。因为真正真正强制执行合同很难,并且这种半合作的方式导致了大量的hackish代码。

Use get-only descriptors, and state clearly in your documentation that these data is meant to be read only. After all, a determined coder could probably find a way to use your code in different ways you thought of anyways.

使用get-only描述符,并在文档中清楚地说明这些数据是只读的。毕竟,一个坚定的编码人员可能会找到一种方法来以不同的方式使用你的代码。

#3


8  

There are many design questions about any language, the answer to most of which is "just because". It's pretty clear that constants like this would go against the ideology of Python.

关于任何语言都有很多设计问题,其中大多数的答案都是“仅仅因为”。很明显,像这样的常量会违背Python的意识形态。


You can make a read-only class attribute, though, using descriptors. It's not trivial, but it's not very hard. The way it works is that you can make properties (things that look like attributes but call a method on access) using the property decorator; if you make a getter but not a setter property then you will get a read-only attribute. The reason for the metaclass programming is that since __init__ receives a fully-formed instance of the class, you actually can't set the attributes to what you want at this stage! Instead, you have to set them on creation of the class, which means you need a metaclass.

但是,您可以使用描述符创建只读类属性。这不是微不足道的,但并不是很难。它的工作方式是你可以使用属性装饰器创建属性(看起来像属性但在访问时调用方法的东西);如果你制作一个getter而不是setter属性,那么你将获得一个只读属性。元类编程的原因是,由于__init__接收到一个完整形式的类实例,实际上你无法在这个阶段将属性设置为你想要的!相反,您必须在创建类时设置它们,这意味着您需要一个元类。

Code from this recipe:

这个食谱的代码:

# simple read only attributes with meta-class programming

# method factory for an attribute get method
def getmethod(attrname):
    def _getmethod(self):
        return self.__readonly__[attrname]

    return _getmethod

class metaClass(type):
    def __new__(cls,classname,bases,classdict):
        readonly = classdict.get('__readonly__',{})
        for name,default in readonly.items():
            classdict[name] = property(getmethod(name))

        return type.__new__(cls,classname,bases,classdict)

class ROClass(object):
    __metaclass__ = metaClass
    __readonly__ = {'a':1,'b':'text'}


if __name__ == '__main__':
    def test1():
        t = ROClass()
        print t.a
        print t.b

    def test2():
        t = ROClass()
        t.a = 2

    test1()

#4


1  

While one programmer writing code is a consenting adult, two programmers working on the same code seldom are consenting adults. More so if they do not value the beauty of the code but them deadlines or research funds.

虽然一个编写代码的程序员是同意的成年人,但是使用相同代码的两个程序员很少同意成年人。更重要的是,如果他们不重视代码的美丽,但他们的最后期限或研究基金。

For such adults there is some type safety, provided by Enthought's Traits.

对于这样的成年人,有一些类型安全,由Enthought的特征提供。

You could look into Constant and ReadOnly traits.

您可以查看Constant和ReadOnly特征。

#5


1  

For some additional thoughts, there is a similar question posed about Java here:
Why is there no Constant feature in Java?

对于一些额外的想法,这里提出了一个类似的问题:为什么Java中没有常量功能?

When asking why Python has decided against constant references, I think it's helpful to think of how they would be implemented in the language. Should Python have some sort of special declaration, const, to create variable references that can't be changed? Why not allow variables to be declared a float/int/whatever then...these would surely help prevent programming bugs as well. While we're at it, adding class and method modifiers like protected/private/public/etc. would help enforce compile-type checking against illegal uses of these classes. ...pretty soon, we've lost the beauty, simplicity, and elegance that is Python, and we're writing code in some sort of bastard child of C++/Java.

在问为什么Python决定反对不断引用时,我认为考虑如何在语言中实现它们是有帮助的。 Python是否应该使用某种特殊声明const来创建无法更改的变量引用?为什么不允许变量被声明为float / int /那么......这些肯定有助于防止编程错误。当我们在它的时候,添加类和方法修饰符,如protected / private / public / etc.将有助于强制执行编译类型检查以防止非法使用这些类。 ...很快,我们失去了Python的美丽,简洁和优雅,我们正在用C ++ / Java的某种混蛋编写代码。

Python also currently passes everything by reference. This would be some sort of special pass-by-reference-but-flag-it-to-prevent-modification...a pretty special case (and as the Tao of Python indicates, just "un-Pythonic").

Python目前也通过引用传递所有内容。这将是某种特殊的传递参考 - 但是 - 标志 - 它要防止 - 修改...一个非常特殊的情况(并且正如Python的道所指出的那样,只是“非Pythonic”)。

As mentioned before, without actually changing the language, this type of behaviour can be implemented via classes & descriptors. It may not prevent modification from a determined hacker, but we are consenting adults. Python didn't necessarily decide against providing this as an included module ("batteries included") - there was just never enough demand for it.

如前所述,在不实际更改语言的情况下,可以通过类和描述符实现此类行为。它可能无法阻止确定的黑客进行修改,但我们同意成年人。 Python并不一定决定不将其作为一个包含的模块(“包含电池”)提供 - 对它的需求从来没有。