”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 动态语言中静态类型的讽刺

动态语言中静态类型的讽刺

发布于2024-11-07
浏览:391

您还可以在 Medium 上阅读这篇文章。

当我们看到编程语言如何随着时间的推移而演变时,总是很有趣。

曾几何时,当我开始进入软件开发世界时,Python、PHP 和 JavaScript 等动态语言因其灵活性和适合快速开发的简洁语法而受到赞赏。

然而,随着这些弱类型语言的发展,它们融合了强类型语言的特性,使它们与 C 和 Java 非常相似:

  • Python:从 2015 年版本 3.5 开始引入类型提示功能,并在 2022 年版本 3.12 中得到增强。
  • PHP:2015 年版本 7 中引入的声明类型。
  • JavaScript:通过 2012 年 TypeScript 的发布进行了扩展,定义为“具有类型语法的 JavaScript”。

为什么会有这样的转变?

在严格类型语言中,我们在代码中显式定义变量的类型。目标是在执行程序之前捕获开发阶段的错误,并向编译器提供有关分配给这些变量的内存大小的提示。

// C   example: 'y' will be an integer
float x = 3.14;
int y = x;  //  y = 3 (ignored the decimal part of the number)

另一方面,动态类型语言(例如 Python、PHP 和 JavaScript)允许我们创建变量并让解释器在运行时暗示它们的类型:

# In python and PHP: 'y' will take the same type as 'x'
x = 3.14
y = x  // y = 3.14 (float)

动态语言中如何引入显式类型?

在下面的示例中,我们使用动态和静态类型声明相同的函数。

Python:

# using the classic syntax:
def add(x, y):
    return x   y
# using explicit typing:
def add(x: int, y:int) -> int:
    return x   y

JavaScript / TypeScript:

// using the classic syntax
function add(x, y) {
    return x   y;
}
// using explicit typing
function add(x: number, y: number): number {
    return x   y;
}

PHP:

// using the classic syntax:
function add($x, $y) {
    return $x   $y;
}
// using explicit typing:
function add(int $x, int $y): int {
    return $x   $y;
}

PHP 8.2(于 2022 年 12 月发布)通过引入对 null、true 和 false 作为独立类型的支持来进一步推动它:

