定义我自己的非类似Python常量

Lar*_*tig 4 python singleton constants

我有一种情况需要从各种来源读取数据库更新指令的集合.所有源都将包含主键值,以便将更新应用于数据库的代码可以找到正确的记录.但是,报告的其他列中的文件会有所不同.

当我阅读并创建更新指令时,我必须区分一个更新,其中提供了一个列(例如,MiddleName)但是为空(意味着没有中间名,字段应该更新为NULL)和更新中的MiddleName字段未包含在内(意味着更新不应触及中间名称列).

前一种情况(提供的列但没有值)似乎适当地由None值表示.然而,对于第二种情况,我想要一个NotInFile "值",我可以使用类似于我使用None的方式.

是否正确实现此方法如下?

NotInFile = 1

class PersonUpdate(object):

     def __init__(self):

         self.PersonID = None
         self.FirstName = NotInFile
         self.MiddleName = NotInFile
Run Code Online (Sandbox Code Playgroud)

然后在另一个模块中

import othermod
upd = othermod.PersonUpdate()
if upd.MiddleName is othermod.NotInFile:
    print 'Hey, middle name was not supplied'
Run Code Online (Sandbox Code Playgroud)

mgi*_*son 8

我没有看到你的实施有什么特别的错误.但是,1它不一定是最好的sentinel值,因为它是Cpython中的缓存常量.(例如-1+2 is 1将返回True).在这些情况下,我可能会考虑使用sentinel对象实例:

NotInFile = object()
Run Code Online (Sandbox Code Playgroud)

蟒蛇也提供了一些其他的命名常量,其如果它似乎合适,你可以使用: NotImplementedEllipsis立即浮现在脑海中.(注意,我不建议你使用这些常量......我只是提供更多选项).


小智 6

不,使用整数是一个坏主意.在这种情况下,如果MiddleName它总是一个字符串或者None,它可能会有效,但一般来说,实现可以随意使用实习生整数,字符串,元组和其他不可变值.CPython用于上述类型的小整数和常量.PyPy is通过整数和一些其他类型的值定义.因此,如果MiddleName为1,您必然会看到您的代码认为它未提供.

使用一个object代替,每一个新的对象都有一个独特的身份:

NotInFile = object()
Run Code Online (Sandbox Code Playgroud)

或者,为了更好地调试输出,请定义自己的类:

class NotInFileType(object):
    # __slots__ = () if you want to save a few bytes
    def __repr__(self):
        return 'NotInFile'

NotInFile = NotInFileType()
del NotInFileType # look ma, no singleton
Run Code Online (Sandbox Code Playgroud)

如果你是偏执狂,你可以把它变成一个合适的单身人士(丑陋).如果您需要多个这样的实例,可以将类重命名为Sentiel或者某种东西,使表示形式成为实例变量并使用多个实例.


Noé*_*ein 6

如果您想要类型检查,这个习惯用法现在受到 PEP 484 的祝福得到 mypy 的支持

from enum import Enum

class NotInFileType(Enum):
    _token = 0

NotInFile = NotInFileType._token
Run Code Online (Sandbox Code Playgroud)

如果您使用的是 mypy 0.740 或更早版本,则需要使用 Typing.Final 来解决mypy 中的此错误:

from typing import Final

NotInFile: Final = NotInFileType._token
Run Code Online (Sandbox Code Playgroud)

如果您使用的是 Python 3.7 或更早版本,则可以使用typing_extensions.Finalpip 包typing_extensions而不是typing.Final