Maison développement back-end Tutoriel Python Python和Lua的默认作用域以及闭包

Python和Lua的默认作用域以及闭包

Oct 19, 2016 pm 01:34 PM

默认作用域

前段时间学了下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
Copier après la connexion

闭包的本质可以参考SICP第三章的环境模型。在这里可以简单的想象为函数counter有一个私有成员n。

现在问题来了:我想用Python实现同样功能的闭包?

首先直接从Lua代码依葫芦画瓢改写成Python代码:

def new_counter():
  n = 0
  def counter():
    n = n + 1
    return n
  return counter
Copier après la connexion

然后傻眼:这个程序不能运行,第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
Copier après la connexion

这里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
Copier après la connexion

这个程序为什么是错的就很明显了。第4行我们要的是赋值操作,而非定义操作。修改成正确的写法:

def new_counter():
  n := 0
  def counter():
    n = n + 1
    return n
  return counter
Copier après la connexion

   

这样就能正确运行了(前提是有修改版的Python解释器XD)。

最后说一些Lua的情况。Lua感觉上就把定义和赋值的分离实现了一半。带有local关键字的等号语句肯定是定义了。问题是不带local的等号语句。对于这种语句Lua是这样做的:先试图做赋值,如果赋值失败(变量不存在),就在最外层环境(全局环境)定义变量。也就是说,不带local的等号语句把定义和赋值混在一起了。另外,如果实现了定义和赋值的分离,就不需要考虑默认作用域的问题了——定义全部是在当前环境下定义,都是定义局部变量。我实在想不出在一个函数体或者什么块中定义全局变量的好处。


Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Comment réparer l'audio si vous n'entendez personne
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Où trouver la courte de la grue à atomide atomique
1 Il y a quelques semaines By DDD

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

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

Comment résoudre le problème des autorisations rencontré lors de la visualisation de la version Python dans le terminal Linux? Comment résoudre le problème des autorisations rencontré lors de la visualisation de la version Python dans le terminal Linux? Apr 01, 2025 pm 05:09 PM

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 ...

Comment utiliser la belle soupe pour analyser HTML? Comment utiliser la belle soupe pour analyser HTML? Mar 10, 2025 pm 06:54 PM

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

Sérialisation et désérialisation des objets Python: partie 1 Sérialisation et désérialisation des objets Python: partie 1 Mar 08, 2025 am 09:39 AM

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

Comment effectuer l'apprentissage en profondeur avec TensorFlow ou Pytorch? Comment effectuer l'apprentissage en profondeur avec TensorFlow ou Pytorch? Mar 10, 2025 pm 06:52 PM

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

Modules mathématiques en python: statistiques Modules mathématiques en python: statistiques Mar 09, 2025 am 11:40 AM

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

Stracage des pages Web en Python avec une belle soupe: recherche et modification DOM Stracage des pages Web en Python avec une belle soupe: recherche et modification DOM Mar 08, 2025 am 10:36 AM

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

Comment créer des interfaces de ligne de commande (CLI) avec Python? Comment créer des interfaces de ligne de commande (CLI) avec Python? Mar 10, 2025 pm 06:48 PM

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.

Quelles sont les bibliothèques Python populaires et leurs utilisations? Quelles sont les bibliothèques Python populaires et leurs utilisations? Mar 21, 2025 pm 06:46 PM

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

See all articles