public null $nil = null;
public false $false = false;`

讽刺在哪里?

不要将这篇文章视为对这些新功能的反对,我确实承认使用严格类型语言的优势。然而,例如,在 Python 中使用类型注释并不能阻止您更改变量的类型:

x: int = 0
x = "John" 
print(type(x))   # 

PHP 也一样,它只会在控制台上打印 Deprecated 警告。

有人可能会问为什么解释器允许我们执行这段代码?
这是因为这些语言是这样构建的:它们根据定义是动态类型的。如果我们删除这个特性,它们将不再是动态的;它们将成为像 C 一样的严格类型语言,但速度较慢。

希望您可以通过在 PHP 文件中将 strict_types 设置为 true 来要求您的解释器更加严格:

declare(strict_types=1);

在Python中,您可以使用“mypy”包来分析代码并捕获错误:

$ mypy program.py
error: Incompatible types in assignment (expression has type "str", variable has type "int")  [assignment]

您可以将“mypy”视为顾问,告诉您做错了什么,但这并不能阻止您自行承担风险执行代码。

The Irony of Static Typing in Dynamic Languages

即使您不确定变量的类型,您仍然可以使用联合运算符来减少接受类型的列表:

以下来自 PHP 和 Python 的示例展示了如何执行此操作:

y: int | float = f(x)   # introduced in Python 3.10
int | float $y = f($x)  // introduced in PHP 8.0
let y: number | string  // typescript

我们是否牺牲了代码的可读性?

十年前,我决定使用 Python 攻读博士学位,因为它简单且能够快速构建新想法原型。然后我也开始将它用于我的其他项目。

现在,我发现自己阅读了一些奇怪的 PEP,并质疑自己是否真的值得通过包含这些新功能来使我的代码库复杂化。

让我们看一个打印字典项目的示例函数。这是最初的版本:

def print_attributes(**kwargs):
    for key, value in kwargs.items():
        print(key, value)

person = {"name": "John", "height": 1.84}
print_attributes(**person)

通过使用Python 3.12中引入的PEP 692的建议,代码变为:

from typing import TypedDict, Unpack

class Person(TypedDict):   # create a class inheriting from TypedDict
    name: str                  
    height: float           

def print_attributes(**kwargs: Unpack[Person]) -> None:  # use the Unpack operator
    for key, value in kwargs.items():
        print(key, value)

person: Person = {"name": "John", "height": 1.84}  # create an instance of the class
print_attributes(**person)

总结:我们创建了一个继承自 TypedDict 的类,指定了每个项目的名称和类型,并使用 Unpack 运算符告诉“mypy”接收到的对象是 TypedDict。

结果,我们的代码大小增加了一倍。如果我们的对象有更多的项目,它会变得更长。

幸运的是,我们可以对代码的某些部分使用静态类型,而将其余部分保留为动态类型。或者,如果我们愿意,我们可以选择根本不使用它。

The Irony of Static Typing in Dynamic Languages

我们什么时候应该使用它?

不要因为学到了一个新的、闪亮的功能而感到有重写整个代码库的压力。

这些新功能就像工具。我的建议是明智地使用它们:

在以下场景中使用静态类型:

  • 从外部源(例如数据库、库和 API)检索数据时。
  • 在代码的关键部分不允许失败。
  • 当您的代码库容易出现频繁错误时。

在以下情况下避免使用静态类型:

  • 设计原型以快速测试您的想法。
  • 实现内部逻辑,其中类型检查只会导致冗长的代码,没有任何好处。
  • 仅在屏幕上显示数据(例如绘制图表、图像、数字......)。
  • 编写没有用户输入的命令行脚本。

请记住,在编码方面,黄金法则始终是力求简单,除非您有充分的理由使事情复杂化。

版本声明 本文转载于:https://dev.to/aminehorseman/the-irony-of-static-typing-in-dynamic-languages-31g1?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 如何使用Java.net.urlConnection和Multipart/form-data编码使用其他参数上传文件?
    如何使用Java.net.urlConnection和Multipart/form-data编码使用其他参数上传文件?
    使用http request 上传文件上传到http server,同时也提交其他参数,java.net.net.urlconnection and Multipart/form-data Encoding是普遍的。 Here's a breakdown of the process:Mu...
    编程 发布于2025-04-15
  • 如何使用Depimal.parse()中的指数表示法中的数字?
    如何使用Depimal.parse()中的指数表示法中的数字?
    在尝试使用Decimal.parse(“ 1.2345e-02”中的指数符号表示法时,您可能会出现错误。这是因为默认解析方法无法识别指数符号。 成功解析这样的字符串,您需要明确指定它代表浮点数。您可以使用numbersTyles.Float样式进行此操作,如下所示:[&& && && &&华氏度D...
    编程 发布于2025-04-15
  • 如何使用Python有效地以相反顺序读取大型文件?
    如何使用Python有效地以相反顺序读取大型文件?
    在python 中,如果您使用一个大文件,并且需要从最后一行读取其内容,则在第一行到第一行,Python的内置功能可能不合适。这是解决此任务的有效解决方案:反向行读取器生成器 == ord('\ n'): 缓冲区=缓冲区[:-1] ...
    编程 发布于2025-04-15
  • 我可以将加密从McRypt迁移到OpenSSL,并使用OpenSSL迁移MCRYPT加密数据?
    我可以将加密从McRypt迁移到OpenSSL,并使用OpenSSL迁移MCRYPT加密数据?
    将我的加密库从mcrypt升级到openssl 问题:是否可以将我的加密库从McRypt升级到OpenSSL?如果是这样,如何?答案:是的,可以将您的Encryption库从McRypt升级到OpenSSL。可以使用openssl。附加说明: [openssl_decrypt()函数要求iv参...
    编程 发布于2025-04-15
  • CORS在我的PHP应用中为何不起作用?
    CORS在我的PHP应用中为何不起作用?
    cross cross-origin Resource共享(CORS)中不起作用的CORS,网页可以从另一个原点请求资源,通常涉及不同的域,端口,端口或协议。但是,默认情况下,浏览器由于安全问题而限制了此类请求。在给定方案中,用户正在尝试使用cors从www.siteone.com尝试从www....
    编程 发布于2025-04-15
  • 如何使用不同数量列的联合数据库表?
    如何使用不同数量列的联合数据库表?
    合并列数不同的表 当尝试合并列数不同的数据库表时,可能会遇到挑战。一种直接的方法是在列数较少的表中,为缺失的列追加空值。 例如,考虑两个表,表 A 和表 B,其中表 A 的列数多于表 B。为了合并这些表,同时处理表 B 中缺失的列,请按照以下步骤操作: 确定表 B 中缺失的列,并将它们添加到表的末...
    编程 发布于2025-04-15
  • 使用jQuery如何有效修改":after"伪元素的CSS属性?
    使用jQuery如何有效修改":after"伪元素的CSS属性?
    在jquery中了解伪元素的限制:访问“ selector 尝试修改“:”选择器的CSS属性时,您可能会遇到困难。 This is because pseudo-elements are not part of the DOM (Document Object Model) and are th...
    编程 发布于2025-04-15
  • 哪种方法更有效地用于点 - 填点检测:射线跟踪或matplotlib \的路径contains_points?
    哪种方法更有效地用于点 - 填点检测:射线跟踪或matplotlib \的路径contains_points?
    在Python Matplotlib's path.contains_points FunctionMatplotlib's path.contains_points function employs a path object to represent the polygon.它...
    编程 发布于2025-04-15
  • 哪种在JavaScript中声明多个变量的方法更可维护?
    哪种在JavaScript中声明多个变量的方法更可维护?
    在JavaScript中声明多个变量:探索两个方法在JavaScript中,开发人员经常遇到需要声明多个变量的需要。对此的两种常见方法是:在单独的行上声明每个变量: 当涉及性能时,这两种方法本质上都是等效的。但是,可维护性可能会有所不同。 第一个方法被认为更易于维护。每个声明都是其自己的语句,使其...
    编程 发布于2025-04-15
  • 切换到MySQLi后CodeIgniter连接MySQL数据库失败原因
    切换到MySQLi后CodeIgniter连接MySQL数据库失败原因
    无法连接到mySQL数据库:故障排除错误消息要调试问题,建议将以下代码添加到文件的末尾.//config/database.php并查看输出: ... ... 回声'... echo '<pre>'; print_r($db['default']); echo '</pr...
    编程 发布于2025-04-15
  • input: How Can I Construct Objects Using `std::malloc`?

output: 使用`std::malloc`构造对象的正确姿势
    input: How Can I Construct Objects Using `std::malloc`? output: 使用`std::malloc`构造对象的正确姿势
    malloc and构造函数:探索指南,标准库同时提供std :: malloc and Malloc and New Expressions。尽管新的方便地通过构造函数初始化对象,但std :: malloc却没有。这提出了一个问题:我们如何创建一个对象并确保使用std :: malloc?一...
    编程 发布于2025-04-15
  • 使用PHP的`mail()`和PEAR Mail确保UTF-8邮件编码正确的方法
    使用PHP的`mail()`和PEAR Mail确保UTF-8邮件编码正确的方法
    发送utf-8电子邮件在发送电子邮件时,这对于处理正确编码的字符至关重要,以避免gropled字符。一个常见的问题是编码非英语字符,例如用各种语言使用的字符。在提供的方案中,发送者面临着发送电子邮件后出现不可读取文本的问题的问题。尽管添加了内容类型和Charset标题,但问题仍然存在。要纠正此问题...
    编程 发布于2025-04-15
  • 如何将PANDAS DataFrame列转换为DateTime格式并按日期过滤?
    如何将PANDAS DataFrame列转换为DateTime格式并按日期过滤?
    Transform Pandas DataFrame Column to DateTime FormatScenario:Data within a Pandas DataFrame often exists in various formats, including strings.使用时间数据时...
    编程 发布于2025-04-15
  • MySQL查询数据修改成功的可靠方法
    MySQL查询数据修改成功的可靠方法
    测试mysql查询的成功:修改数据库表数据在执行数据库操作时,验证查询的成功至关重要。本文探讨了如何确定MySQL查询是否已在数据库表中成功修改了数据。考虑以下用于从数据库中删除文章的php代码shippet: if($ cmd == ==“ deleterec”){ $ deletequ...
    编程 发布于2025-04-15
  • 您可以使用CSS在Chrome和Firefox中染色控制台输出吗?
    您可以使用CSS在Chrome和Firefox中染色控制台输出吗?
    在javascript console 中显示颜色是可以使用chrome的控制台显示彩色文本,例如红色的redors,for for for for错误消息?回答是的,可以使用CSS将颜色添加到Chrome和Firefox中的控制台显示的消息(版本31或更高版本)中。要实现这一目标,请使用以下模...
    编程 发布于2025-04-15

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3