【问题标题】:Keywords in python that evaluate to themselvespython中对自己进行评估的关键字
【发布时间】:2020-08-09 13:41:44
【问题描述】:

Clojure 中有一个关键字的概念,您可以通过在您要作为关键字处理的单词前面添加一个冒号来定义它们。此外,它对自身进行评估。例如:

:my-keyword 
;=> :my-keyword

有没有办法通过定义一些自定义类或任何解决方法在 python 中实现这一点?

这样做的原因是有更多的自描述参数(字符串在那里,但在传递时无法跟踪是否有一致的字符串)。

一个实际的用例是这样的:

def area(polygon_type):
  return \
  {
    "square": lambda side: (side * side),
    "triangle": lambda base, height: (0.5 * base * height)
  }[polygon_type]

area("square")(2) # ==> 4

但是,如果处理不当,以这种方式使用字符串会导致运行时出错。但是在任何 IDE 中都有类似关键字的东西,甚至是自动完成功能,这表明在传递 polygon_type 时所犯的错误。

area("Sqaure")(2) # would lead to a KeyError

python 中是否有一些我不知道的功能可以解决这类问题? 如果没有,有人会如何解决这个问题?

编辑: 我并不是特别想解决拥有这样一个功能的问题;而是寻找一种在 python 中实现 keyword 概念的方法。因为,对于枚举,我必须捆绑并在某个类别下明确定义它们(在本例中为 polygon_type

【问题讨论】:

  • 使用 clojure 并使用子进程来运行你的 python。这样做不太明智。
  • 您是否在询问 python 是否可以找到并解决您代码中的拼写错误?
  • 你可以使用枚举。您可以使用类型提示。 IDE 可能会检查这类事情。
  • @khelwood 不完全是。因为使用枚举,我必须将上面示例中的术语捆绑到一个名为 PolygonType 的单个枚举类中。然后将它们用作 PolygonType.square 和 PolygonType.triangle。还必须将 PolygonType 导入我使用它们的每个模块中;这是不可取的。
  • 如果你想要一个函数area(polygon_type),它只有有限数量的精确值是有效的,并且你想要一个能够检查你的代码的工具,看看你是否试图通过它是一个无效的值,枚举和/或类型提示似乎符合该要求。另一方面,如果您真正想要的是以与编写另一种语言完全相同的方式编写 Python,那么您的方法是错误的。

标签: python clojure keyword abstract-data-type


【解决方案1】:

Clojure 中的关键字是interned strings,Clojure 为它们提供了特殊的语法支持。我建议你看看how they are implemented。看起来像Python does some interning of its strings,但我不太了解它的细节。

使用关键字的重点是快速比较和地图查找。虽然我不确定你会如何从中受益,但你可以尝试使用字符串实习在 Python 中实现自己的关键字对象,如下所示:

str2kwd = {}

class Keyword:
    def __init__(self, s):
        self.s = s
        
    def __repr__(self):
        return str(self)
    
    def __str__(self):
        return ":" + self.s

def kwd(s):
    """Construct a keyword"""
    k = str2kwd.get(s)
    if k is None:
        k = Keyword(s)
        str2kwd[s] = k
    return k

只要你想构造一个关键字,你就调用kwd 函数。对于 Keyword 类,我们依赖默认的相等和散列方法。然后你可以这样使用它:

>>> kwd("a")
:a
>>> kwd("a") == kwd("a")
True
>>> kwd("b") == kwd("a")
False
>>> kwd_a = kwd("a")
>>> kwd_b = kwd("b")
>>> {kwd_a: 3, kwd_b: 4}
{:a: 3, :b: 4}
>>> {kwd_a: 3, kwd_b: 4}[kwd_a]
3

但是,我没有衡量这是否会导致比仅使用常规 Python 字符串更快的比较和地图查找,这可能是 Python 最惯用的选择。我怀疑你会看到使用这个自制关键字类的性能有显着改善。另请注意,最好在模块的顶层调用kwd 函数并将其分配给您使用的变量,而不是每次需要关键字时调用kwd。显然,你不会有 Clojure 中的特殊关键字语法。

更新:如何避免拼写错误

如果您担心地图中的键拼写错误,您可以将键分配给局部变量并使用这些局部变量而不是直接使用键值。这样,如果您拼写错误的局部变量名称,您可能会很快收到错误,因为您指的是不存在的局部变量。

>>> kwd_square = "square"
>>> kwd_triangle = "triangle"
>>> m = {kwd_square: 3, kwd_triangle: 4}
>>> m[kwd_square]
3
>>> m[Square]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'Square' is not defined

【讨论】:

  • 但是在跨模块使用这些关键字时,必须明确导入“关键字”,或者在单独的模块中预先定义所有关键字并根据需要导入它们;这不符合 Clojure 的“关键字”的想法。但这无论如何都消除了我的疑问:)
  • 在我看来,您确实需要两件事:(i) 如何在 Python 中实现关键字之类的东西,以及 (ii) 如何避免与拼写错误相关的错误。关于 (ii),Clojure 中的键拼写错误的可能性与 Python 中的拼写相同:如果您的映射是 {:square 3, :triangle 4},那么您可能会错误地使用键 :Square 而不是键 :square 来获取值 3。Clojure 不提供任何额外的保护来防止犯此错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-13
  • 1970-01-01
  • 2015-09-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多