python 类中定义列表_Python-从类定义中的列表理解访问类变量

小编典典

类范围和列表,集合或字典的理解以及生成器表达式不混合。

为什么;或者,官方用词

在Python 3中,为列表理解赋予了它们自己的适当范围(本地名称空间),以防止其局部变量渗入周围的范围内(即使在理解范围之后,也请参阅Python列表理解重新绑定名称。对吗?)。在模块或函数中使用这样的列表理解时,这很好,但是在类中,作用域范围有点奇怪。

在pep 227中有记录:

类范围内的名称不可访问。名称在最里面的函数范围内解析。如果类定义出现在嵌套作用域链中,则解析过程将跳过类定义。

在class复合语句文档中:

然后,使用新创建的本地名称空间和原始的全局名称空间,在新的执行框架中执行该类的套件(请参见Naming and binding部分)。(通常,套件仅包含函数定义。)当类的套件完成执行时,其执行框架将被丢弃,但其本地名称空间将被保存。[4]然后,使用基类的继承列表和属性字典的已保存本地名称空间创建类对象。

强调我的;执行框架是临时范围。

由于范围被重新用作类对象的属性,因此允许将其用作非本地范围也将导致未定义的行为。例如,如果一个类方法称为x嵌套作用域变量,然后又进行操作Foo.x,会发生什么情况?更重要的是,这对的子类意味着什么Foo?Python必须以不同的方式对待类范围,因为它与函数范围有很大不同。

最后但并非最不重要的一点是,执行模型文档中链接的命名和绑定部分明确提到了类作用域:

在类块中定义的名称范围仅限于该类块。它不会扩展到方法的代码块–包括理解和生成器表达式,因为它们是使用函数范围实现的。这意味着以下操作将失败:

class A:

a = 42

b = list(a + i for i in range(10))

因此,总结一下:你不能从函数,列出理解或包含在该范围内的生成器表达式中访问类范围;它们的作用就好像该范围不存在。在Python 2中,列表理解是使用快捷方式实现的,但是在Python 3中,它们具有自己的功能范围(应该一直如此),因此你的示例中断了。无论Python版本如何,其他理解类型都有其自己的范围,因此具有set或dict理解的类似示例将在Python 2中中断。

# Same error, in Python 2 or 3

y = {x: x for i in range(1)}

(小的)例外;或者,为什么一部分仍然可以工作

无论Python版本如何,理解或生成器表达式的一部分都在周围的范围内执行。那就是最外层迭代的表达。在你的示例中,它是range(1):

y = [x for i in range(1)]

# ^^^^^^^^

因此,x在该表达式中使用不会引发错误:

# Runs fine

y = [i for i in range(x)]

这仅适用于最外面的可迭代对象。如果一个理解具有多个for子句,则内部for子句的可迭代项将在该理解的范围内进行评估:

# NameError

y = [i for i in range(1) for j in range(x)]

做出此设计决定是为了在genexp创建时引发错误,而不是在创建生成器表达式的最外层可迭代器引发错误时,或者当最外层可迭代器变得不可迭代时,在迭代时抛出错误。理解共享此行为以保持一致性。

在引擎盖下看;或者,比你想要的方式更详细

你可以使用dis模块查看所有这些操作。在以下示例中,我将使用Python 3.3,因为它添加了合格的名称,这些名称可以整洁地标识我们要检查的代码对象。产生的字节码在其他方面与Python 3.2相同。

为了创建一个类,Python本质上采用了构成类主体的整个套件(因此所有内容都比该class :行缩进了一层),并像执行一个函数一样执行:

>>> import dis

>>> def foo():

... class Foo:

... x = 5

... y = [x for i in range(1)]

... return Foo

...

>>> dis.dis(foo)

2 0 LOAD_BUILD_CLASS

