不关心python的值
omitted的Python项目详细描述
a不关心python的值
让我们谈谈夸尔格
这很容易被认为是理所当然的,但是python最优雅的方面之一 是它对函数关键字参数(kwargs)的处理。这个构造 提供:
- A way to specify parameters without having to know its position in the argument list
- Automatic checking of expected parameters
- An elegant way to specify parameter defaults
- A meaningful, self-documenting function signature
大多数时候,夸尔格语都是完美无瑕的;但也有少数情况下 它们的使用变得棘手。
我要谈谈这个问题,展示一个常见的反模式 尝试修复它,然后提出一种保留所有 以引入新概念为代价的上述好处 python,Omittedsingleton。
问题,什么问题?
让我们从一个例子开始。假设有一个函数 允许您更新此人的姓名、年龄、两者或两者都不更新。 天真地说,您可以将该函数编写为类似于:
def update(person, name=None, age=None): person.name = name person.age = age
现在我们调用此函数,但只更新此人的年龄:
> person = Person(name='Alice', age=32) > update(person, age=33) > person.age 33 > person.name None
注意,代码正确地设置了年龄,但是,从调用方的 从角度看,还可以将名称设置为None。不是我们想要的。
这里的问题是None不能同时用于表示有效值 同时我们也代表了一种不在乎的状态。
意识到我们需要一种区分这两种情况的方法,我们修改了 稍微编码:
def update(person, **kwargs): for k, v in kwargs.items(): setattr(person, k, v)
在这里,我们使用在夸尔格字典中存在或不存在的键来 表示不关心条件,None的值被单独保留 用于实际将属性设置为None(非常合理,是吗?).
让我们再次调用这个新版本的update:
> person = Person(name='Alice', age=32) > update(person, age=33) > person.age 33 > person.name 'Alice'
这个方法的表现和我们预期的完全一样。根据我的经验,很多 开发人员停在这里是因为它工作正常。但代价是:我们没有 长久以来,人们一直期待着夸格检查(优点2),而不是优雅的设置方式 默认参数(benefit 3),我们失去了有意义的函数 签名(利益4)。基于这些原因,我认为这是一种反模式 提出不同的方法。
不再有
为了保留显式kwargs的好处,我们需要一种方法来获取 区分不关心条件和有效条件的关键字 价值。如上所述,None不够好,因为None是 对许多属性来说都是非常合理的值。
相反,我们需要创建一个新值,一个像None这样的单例 表示这种情况,我称之为Omitted。有了它,我们的功能变成:
Omitted = object() def update(person, name=Omitted, age=Omitted): if name is not Omitted: person.name = name if age is not Omitted: person.age = age
我们最终得到的代码与调用时的预期行为完全相同,但是 保留显式Kwargs的优点:
update(person, age=33) # Just set the age to 33 update(person, name=None) # Set the name to None update(person) # Doesn't update any attributes update(person, foo=bar) # Raises a TypeError because foo isn't an # expected kwargs (benefit #2)
有什么发现?
所以,解决我们的默认Kwarg问题,我们已经发布了 包含update函数的库。现在假设有人来了 想用我们的图书馆。首先,他们会感谢我们 显式kwargs的用法-一旦它们通过不寻常的外观Omitted 默认值。
但是,当他们使用它时,他们可能会做如下操作:
Omitted = object() def update_with_email(person, name=Omitted, age=Omitted): update(person, name=name, age=age) send_email(person) > person = Person(name='Alice', age=32) > update_with_email(age=33) > person.age 33 > person.name <object object at 0x105ae2080>
如您所见,person.name以值Omitted结束。这个 这里的问题是调用方的Omitted实例不同于 库Omitted实例,因此它们不会进行相同的比较。
我们想要的是定义一个表示 这并不关心所有python包中的条件,就像 None无论在哪里使用都是相同的。
介绍…
这个python模块旨在通过定义 Omitted实例,可在系统上的所有包之间共享。
要清楚,仅仅因为库使用Omitted,并不意味着 调用代码也必须如此。不传递Kwarg或将其设置为Nonewill 表现C正确地说,不必知道Omitted是在 让它发挥作用的场景。
调用方需要导入Omitted的唯一时间是 将调用方的“不关心”条件代理到库中。在那里面 凯斯,你只需要做如下事情:
from libperson import update from omitted import Omitted def update_with_email(person, name=Omitted, age=Omitted): update(person, name=name, age=age) send_email(person)
考虑到这一点,继续导入Omitted,让您的代码停止关心。