Python和Lua的默认作用域以及闭包
默认作用域
前段时间学了下Lua,发现Lua的默认作用域和Python是相反的。Lua定义变量时默认变量的作用域是全局(global,这样说不是很准确,Lua在执行x = 1这样的语句时会从当前环境开始一层层往上查找x,只有在找不到x的情况下才定义全局变量)的,而Python定义变量时默认变量的作用域是局部(local)的(当前块)。另外,Lua可以再定义变量时在变量前加上local关键字来定义局部变量,而Python没有类似的关键字,Python的变量只能定义在当前块中。
我们知道,全局变量是不好的,而局部变量是好的,写程序应该尽量使用局部变量。所以一开始时我觉得Python的这种约定比较好,它的优点就是可以少打些字。写Lua程序时不断在心底默念“勿忘local,勿忘local”,然而还是有时会出现几个漏网之鱼并引发了一些神奇的bug。
闭包
第一次意识到Python默认作用域的问题是在使用闭包时碰到的。关于闭包,Lua教程上有一段代码:
function new_counter() local n = 0 local function counter() n = n + 1 return n end return counter end c1 = new_counter() c2 = new_counter() print(c1()) -- 打印1 print(c2()) -- 打印1 print(c1()) -- 打印2 print(c2()) -- 打印2
闭包的本质可以参考SICP第三章的环境模型。在这里可以简单的想象为函数counter有一个私有成员n。
现在问题来了:我想用Python实现同样功能的闭包?
首先直接从Lua代码依葫芦画瓢改写成Python代码:
def new_counter(): n = 0 def counter(): n = n + 1 return n return counter
然后傻眼:这个程序不能运行,第4行访问了未赋值的变量n。出错的原因并非是Python不支持闭包,而是Python的赋值操作访问不了上一层的变量n(实际上,Python认为这是定义局部变量,而非赋值。在Python中定义局部变量与赋值操作在语法上是冲突的,Python干脆只支持可重定义的定义语句)。由于Python默认作用域是局部的,所以当程序运行到n = n + 1时,Python认为这是一个变量定义操作,于是创建了一个(未初始化的)局部变量n——并且顺利地覆盖了new_counter这一层的n——然后试图把n + 1赋值给n,但是n未初始化,n + 1没法计算,所以程序报错。
可以用个小技巧来实现闭包赋值的功能:
def new_counter(): n = [0] def counter(): n[0] = n[0] + 1 return n[0] return counter
这里n[0] = n[0] + 1不会出错的原因是这里的等号和前面n = n + 1的等号含义不一样。n[0] = n[0] + 1中的等号意思是修改n的某个属性。事实上这个等号最终调用了list的__setitem__方法。而n = n + 1中的等号意思是在当前环境将n + 1这个值绑定到符号n中(如果当前环境已存在符号n,就覆盖它)。
另外题外话:打死我不用这种写法,多难看呐。反正Python是面向对象语言,要实现个计数器,大不了写个类。
定义与赋值的分离
先总结一下Python与Lua的默认作用域的特点:
1、 Lua默认作用域是全局的,写程序时要牢记local关键字(除非确实要定义全局变量),不小心忘了local也不会提示,就等着纠bug吧。
2、 Python默认作用域是局部的,虽然写程序的思维负担少些,但是丧失了对上层变量赋值的能力(可以改,但会让语言更混乱)。
看来两种默认作用域都有问题?个人认为,出现以上问题的原因是:Python和Lua没有实现定义和赋值的分离。在Python和Lua中,像x = 1这样的语句既可以表示定义,也可以表示赋值。其实不只是这两种语言,其实很多高级语言都没有实现定义和赋值的分离。定义和赋值两者功能上很像,但是它们本质上是有差别的。
下面以x = 1为例解释定义与赋值:
定义的意思是:在当前环境中注册符号x,并初始化为1。如果x已经存在,则报错(不允许重定义)或者覆盖(允许重定义)。
赋值的意思是:从当前环境开始,一层层往上找直到第一次找到符号x,把它的值修改成1。如果找不到就报错(变量不存在)。
现在我们稍微修改一下Python来实现定义和赋值的分离:用“:=”表示定义,用“=”表示赋值。然后重写那个不能运行的new_counter例子(Python中赋值操作和定义局部变量冲突,换句话说,Python其实没有赋值操作,所以我们只需简单的把“=”全换成“:=”就行了),看看它错在哪:
def new_counter(): n := 0 def counter(): n := n + 1 return n return counter
这个程序为什么是错的就很明显了。第4行我们要的是赋值操作,而非定义操作。修改成正确的写法:
def new_counter(): n := 0 def counter(): n = n + 1 return n return counter
这样就能正确运行了(前提是有修改版的Python解释器XD)。
最后说一些Lua的情况。Lua感觉上就把定义和赋值的分离实现了一半。带有local关键字的等号语句肯定是定义了。问题是不带local的等号语句。对于这种语句Lua是这样做的:先试图做赋值,如果赋值失败(变量不存在),就在最外层环境(全局环境)定义变量。也就是说,不带local的等号语句把定义和赋值混在一起了。另外,如果实现了定义和赋值的分离,就不需要考虑默认作用域的问题了——定义全部是在当前环境下定义,都是定义局部变量。我实在想不出在一个函数体或者什么块中定义全局变量的好处。

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds



