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

时间:2013-06-24 14:22:11

标签: python constants

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

当我阅读并创建我的更新说明时,我必须区分提供了一个列(例如,MiddleName)但是为空(意味着没有中间名并且该字段应该更新为NULL)的更新以及更新其中没有包含MiddleName字段(意味着更新不应该触及中间名列)。

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

实现此方法的正确方法如下:

NotInFile = 1

class PersonUpdate(object):

     def __init__(self):

         self.PersonID = None
         self.FirstName = NotInFile
         self.MiddleName = NotInFile

然后在另一个模块中

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

3 个答案:

答案 0 :(得分:8)

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

NotInFile = object()

python还提供了一些其他命名常量,如果合适,您可以使用它们:NotImplementedEllipsis立即浮现在脑海中。 (请注意,我不建议您使用这些常量......我只是提供更多选项)。

答案 1 :(得分:6)

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

使用object代替,每个新对象都有不同的标识:

NotInFile = object()

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

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

如果你是偏执狂,你可以把它变成一个合适的单身人士(丑陋)。如果您需要多个此类实例,可以将该类重命名为Sentiel或其他内容,使表示形式为实例变量并使用多个实例。

答案 2 :(得分:1)

如果您要进行类型检查,则该习惯用法现在为blessed by PEP 484supported by mypy

from enum import Enum

class NotInFileType(Enum):
    _token = 0

NotInFile = NotInFileType._token

如果您使用的是mypy 0.740或更早的版本,则需要使用打字方法来解决this bug in mypy。最终:

from typing import Final

NotInFile: Final = NotInFileType._token

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