Django:鸭子打字友好的方式接受记录或slug记录的输入

Jor*_*ter 1 django duck-typing

我有这样的功能:

def foo(bar):
    ...
Run Code Online (Sandbox Code Playgroud)

现在bar既可以是Django记录,也可以是指向记录的slug.我需要这种灵活性,这样我就可以在手边有实际记录时调用此函数,或者从一个更通用的函数调用它,该函数只有一个字符串可用作为字符串(从数据库中提取).

我意识到我可以这样做:

def foo(bar):
    try:
        bar.pk
    except AttributeError:
        bar = Bar.objects.get(slug=bar)
    ...
Run Code Online (Sandbox Code Playgroud)

但是,这似乎并没有优雅可言.

如果我可以,我想避免使用isinstance.

Joh*_*ohn 5

根据定义,您不使用Duck Typing.鸭子打字说"如果它像鸭子一样说话,看起来像鸭子,那就是鸭子."

Duck Typing意味着你可以将两个完全不同的类的对象传递给方法,并让它工作,因为它们都实现相同的方法/属性(或优雅地处理缺失的方法/属性).这意味着该方法从不关心它获取的类型,只是您传递的任何对象都具有它期望使用的属性.

在您的情况下,您希望有时传递一个对象和一个可用于在其他时间查找所述对象的字符串.这与Duck Typing无关.

isinstance是解决这个问题的正确方法.在这种情况下,这是解决问题的最明确方法,其他任何事情都会变得更复杂,更难理解有0个好处.您可以在属性或hasattr上使用try/except,但这可能会让任何未来的开发人员比其他任何事情更困惑.Duck Typing非常棒,它取代了各种子类以匹配某些特定的功能,但在这种情况下鸭子类型不适用.

简而言之.只需使用isinstance.对于你的情况,这是正确的(pythonic)方式.

  • 刚刚检查了`django.db.models.fields.related`,它使用`isinstance`来验证外键分配.感谢John以这种方式解释Duck Typing,它将帮助我区分各种各样的`isinstance`-avoiders.我很难理解为什么这对这种情况有利并且你已经清除了这一点. (2认同)