Puis-je empêcher de modifier un objet en Python?

je veux contrôler les variables globales (ou globalement les variables scopées) d'une manière telle qu'elles ne soient définies qu'une seule fois dans le code d'initialisation du programme, et les verrouiller après cela.

j'utilise UPPER_CASE_VARIABLES pour les variables globales, mais je veux avoir un moyen sûr de ne pas changer la variable de toute façon.

  • python fournit-il cette fonctionnalité (ou une fonctionnalité similaire)?
  • Comment contrôlez-vous les variables globally scoped?
9
demandé sur prosseek 2010-09-14 22:08:31

3 réponses

Activestate a une recette intitulée constantes en Python par le vénérable Alex Martelli pour créer un module const avec des attributs qui ne peuvent pas être rebond après la création. Cela ressemble à ce que vous recherchez sauf pour l'upcasing - mais cela pourrait être ajouté en le faisant vérifier pour voir si le nom de l'attribut était tout en majuscule ou pas.

bien sûr, cela peut être contourné par la détermination, mais c'est la façon Python est - et est considéré comme une "bonne chose" par la plupart des gens. Cependant, pour rendre cela un peu plus difficile, je suggère que vous ne vous embêtiez pas à ajouter la méthode soi-disant évidente __delattr__ puisque les gens pourraient alors simplement supprimer des noms et puis les ajouter rebond en arrière à des valeurs différentes.

C'est ce que je prends au sujet de:

# Put in const.py...
# from http://code.activestate.com/recipes/65207-constants-in-python
class _const:
    class ConstError(TypeError): pass  # base exception class
    class ConstCaseError(ConstError): pass

    def __setattr__(self, name, value):
        if name in self.__dict__:
            raise self.ConstError("Can't change const.%s" % name)
        if not name.isupper():
            raise self.ConstCaseError('const name %r is not all uppercase' % name)
        self.__dict__[name] = value

# replace module entry in sys.modules[__name__] with instance of _const
# (and create additional reference to module so it's not deleted --
#  see Stack Overflow question: http://bit.ly/ff94g6)
import sys
_ref, sys.modules[__name__] = sys.modules[__name__], _const()

if __name__ == '__main__':
    import const  # test this module...

    try:
        const.Answer = 42  # not OK, mixed-case attribute name
    except const.ConstCaseError as exc:
        print(exc)
    else:  # test failed - no ConstCaseError exception generated
        raise RuntimeError("Mixed-case const names should't have been allowed!")

    const.ANSWER = 42  # should be OK, all uppercase

    try:
        const.ANSWER = 17  # not OK, attempts to change defined constant
    except const.ConstError as exc:
        print(exc)
    else:  # test failed - no ConstError exception generated
        raise RuntimeError("Shouldn't have been able to change const attribute!")

sortie:

const name 'Answer' is not all uppercase
Can't change const.ANSWER
11
répondu martineau 2014-06-07 15:49:35

Python est un langage très ouvert et ne contient pas de mot-clé final . Python vous donne plus de liberté pour faire les choses et suppose que vous savez comment les choses devraient fonctionner. Par conséquent, il est supposé que les personnes qui utilisent votre code sauront que SOME_CONSTANT ne devrait pas se voir attribuer une valeur à un point quelconque du code.

Si vous voulez, vous pouvez placer la constante à l'intérieur d'une fonction get.

def getConstant()
  return "SOME_VALUE"
6
répondu unholysampler 2016-07-18 11:15:11

vous pouvez envelopper vos variables globales dans un objet et outrepasser l'objet.__setattr__ méthode. Vous pouvez alors empêcher de définir des attributs qui sont déjà définis. Cependant, cela ne concerne pas les objets complexes qui sont passés par référence. Vous devez faire des copies superficielles/profondes de ces objets pour être absolument sûr qu'ils ne peuvent pas être modifiés. Si vous utilisez de nouvelles classes de style, vous pouvez outrepasser object.__getattribute__(self, nom) pour faire les copies.

class State(object):
    def __init__(self):
        pass

    def __setattr__(self, name, value):
        if name not in self.__dict__:
            self.__dict__[name] = value

* * Je ne m'inquiète généralement pas tellement si quelqu'un va essayer vraiment fort de briser mon code. Je trouve que dépasser _ _ setattr__ est suffisant (surtout si vous lancez une exception) pour avertir quiconque joue avec le code que le but de l'État doit être lu seulement. Si quelqu'un ressent encore le besoin de modifier l'État, alors quel que soit le comportement indéfini qu'il rencontre, ce n'est pas ma faute.

2
répondu GWW 2010-09-14 18:34:21