Solution aux problèmes d'autorisation Lors de la visualisation de la version Python dans Linux Terminal Lorsque vous essayez d'afficher la version Python dans Linux Terminal, entrez Python ...

Cet article explique comment utiliser la belle soupe, une bibliothèque Python, pour analyser HTML. Il détaille des méthodes courantes comme find (), find_all (), select () et get_text () pour l'extraction des données, la gestion de diverses structures et erreurs HTML et alternatives (Sel

La sérialisation et la désérialisation des objets Python sont des aspects clés de tout programme non trivial. Si vous enregistrez quelque chose dans un fichier Python, vous effectuez une sérialisation d'objets et une désérialisation si vous lisez le fichier de configuration, ou si vous répondez à une demande HTTP. Dans un sens, la sérialisation et la désérialisation sont les choses les plus ennuyeuses du monde. Qui se soucie de tous ces formats et protocoles? Vous voulez persister ou diffuser des objets Python et les récupérer dans son intégralité plus tard. C'est un excellent moyen de voir le monde à un niveau conceptuel. Cependant, à un niveau pratique, le schéma de sérialisation, le format ou le protocole que vous choisissez peut déterminer la vitesse, la sécurité, le statut de liberté de maintenance et d'autres aspects du programme

Cet article compare TensorFlow et Pytorch pour l'apprentissage en profondeur. Il détaille les étapes impliquées: préparation des données, construction de modèles, formation, évaluation et déploiement. Différences clés entre les cadres, en particulier en ce qui concerne le raisin informatique

Le module statistique de Python fournit de puissantes capacités d'analyse statistique de données pour nous aider à comprendre rapidement les caractéristiques globales des données, telles que la biostatistique et l'analyse commerciale. Au lieu de regarder les points de données un par un, regardez simplement des statistiques telles que la moyenne ou la variance pour découvrir les tendances et les fonctionnalités des données d'origine qui peuvent être ignorées et comparer les grands ensembles de données plus facilement et efficacement. Ce tutoriel expliquera comment calculer la moyenne et mesurer le degré de dispersion de l'ensemble de données. Sauf indication contraire, toutes les fonctions de ce module prennent en charge le calcul de la fonction moyenne () au lieu de simplement additionner la moyenne. Les nombres de points flottants peuvent également être utilisés. Importer au hasard Statistiques d'importation de fracTI

Ce tutoriel s'appuie sur l'introduction précédente à la belle soupe, en se concentrant sur la manipulation de Dom au-delà de la simple navigation sur les arbres. Nous explorerons des méthodes et techniques de recherche efficaces pour modifier la structure HTML. Une méthode de recherche DOM commune est ex

Cet article guide les développeurs Python sur la construction d'interfaces de ligne de commande (CLI). Il détaille à l'aide de bibliothèques comme Typer, Click et Argparse, mettant l'accent sur la gestion des entrées / sorties et promouvant des modèles de conception conviviaux pour une meilleure convivialité par la CLI.

L'article traite des bibliothèques Python populaires comme Numpy, Pandas, Matplotlib, Scikit-Learn, Tensorflow, Django, Flask et Demandes, détaillant leurs utilisations dans le calcul scientifique, l'analyse des données, la visualisation, l'apprentissage automatique, le développement Web et H et H
