代码之家  ›  专栏  ›  技术社区  ›  Jason Coon

`Python中变量的final`关键字等价物?

  •  42
  • Jason Coon  · 技术社区  · 17 年前

    final

    我正在创建一个对象的快照(如果出现任何故障,则用于恢复);一旦分配了这个备份变量,就不应该对其进行修改——Python中的最后一个类似于的特性将非常适合这种情况。

    9 回复  |  直到 17 年前
        1
  •  71
  •   Eli Courtwright    17 年前

    在Java中有一个变量 final

    public final List<String> messages = new LinkedList<String>();
    
    public void addMessage()
    {
        messages.add("Hello World!");  // this mutates the messages list
    }
    

    但以下内容甚至无法编译:

    public final List<String> messages = new LinkedList<String>();
    
    public void changeMessages()
    {
        messages = new ArrayList<String>();  // can't change a final variable
    }
    

    所以你的问题是关于 最终的 存在于Python中。事实并非如此。

    list ,你不能使基因突变 tuple . 你可以变异一个基因 set frozenset

    我的建议是,不要担心在语言级别强制执行非变异,只需专注于确保您不会编写任何在分配这些对象后对其进行变异的代码。

        2
  •  70
  •   Josh Correia sgargan    6 年前

    没有 final 在Python中是等效的。

    但是,要创建类实例的只读字段,可以使用 property

    编辑 :也许你想要这样的东西:

    class WriteOnceReadWhenever:
        def __setattr__(self, attr, value):
            if hasattr(self, attr):
                raise Exception("Attempting to alter read-only value")
    
            self.__dict__[attr] = value
    
        3
  •  42
  •   congusbongus piRSquared    6 年前

    Python 3.8 PEP 591 )加上 Final 变量、函数、方法和类。以下是一些使用方法:

    @final 装饰器(类、方法)

    from typing import final
    
    @final
    class Base:
        # Cannot inherit from Base
    
    class Base:
        @final
        def foo(self):
            # Cannot override foo in subclass
    

    最终的

    from typing import Final
    
    PI: Final[float] = 3.14159     # Cannot set PI to another value
    KM_IN_MILES: Final = 0.621371  # Type annotation is optional
    
    class Foo:
        def __init__(self):
            self.bar: Final = "baz"   # Final instance attributes only allowed in __init__
    

    请注意,与其他类型提示一样,这些提示并不阻止您重写类型,但它们确实有助于linters或IDEs警告您错误的类型用法。

        4
  •  9
  •   Jackson H    6 年前

    class OnePingOnlyPleaseVassily(object):
        def __init__(self):
            self.value = None
        def set(self, value):
            if self.value is not None:
                raise Exception("Already set.")
            self.value = value
    
    someStateMemo = OnePingOnlyPleaseVassily()
    someStateMemo.set(aValue) # works
    someStateMemo.set(aValue) # fails
    

    这很笨拙,但它会在运行时检测设计问题。

        5
  •  7
  •   millimoose Tomasz Nurkiewicz    17 年前

    我想,您可以通过对模型的相关部分使用元组或命名元组来解决这一问题,它们本质上是不可变的。当然,这对于模型中必须可变的任何部分都没有帮助。

        6
  •  6
  •   RichieHindle    17 年前

    Python没有“final”的等价物。它也没有“public”和“protected”,除了命名约定之外。这不是“束缚和纪律”。

        7
  •  6
  •   UncleZeiv    17 年前

    您可以通过 descriptor protocol

    class Foo(object):
    
      @property
      def myvar(self):
         # return value here
    
      @myvar.setter
      def myvar(self, newvalue):
         # do nothing if some condition is met
    
    a = Foo()
    print a.myvar
    a.myvar = 5 # does nothing if you don't want to
    
        8
  •  5
  •   antonagestam Maxim Suslov    7 年前

    截至2019年和 PEP 591 ,Python有一个 Final 类型在Python3.8发布之前,它不会出现在标准库中,但在此之前,您可以通过 typing-extensions 图书馆它不会像以前那样工作 final mypy 它会给你带来非常相似的好处。

    最终的

        9
  •  3
  •   cobbal    17 年前

    http://code.activestate.com/recipes/576527/ 定义一个冻结函数,尽管它不能完美地工作。

        10
  •  1
  •   user2799096    8 年前

    Python确实没有最终的类型,它有不可变的类型,比如元组,但这是另外一回事。

    这里的一些其他答案使类充满伪final变量,我更喜欢我的类只有几个final类型,因此我建议使用描述符创建final类型:

    from typing import TypeVar, Generic, Type
    
    T = TypeVar('T')
    
    class FinalProperty(Generic[T]):
        def __init__(self, value: T):
            self.__value = value
        def __get__(self, instance: Type, owner) -> T:
            return self.__value
        def __set__(self, instance: Type, value: T) -> None:
            raise ValueError("Final types can't be set")
    

    如果您这样使用此类:

    class SomeJob:
        FAILED = FinalProperty[str]("Failed")
    

    不幸的是,与WriteOnCeradAnwhere答案一样,您仍然可以设置类变量。

    job = SomeJob()
    job.FAILED = "Error, this will trigger the ValueError"
    SomeJob.FAILED = "However this still works and breaks the protection afterwards"
    
        11
  •  0
  •   Friendly King    13 年前

    虽然这是一个老问题,但我想我会添加另一个潜在选项:您也可以使用 assert final 在Java中,它可以用来创建类似的效果:

    PI = 3.14
    radius = 3
    
    try:
        assert PI == 3.14
        print PI * radius**2
    except AssertionError:
        print "Yikes."
    

    如上所述,如果 PI 3.14 AssertionError try/except block可能是一个明智的加法。不管怎样,它可能会根据你的情况派上用场。

    推荐文章