1 LOAD_CONST 1 (", line 2>)

4 LOAD_CONST 2 ('Foo')

7 MAKE_FUNCTION 0

10 LOAD_CONST 2 ('Foo')

13 CALL_FUNCTION 2 (2 positional, 0 keyword pair)

16 STORE_FAST 0 (Foo)

5 19 LOAD_FAST 0 (Foo)

22 RETURN_VALUE

首先LOAD_CONST在Foo该类中为类主体加载一个代码对象,然后将其放入函数中并进行调用。然后,该调用的结果用于创建类的名称空间__dict__。到目前为止,一切都很好。

这里要注意的是,字节码包含一个嵌套的代码对象。在Python中,类定义,函数,理解和生成器均表示为代码对象,这些对象不仅包含字节码,而且还包含表示局部变量,常量,取自全局变量的变量和取自嵌套作用域的变量的结构。编译后的字节码引用这些结构,而python解释器知道如何访问给定的字节码。

这里要记住的重要一点是,Python在编译时创建了这些结构。该class套件是", line 2>已编译的代码对象()。

让我们检查创建类主体本身的代码对象。代码对象具有以下co_consts结构:

>>> foo.__code__.co_consts

(None, ", line 2>, 'Foo')

>>> dis.dis(foo.__code__.co_consts[1])

2 0 LOAD_FAST 0 (__locals__)

3 STORE_LOCALS

4 LOAD_NAME 0 (__name__)

7 STORE_NAME 1 (__module__)

10 LOAD_CONST 0 ('foo..Foo')

13 STORE_NAME 2 (__qualname__)

3 16 LOAD_CONST 1 (5)

19 STORE_NAME 3 (x)

4 22 LOAD_CONST 2 ( at 0x10a385420, file "", line 4>)

25 LOAD_CONST 3 ('foo..Foo.')

28 MAKE_FUNCTION 0

31 LOAD_NAME 4 (range)

34 LOAD_CONST 4 (1)

37 CALL_FUNCTION 1 (1 positional, 0 keyword pair)

40 GET_ITER

41 CALL_FUNCTION 1 (1 positional, 0 keyword pair)

44 STORE_NAME 5 (y)

47 LOAD_CONST 5 (None)

50 RETURN_VALUE

上面的字节码创建了类主体。该函数将被执行,结果locals()命名空间将包含x并y用于创建类(但由于x未定义为全局变量而无法使用)。请注意,存储5在中后x,它将加载另一个代码对象;那就是列表理解;它像类主体一样被包装在一个函数对象中;创建的函数带有一个位置参数,该参数range(1)可迭代用于其循环代码,并转换为迭代器。如字节码所示,range(1)在类范围内进行评估。

从中可以看到,用于函数或生成器的代码对象与用于理解的代码对象之间的唯一区别是,后者在执行父代码对象时立即执行;字节码只是简单地动态创建一个函数,然后只需几个小步骤就可以执行它。

Python 2.x在那里改用内联字节码,这是Python 2.7的输出:

2 0 LOAD_NAME 0 (__name__)

3 STORE_NAME 1 (__module__)

3 6 LOAD_CONST 0 (5)

9 STORE_NAME 2 (x)

4 12 BUILD_LIST 0

15 LOAD_NAME 3 (range)

18 LOAD_CONST 1 (1)

21 CALL_FUNCTION 1

24 GET_ITER

>> 25 FOR_ITER 12 (to 40)

28 STORE_NAME 4 (i)

31 LOAD_NAME 2 (x)

34 LIST_APPEND 2

37 JUMP_ABSOLUTE 25

>> 40 STORE_NAME 5 (y)

43 LOAD_LOCALS

44 RETURN_VALUE

没有代码对象被加载,而是FOR_ITER循环内联运行。因此,在Python 3.x中,为列表生成器提供了自己的适当代码对象,这意味着它具有自己的作用域。

然而,理解与当模块或脚本首先被解释加载的Python源代码的其余部分一起编译,编译器并没有考虑一类套件的有效范围。在列表理解任何引用变量必须在查找范围周围的类定义,递归。如果编译器未找到该变量,则将其标记为全局变量。列表理解代码对象的反汇编显示x确实确实是作为全局加载的:

>>> foo.__code__.co_consts[1].co_consts

('foo..Foo', 5, at 0x10a385420, file "", line 4>, 'foo..Foo.', 1, None)

>>> dis.dis(foo.__code__.co_consts[1].co_consts[2])

4 0 BUILD_LIST 0

3 LOAD_FAST 0 (.0)

>> 6 FOR_ITER 12 (to 21)

9 STORE_FAST 1 (i)

12 LOAD_GLOBAL 0 (x)

15 LIST_APPEND 2

18 JUMP_ABSOLUTE 6

>> 21 RETURN_VALUE

这字节代码块加载传入的第一个参数(range(1)迭代器),就像Python 2.x版本FOR_ITER用来循环遍历并创建其输出一样。

如果我们x在foo函数中定义,x它将是一个单元格变量(单元格是指嵌套作用域):

>>> def foo():

... x = 2

... class Foo:

... x = 5

... y = [x for i in range(1)]

... return Foo

...

>>> dis.dis(foo.__code__.co_consts[2].co_consts[2])

5 0 BUILD_LIST 0

3 LOAD_FAST 0 (.0)

>> 6 FOR_ITER 12 (to 21)

9 STORE_FAST 1 (i)

12 LOAD_DEREF 0 (x)

15 LIST_APPEND 2

18 JUMP_ABSOLUTE 6

>> 21 RETURN_VALUE

在LOAD_DEREF将间接加载x从代码对象小区对象:

>>> foo.__code__.co_cellvars # foo function `x`

('x',)

>>> foo.__code__.co_consts[2].co_cellvars # Foo class, no cell variables

()

>>> foo.__code__.co_consts[2].co_consts[2].co_freevars # Refers to `x` in foo

('x',)

>>> foo().y

[2]

实际引用从当前帧数据结构中查找值,当前帧数据结构是从功能对象的.__closure__属性初始化的。由于为理解代码对象创建的函数被再次丢弃,因此我们无法检查该函数的关闭情况。要查看实际的闭包,我们必须检查一个嵌套函数:

>>> def spam(x):

... def eggs():

... return x

... return eggs

...

>>> spam(1).__code__.co_freevars

('x',)

>>> spam(1)()

1

>>> spam(1).__closure__

>>> spam(1).__closure__[0].cell_contents

1

>>> spam(5).__closure__[0].cell_contents

5

因此,总结一下:

列表推导在Python 3中获得了自己的代码对象,并且函数,生成器或推导的代码对象之间没有区别。理解代码对象包装在一个临时函数对象中,并立即调用。

代码对象是在编译时创建的,根据代码的嵌套范围,所有非局部变量都将标记为全局变量或自由变量。类主体不被视为查找那些变量的范围。

执行代码时,Python只需查看全局变量或当前正在执行的对象的关闭。由于编译器未将类主体作为范围包括在内,因此不考虑临时函数名称空间。

解决方法;或者,该怎么办

如果要x像在函数中那样为变量创建显式作用域,则可以将类作用域变量用于列表理解:

>>> class Foo:

... x = 5

... def y(x):

... return [x for i in range(1)]

... y = y(x)

...

>>> Foo.y

[5]

y可以直接调用“临时” 功能。我们用它的返回值替换它。它的范围是解决时考虑x:

>>> foo.__code__.co_consts[1].co_consts[2]

", line 4>

>>> foo.__code__.co_consts[1].co_consts[2].co_cellvars

('x',)

当然,人们在阅读你的代码时会对此有些挠头。你可能要在其中添加一个大的注释,以解释你为什么这样做。

最好的解决方法是仅使用__init__创建一个实例变量:

def __init__(self):

self.y = [self.x for i in range(1)]

并避免一切费力的工作,并避免提出自己的问题。对于你自己的具体示例,我什至不将其存储namedtuple在类中;而是将其存储在类中。直接使用输出(根本不存储生成的类),或使用全局变量:

from collections import namedtuple

State = namedtuple('State', ['name', 'capital'])

class StateDatabase:

db = [State(*args) for args in [

('Alabama', 'Montgomery'),

('Alaska', 'Juneau'),

# ...

]]

2020-02-07

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/349151.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mvc html 生成图片,asp.net mvc5 cs代码中获取视图生成后的HTML

public static class ViewExtensions { /// /// 在控制器内获取指定视图生成后的HTML /// /// 当前控制器的上下文 /// 视图名称 /// 视图所需要的参数 /// 视图生成的HTML public static string GetViewHtml(this ControllerContext context, string viewName, Object param) …

如何在Java 8中将Lambda表达式转换为方法引用?

如果您使用Java 8进行编码,那么您会知道使用方法引用代替lambda表达式会使您的代码更具可读性,因此建议尽可能使用方法引用替换lambda表达式,但是,最大的问题是,您如何查找是否可以用方法引用替换lambda? 是…

最大化窗口设置_打开表格总是默认窗口最小化?适用Word、PPT等其他应用

今天有小哥哥说每天早上上班打开第一个表格时,这样显示;打开第二个表时是这样显示;每次打开第二个表后点最大化再打开其他的表才正常显示为最大化的状态。其实,这只是表格的默认打开方式改变了,我们改正过来就好了。在…

html5块元素代码,html5 区块与内联div 与span html块级元素(示例代码)

HTML 和 可以通过 和 将 HTML 元素组合起来。HTML 块元素大多数 HTML 元素被定义为块级元素或内联元素。编者注:"块级元素"译为 block level element,"内联元素"译为 inline element。块级元素在浏览器显示时,通常会以新…

js 加总数组中某一列_JS数组求和的常用方法实例小结

本文实例总结了JS数组求和的常用方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;js数组求和的方法var array [1, 2, 3, 4, 5];var sum 0;1.for循环for (let i 0; i < array.length; i) {sum array[i];}console.log(sum)运行结果sum为 15&#xff0c;如下图…

html页面js遍历listview,javascript实现的listview效果

javascript实现的listview效果更新时间&#xff1a;2007年04月28日 00:00:00 作者&#xff1a;#oContainer {width: 600px;height: 500px;border: 1px solid menu;margin: 0px;padding: 0px;overflow: hidden;}a {color: black;text-decoration: none;}a:hover {color: red;t…

华南x79主板u盘装系统教程_华南x99主板装win7系统及BIOS设置教程

[文章导读]最近有小伙伴问我华南x99主板能装win7吗&#xff1f;华南x99主板可以安装win7&#xff0c;但安装win7过程中有很多问题&#xff0c;要采用win7新机型安装&#xff0c;且要在BIOS中关闭“安全启动”和开启"兼容模式"选择&#xff0c;如果是NVME接口的固态硬…

html按钮返回上一步操作,用js实现返回上一步操作

按钮式&#xff1a;onClick"location.hrefhttp://www.ddhbb.com/">链接式&#xff1a;href"javascript:history.go(-1)">返回上一步href"">返回上一步直接跳转式&#xff1a;开新窗口&#xff1a;onClick"window.open(http://www.…

Apache Ignite本机持久性,简要概述

通过将数据的工作集放入系统内存中&#xff0c;内存中方法可以达到极高的速度。 当所有数据都保存在内存中后&#xff0c;处理使用传统旋转磁盘引起的问题的需求就消失了。 例如&#xff0c;这意味着无需维护数据的其他缓存副本并管理它们之间的同步。 但是这种方法还有一个缺点…

cheetah的中文_cheetah是什么意思_cheetah的翻译_音标_读音_用法_例句_爱词霸在线词典...

全部非洲猎豹One economist talks hopefully of the " cheetah generation " taking over from the " hippos ".有一位经济学者满怀希望地讲道,肯尼亚的年轻人是征服了 “ 河马一族 ” 的 “ 猎豹一代 ”.期刊摘选The fastest animal on land is the cheet…

计算机减法英语,英语加减乘除的表达

1. 加: “一加二等于三”可以这样表达One plus two is three.One plus two makes three.One plus two equals three.One and two are three.One and two make three.One and two equal three.2. 减: “八减四等于四” 可以这样表达Eight minus four is four.Eight minus four m…

Java命令行界面(第23部分):Rop

Rop库在其主页上被描述为“用Java编写的轻量级命令行选项解析器”。 Rop的“简介”还指出&#xff1a;“ Rop的设计目的是最小化同时方便&#xff0c;并涵盖了大多数常见的命令行解析用例。” 这篇文章是本系列中第23篇有关解析Java命令行参数的文章 &#xff0c;重点是Rop。 …

80端口请求太多超时 php_apmserver 80端口老是被占用问题解决

apmserver 80端口老是被占用问题解决1、在windows下如何查看80端口占用情况?是被哪个进程占用?如何终止等.这里主要是用到windows下的DOS工具,点击”开始”–“运行”,输入”cmd”后点击确定按钮,进入DOS窗口,接下来分别运行以下命令:>netstat -aon | findstr “80”Proto…

计算机网络计技术段标 实训,计算机网络技术实训报告精选.pdf

计算机网络技术实训报告精选《计算机网络技术》实训报告专 业 计算机应用技术专 业 计算机应用技术专专 业业 计计算算机机应应用用技技术术系 别 电子信息工程系系 别 电子信息工程系系系 别别 电电子子信信息息工工程程系系课 程 计算机网络技术课 程 计算机网络技术课课 程程…

mysql 定义年龄属性_sql中定义年龄用什么数据类型,长度为多少?

展开全部sql中定义年龄可以用的用数据类型及长度&#xff1a;1、char(3) &#xff1a;长度为3的字符串。小于10位且62616964757a686964616fe59b9ee7ad9431333431373865长度基本固定的字符串用char。2、varchar(3)&#xff1a;长度为3的字符串。长度大于10的用varchar&#xff0…

Java 9,Jigsaw,JPMS和模块:个人探索

Java 9由于Jigsaw项目而延迟了很多次&#xff0c;您可能会听到很多关于模块&#xff0c;模块化和其他内容的信息&#xff0c;那么&#xff0c;它的全部含义是什么&#xff1f; 模块化到底是什么&#xff0c;模块化平台是什么意思&#xff1f; Java平台模块系统&#xff08;JPMS…

仪征市第二中学计算机老师,静心倾听花自开 ——仪征市第二中学徐丞老师

原标题&#xff1a;静心倾听花自开 ——仪征市第二中学徐丞老师徐丞老师是我校一名优秀的青年教师。自2004年从教以来&#xff0c;他满怀对教育事业的真诚&#xff0c;立足本职&#xff0c;默默耕耘&#xff0c;在平凡中成就着不平凡。在教育教学过程中&#xff0c;徐丞老师始终…

eplise怎么连接数据库_Eclipse连接MySQL数据库(傻瓜篇)

我的环境&#xff1a;MySQL&#xff1a;mysql-essential-5.1.51-win32Eclipse&#xff1a;任意版本&#xff0c;免费的&#xff0c;可以百度的到。下面来创建一个数据&#xff1a;mysql>CREATE DATABASE test; //创建一个数据库mysql>use test; //指定test为当前要操作的…

清空计算机网络缓存,【缓存清理工具】缓存清理软件_电脑缓存清理软件【最新】-太平洋电脑网...

Windows7系统清理dns缓存失败解决方法介绍在win7纯净版系统中有时候&#xff0c;发现网络突然变得很慢&#xff0c;甚至没有网络&#xff0c;怎么回事呢&#xff1f;可能是dns缓存导致的&#xff0c;这时候可以清理dns缓存尝试解决问题。但是有朋友在win7系统清理dns缓存失败&a…

智慧物业小程序_刷脸支付+电商小程序+智慧酒店营销方案

我们这边刷脸支付电商小程序智慧酒店行业解决方案&#xff0c;支付宝微信订房小程序&#xff0c;芝麻信用免押住&#xff0c;数字化经营发券引流&#xff0c;未来酒店:0押金 0房费 退房扣款&#xff0c;不占用资金&#xff0c;用户增长信用分&#xff0c;线上订房小程序&#x…