私信  •  关注

Martijn Pieters

Martijn Pieters 最近创建的主题
Martijn Pieters 最近回复了
6 年前
回复了 Martijn Pieters 创建的主题 » Python xrange名称错误?[副本]

您正在尝试使用Python 3运行Python 2代码库。 xrange() range() 在Python 3中。

改用Python 2运行游戏。除非你知道你在做什么,否则不要试图移植它,很可能会有更多的问题超出 与。 范围() .

对于记录,您看到的不是语法错误,而是运行时异常。


如果您知道自己在做什么,并且正在积极地使Python2代码库与Python3兼容,那么可以通过将全局名称作为 range 可以 必须更新任何现有的 在Python 2代码库中使用 list(range(...)) 要确保在Python 3中仍然获得list对象,请执行以下操作:

try:
    # Python 2
    xrange
except NameError:
    # Python 3, xrange is now named range
    xrange = range

# Python 2 code that uses xrange(...) unchanged, and any
# range(...) replaced with list(range(...))

或取代 xrange(...) 具有 range(...)

try:
    # Python 2 forward compatibility
    range = xrange
except NameError:
    pass

# Python 2 code transformed from range(...) -> list(range(...)) and
# xrange(...) -> range(...).

对于希望与Python 3兼容的代码基,后者更可取 从长远来看,只要有可能,使用Python 3语法就更容易了。

5 年前
回复了 Martijn Pieters 创建的主题 » Python 2中的可变长度optionals参数(*args)导致错误

(col_name, *args) 使用创建新元组 col_name 作为第一个元素,然后是 args iterable unpacking 而且是 first added to Python 3.5

只需通过连接创建元组:

t =  (col_name,) + args  # assuming args is a tuple too
exprs.append((func, t))

如果 参数

t =  (col_name,) + tuple(args)  # works with any iterable.
exprs.append((func, t))
6 年前
回复了 Martijn Pieters 创建的主题 » 模拟“len”和“bool”的Python行为`

bool() 测试 真理价值 所以你想看看 rules for Truth Value Testing

默认情况下,除非对象的类定义了 __bool__() 返回的方法 False 或者 __len__()

你只实现了 __len__ 故意破坏的方法 TypeError 接到电话时。但是 当它是一个实现并且没有其他选项可用于确定真值时调用它。

__bool__ is preferred over __len__ :

__伦恩 如果已定义,则调用;如果对象的结果为非零,则将其视为真。

>>> class Z:
...     def __bool__(self):
...         return True
...     def __len__(self):
...         raise TypeError
...
>>> len(Z())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __len__
TypeError
>>> bool(Z())
True

注意,它是 len() 引发的函数实现 类型错误 当没有实现 __蓝__ 钩子。没有例外的是 __蓝__

6 年前
回复了 Martijn Pieters 创建的主题 » 是否可以将端口号添加到python请求主机名?

requests.Session() 匹配,大小写无关,由 一个人。如果希望适配器应用于以字符串开头的URL https://google.com:443 那你就用对了。

语法 :port :端口 违约 为了这个计划 使用。对于 https scheme,默认为端口443,因此使用 :443

但是,在安装适配器时,不会进行规范化,因此前缀 'https://google.com:443' 不匹配 https://google.com/ 即使两个地址的主机名和端口相同。

有没有办法可以强制程序在版本检查时失败,从而返回更有用的错误消息?

支持的语法 在文件中,Python 2无法解析f字符串。

您必须将项目分成多个模块,并且在 要导入的第一个模块 (比如说,最高层 __init__.py

或者 . 相反,设置 python_requires

7 年前
回复了 Martijn Pieters 创建的主题 » 使用Python、Flask和SQLAlchemy获取Postgresql数据库中的双条目

Werkzeug重载程序生成一个子进程,以便它可以在每次代码更改时重新启动该进程。Werkzeug是一个库,当您调用 app.run() .

restart_with_reloader() function code 再一次 具有 subprocess.call()

如果你设置 use_reloader False

app.run(port=4004, debug=config.DEBUG, host='0.0.0.0', use_reloader=False)

当使用 flask run 命令也:

FLASK_DEBUG=1 flask run --no-reload

你可以找 WERKZEUG_RUN_MAIN 如果要检测何时处于重新加载子进程中,则为环境变量:

import os
if os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
    print '################### Restarting @ {} ###################'.format(
        datetime.utcnow())

但是,如果需要设置模块全局变量,则应使用 @app.before_first_request decorator

@app.before_first_request
def before_first_request():
    print '########### Restarted, first request @ {} ############'.format(
        datetime.utcnow())

如果在使用forking或新的子进程来处理请求的完整WSGI服务器中运行此命令,请考虑 before_first_request 处理程序 可以

6 年前
回复了 Martijn Pieters 创建的主题 » 如何在Python中保护函数不受基类的影响?

你不能阻止子类使用相同的名称,不,你可以 保护 但是,通过给名称加上双下划线前缀,可以防止意外阴影:

def __primitive_operation_3(self):
    print('Execute operation #3 from main class')

Python编译器将替换 全部的 在类的方法中引用该名称,以添加类名作为前缀。这里,那是 AbstractClass ,因此实际名称变成 _AbstractClass__primitive_operation_3 ,但是因为编译器重写了所有引用,所以您可以透明地继续使用 __primitive_operation_3 在你的密码里。

任何 __原语操作 子类上的名称将使用不同的前缀重命名,因为它们是在具有不同名称的类上定义的。

此功能明确针对那些希望子类在其定义中使用广泛名称的基类。

Reserved classes of identifiers section 在词法分析参考文献中:

__*

类私有名称。此类别中的名称在类定义的上下文中使用时,将重新编写为使用损坏的表单,以帮助避免基类和派生类的“private”属性之间的名称冲突。

以及 Identifiers section 表达式文档:

私名破译 :当在类定义中以文本形式出现的标识符以两个或多个下划线字符开头,而不是以两个或多个下划线结尾时,该标识符将被视为该类的私有名称。在为私有名称生成代码之前,将其转换为更长的形式。转换将在类名前面插入类名,去掉前导下划线并插入一个下划线。例如,标识符 __spam 在一个名为 Ham 将转换为 _Ham__spam . 这种转换独立于使用标识符的语法上下文。如果转换后的名称非常长(超过255个字符),则可能发生实现定义的截断。如果类名仅由下划线组成,则不进行转换。

子类仍然可以重写名称,但必须显式地包含相同的前缀。

请注意,不能使用此机制来避免特殊方法(带有前导和尾随 __ 双下划线,例如。 __init__ __len__ )在子类中被重写。如果基类的子类不能在不注意调用基类实现的情况下重写特定的方法,那么清除项目文档是至关重要的。充其量,您可以通过检查缺少的副作用来检测子类是否正在重写方法(标准库就是这样 protected Thread.__init__ overriding 或者你可以检查一下 self.methodname.__func__ is ClassObject.methodname 在调用方法之前仍然为true。

7 年前
回复了 Martijn Pieters 创建的主题 » 需要有关python 3.7的简单脚本的帮助[duplicate]

你误解了布尔表达式的工作原理;它们不像英语句子那样工作,你猜你说的是这里所有名字的相同比较。您正在寻找:

if x == 1 or y == 1 or z == 1:

x y 否则会自行评估( False 如果 0 , True 否则)。

您可以使用 a tuple :

if 1 in (x, y, z):

或者更好:

if 1 in {x, y, z}:

使用 a set 利用恒定成本隶属度检验( in 无论左手操作数是什么,都需要固定的时间。

当你使用 or ,python将运算符的每一侧视为 分离 表达。表达 x or y == 1 作为第一个布尔测试处理 ,则如果为False,则表达式 y == 1 是经过测试的。

这是因为 operator precedence . 这个 运算符的优先级低于 == 测试,因此对后者进行评估 第一 .

然而,即使这是 这个案子,还有这个表达 x or y or z == 1 实际上被解释为 (x or y or z) == 1 相反,这仍然不能达到你期望的效果。

x or y or z 会对第一个“真理”的论点进行评估,例如 ,数字0或为空(请参见 boolean expressions 有关Python在布尔上下文中认为false的详细信息)。

所以对于价值观 x = 2; y = 1; z = 0 , x或y或z 会决心 2 ,因为这是参数中的第一个类真值。那么 2 == 1 会是 ,尽管 y==1 会是 真的 .

同样的方法也适用于逆函数;对单个变量测试多个值; x == 1 or 2 or 3 会因为同样的原因失败。使用 x == 1 or x == 2 or x == 3 x in {1, 2, 3} .

5 年前
回复了 Martijn Pieters 创建的主题 » Python:float()参数必须是字符串或数字

这个 img.resize() method 调整数据大小 到位 和回报 None . 不要使用返回值来创建数组,只要使用 img 直接的。这是一个核阵列 已经 :

img = imread('1.png')
img.resize(224,224)  # alters the array in-place, returns None
images.append(img)   # so just use the array directly.

如果需要数据的副本,调整大小,请使用 numpy.resize() `:

img = imread('1.png')
resized_img = np.resize(img, (224,224))
images.append(resized_img)

请注意 matplotlib.pyplot.imread() 函数只不过是 matplotlib.image.imread() .

6 年前
回复了 Martijn Pieters 创建的主题 » Python+Flask REST API,如何在camelcase和snakecase之间转换数据密钥?

你不需要转换密钥,因为你不需要。数据不是代码,json中的键不是变量。他们不受PEP8的约束,你也不会改变他们。

如果您有JSON对象键的约定,请在前端和后端的任何地方都遵守它然后用棉花糖3.x data_key 用于在加载和转储时设置JSON文档中的键名的字段的参数。

例如。

class UserSchema(Schema):
    first_name = fields.String(data_key="firstName")
    last_name = fields.Email(data_key='lastName')

如果您想自动化所有字段,可以提供自己的 Schema.on_bind_field() implementation 生成 数据键 字段名中的值:

import re
from functools import partial

from marshmallow import Schema

_snake_case = re.compile(r"(?<=\w)_(\w)")
_to_camel_case = partial(_snake_case.sub, lambda m: m[1].upper())

class CamelCasedSchema(Schema):
    """Gives fields a camelCased data key"""
    def on_bind_field(self, field_name, field_obj, _cc=_to_camel_case):
        field_obj.data_key = _cc(field_name.lower())

演示:

>>> from marshmallow import fields
>>> class UserSchema(CamelCasedSchema):
...     first_name = fields.String()
...     last_name = fields.String()
...
>>> schema = UserSchema()
>>> schema.load({"firstName": "Eric", "lastName": "Idle"})
{'first_name': 'Eric', 'last_name': 'Idle'}
>>> schema.dump({"first_name": "John", "last_name": "Cleese"})
{'firstName': 'John', 'lastName': 'Cleese'}

棉花糖文档的示例部分有 similar recipe 是的。

如果使用的是棉花糖2.x,则需要设置两个参数: load_from dump_to 是的。

6 年前
回复了 Martijn Pieters 创建的主题 » python中属性decorator对于可变属性的有用性

你创建了一个属性 无法删除 以下内容:

>>> f = Foo2('bar')
>>> f.prop
'bar'
>>> f.prop = 'spam'
>>> f.prop
'spam'
>>> del f.prop
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't delete attribute

将此与 Foo().prop 属性,可以删除:

>>> f = Foo('bar')
>>> f.prop
'bar'
>>> del f.prop
>>> f.prop
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'prop'

除此之外,或者如果您添加了 @prop.deleter 处理程序,创建这样的属性实际上没有任何好处。将普通属性访问所能做的委托给函数并没有那么有用。

属性setter或getter在使用时更有用 另外的东西 只需设置属性,比如验证或转换。

例如,setter可以强制值始终为整数,包括在转换为整数失败时设置默认值:

@prop.setter
def prop(self, value):
    try:
        self._prop = int(prop)
    except ValueError:
        self._prop = 0

在其他编程语言(如java)中,如果不必在代码基中的任何地方重新编写对这些属性的所有访问权限,就无法轻松地将属性转换为getter和setter(java中没有与python属性等效的概念),因此在这些语言中,您经常会看到建议,从getter和setter开始。 这不适用于python 您可以将现有属性简单地转换为属性,而不必使用这些属性更改任何代码。

6 年前
回复了 Martijn Pieters 创建的主题 » 在python中创建表时如何简化表

您创建了一个包含多个字符串和几个列表的元组。

你可以使用 * 可拆箱 语法内部 [...] 相反,列表显示:

catalogue_tableau = [
    *(["Asics Gel 2000"] * 2),
    "Mizuno Wave rider", "Nike Air zoom",
    *(["Mizuno Wave plus"] * 3),
    "Merrell Poseidon"
]

每一个里面的表达式 *(...) 组应包含iterable,其值将添加到该位置的列表中。

6 年前
回复了 Martijn Pieters 创建的主题 » 如何正确使用python中的pathlib排除path目录中的文件?

这里不需要将任何内容转换为字符串,因为 Path 对象具有可用于筛选的有用属性。看看 .name .stem 属性;这些属性允许您在基本文件名(其中 是没有扩展名的基名称):

dircontent = [path for path in p.parent.glob('*') if 'mask' not in path.stem]
12 年前
回复了 Martijn Pieters 创建的主题 » 在python中将多个操作压缩成一行[复制]

不能在多个目标上使用扩展赋值语句,不能。

引用 augmented assignment documentation :

除了在一条语句中分配给元组和多个目标 ,通过扩展赋值语句完成的赋值与普通赋值的处理方式相同。同样,除了 就位 行为上,通过增广赋值执行的二进制操作与普通的二进制操作相同。

强调我的。

就地增广赋值从 target -= expression target = target.__isub__(expression) (与相应的 __i...__ 不支持将该操作转换为多个目标。

在这种情况下,增广赋值是二元算子的一种特殊化。( + , * , - 等) 转让。由于实现是基于这些运算符的,并且二进制运算符只有两个操作数,因此原始操作数中从未包含多个目标。 implementation proposal .

你只需单独申请作业:

x -= 1
y -= 2

或者,如果你真的,真的想搞复杂,用 operator 模块和 zip() 申请 operator.isub 到组合(通过 itertools.starmap() ,然后使用元组分配:

from operator import sub
from itertools import starmap

x, y = starmap(operator.isub, zip((x, y), (1, 2)))

哪里 isub 将确保调用右钩子以允许对支持它的可变类型进行就地减法。

或者,如果要操作不支持就地操作的类型,则使用生成器表达式就足够了:

x, y = (val - delta for val, delta in zip((x, y), (1, 2)))
6 年前
回复了 Martijn Pieters 创建的主题 » 在每个python数学模块函数中找到/的含义是什么?[复制品]

它意味着 positional only parameters ,参数 不能 用作关键字参数。这样的参数只能在C API中指定。

这意味着 key 论证 __contains__ 只能通过位置传递( range(5).__contains__(3) ),而不是作为关键字参数( range(5).__contains__(key=3) ),一些你 可以 在纯python函数中使用位置参数。

也看到 Argument Clinic 文档:

若要在参数诊所中将所有参数标记为仅位置参数,请添加 / 在最后一个参数之后的一行上,缩进与参数行相同的行。

以及 Python FAQ :

函数的参数列表中的斜线表示其前面的参数仅为位置参数。仅位置参数是没有外部可用名称的参数。调用只接受位置参数的函数时,参数将仅基于其位置映射到参数。

还为将来可能包含在python中定义了语法,请参见 PEP 457 - Syntax For Positional-Only Parameters .

这股精神最近恢复了,并且 accepted for inclusion in Python . 由于python 3.8仍处于alpha阶段,因此在该版本中或在3.9中它可能成为现实,这取决于速度 the reference implementation 可以敲定。

只有位置的参数可以导致更干净和更清晰的API,使纯的Python实现,否则只有C的模块更一致和更容易维护,并且因为位置参数只需要很少的处理,它们导致更快的Python代码。

11 年前
回复了 Martijn Pieters 创建的主题 » python-为什么要修改整个列表的第一项[重复]
>>> def a():
>>>    print "a executed"
>>>    return []
>>> x =a()
a executed
>>> def b(m=[]):
>>>    m.append(5)
>>>    print m
>>> b(x)
[5]
>>> b(x)
[5, 5]
11 年前
回复了 Martijn Pieters 创建的主题 » 配置分析器。Python2.7[副本]

ConfigParser.ConfigParser() ConfigParser.RawConfigParser() ,其行为记录如下:

所有选项名称都通过 optionxform() 方法。它的默认实现将选项名转换为小写。

这是因为这个模块解析的是windows ini文件,而这些文件应该是不区分大小写的。

您可以通过替换 RawConfigParser.optionxform() function :

self.config = ConfigParser.ConfigParser()
self.config.optionxform = str

str 不加更改地传递选项。

6 年前
回复了 Martijn Pieters 创建的主题 » python使用self回调后如何“释放”对象

如果您担心回调会使实例保持活动状态,那么 不要传入绑定方法 . self.BgError 创建方法对象(通过 descriptor protocol ,它引用实例对象,因为在调用该实例时它需要访问该实例;这就是 self 首先传入参数。

如果不需要引用实例状态,并且回调API可以处理未绑定的方法、类方法或静态方法,则将其中一个方法传入。

例如,您可以 BgError 类方法或静态方法:

@classmethod
def BgError(cls):
    # ...

现在两个 Client.BgError 自错 ( instance_of_Client.BgError )生成绑定到类而不是实例的方法对象,从而提供一致的行为。没有对实例进行额外的引用。

如果您确实需要实例状态,请使用 weak reference 以你为例。调用时,请在使用实例之前检查弱引用是否仍然可用。也看到 using python WeakSet to enable a callback functionality 有关回调和弱引用的更深入的帖子。在那里,回调注册表负责生成和存储弱引用,但同样的原则也适用。

6 年前
回复了 Martijn Pieters 创建的主题 » 如何在python中解决这个regex问题

您可以将变量空白与 \s* (零个或多个空格)或 \s+ (一个或多个空格),您可以使用 (...) 圆括号。

看着 this description of the Verilog input syntax ,你可以看到你会寻找 输入 后跟一个可选范围,后跟一个或多个标识符,它们是 delimited by whitespace . 下面的模式将捕获 列表 来自这样一个语句的标识符:

r'^input\s+(?:\[[^\]]*\]\s+)?(.+);'

这个 (?:\[[^\]]*\]\s+)? 部分将匹配可选范围语法(a [ ,后跟非上的任意数字- ] 字符,后跟 ] ,但没有捕获它。见 https://regex101.com/r/cT0Q0X/1 在线演示。

因为标识符总是用空格分隔的,所以可以使用 str.split() 将捕获的值转换为python列表。

您不需要将文件读入内存或使用 range . 直接循环文件。你不需要使用 re.M ,因为您正在处理单个行。我也会放弃 re.I ,因为verilog是区分大小写的; INPUT 不是同一件事 输入 :

with open(r'D:/pyfile/verilog.v') as file:
    for line in file:
        match = re.search(r'^input\s+(?:\[[^\]]*\]\s+)?(.+);', line)
        if match:
            identifiers = match.group(1).split()
            print(*identifiers)

使用示例演示:

>>> import re
>>> from io import StringIO
>>> sample = '''\
... module(a,b,c,d, vbg
... `ifdef USE_GOOD_PIN
... , vb, vc, vd, vg ..... some more input and outputs
... `endif
...  );
...
... input  [7:0] t_d;
... input srd;
... output comb;
... output src;
... inout  [1:0] Iout;
... output a_in;
... output b_in;
... input ff_parity;
... '''
>>> with StringIO(sample) as file:
...     for line in file:
...         match = re.search(r'^input\s+(?:\[[^\]]*\]\s+)?(.+);', line)
...         if match:
...             identifiers = match.group(1).split()
...             print(*identifiers)
...
t_d
srd
ff_parity

你有 嵌套JSON数据 ;与 'annoucement' key本身是另一个独立的嵌入式json文档。

您必须先解码该字符串:

import json

replay_data = raw_replay_data['data']['video_info'][0]
announcement = json.loads(replay_(data['announcement'])
print(announcement['content'])

然后从那里处理得到的字典。

一字排开-

>>> json.loads(data['data']['video_info'][0]['announcement'])['content']
'FOLLOW ME PLEASE'

为了帮助您理解如何访问数据(这样您就不用再问了),您需要 盯着你的数据 .

首先,让我们把你的数据布局得很好。你可以使用 json.dumps(data, indent=4) ,或者您可以使用在线工具,如 JSONLint.com .

{
    'data': {
        'time': '1515580011',
        'video_info': [{
            'announcement': (    # ***
            """{
                "announcement_id": "6",
                "name": "INS\\u8d26\\u53f7",
                "icon": "http:\\\\/\\\\/liveme.cms.ksmobile.net\\\\/live\\\\/announcement\\\\/2017-08-18_19:44:54\\\\/ins.png",
                "icon_new": "http:\\\\/\\\\/liveme.cms.ksmobile.net\\\\/live\\\\/announcement\\\\/2017-10-20_22:24:38\\\\/4.png",
                "videoid": "15154610218328614178",
                "content": "FOLLOW ME PLEASE",
                "x_coordinate": "0.22",
                "y_coordinate": "0.23"
            }"""),
            'announcement_shop': ''
        }]
    },
    'msg': '',
    'status': '200'
} 

***请注意 announcement 关键是 更多 json数据,我已经将其放在单独的行中。

首先,找出数据所在的位置。你在找 content 密钥,可由 公告 键,它是dicts列表中字典的一部分,可以通过 video_info 密钥,依次由 data .

因此,总而言之,使用下面的“横档”来“下降”梯形图,即“数据”-

  1. 数据 ,一本字典
  2. 小精灵 ,一份口述清单
  3. 公告 ,在命令列表的第一个命令中的命令
  4. 内容 作为json数据的一部分驻留。

第一,

i = data['data']

下一步,

j = i['video_info']

下一步,

k = j[0] # since this is a list

如果只需要第一个元素,这就足够了。否则,你需要 迭代 :

for k in j:
    ...

下一步,

l = k['announcement']

现在, l 是json数据。加载它-

import json
m = json.loads(l)

最后,

content = m['content']

print(content)
'FOLLOW ME PLEASE'

如果您将来有这种性质的查询,这应该是一个很有希望的指导。

6 年前
回复了 Martijn Pieters 创建的主题 » python:类内的字典理解[复制]

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

原因;或者,官方的说法

在Python3中,列表理解被赋予了一个适当的作用域(本地名称空间),以防止它们的本地变量溢出到周围的作用域中(请参见 Python list comprehension rebind names even after scope of comprehension. Is this right? )。在模块或函数中使用这样的列表理解非常好,但是在类中,范围界定有点,嗯, 奇怪的 .

这记录在 pep 227 :

类作用域中的名称不可访问。名称在中解析 最里面的封闭函数作用域。如果类定义 在嵌套作用域链中发生,解析过程将跳过 类定义。

而在 class compound statement documentation :

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

重点挖掘;执行框架是临时范围。

因为作用域被重新用作类对象的属性,允许它用作非本地作用域也会导致未定义的行为;如果类方法引用 x 作为嵌套范围变量,然后操纵 Foo.x 还有,比如说?更重要的是,这对 Foo ?蟒蛇 以不同的方式对待类作用域,因为它与函数作用域非常不同。

最后,但绝对不是最不重要的是 Naming and binding 执行模型文档中的部分明确提到了类作用域:

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

class A:
     a = 42
     b = list(a + i for i in range(10))

因此,总结一下:不能从包含在该作用域中的函数、列表理解或生成器表达式访问类作用域;它们的作用就像该作用域不存在一样。在Python2中,列表理解是使用快捷方式实现的,但在Python3中,它们有自己的函数作用域(它们应该一直都有),因此示例中断。不管python版本如何,其他理解类型都有自己的作用域,因此在python 2中会出现一个带有set或dict理解的类似示例。

# Same error, in Python 2 or 3
y = {x: x for i in range(1)}

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

理解或生成器表达式的一部分在周围的范围内执行,而不管python版本如何。这将是最外层iterable的表达式。在你的例子中,是 range(1) :

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

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

# Runs fine
y = [i for i in range(x)]

这只适用于最外层的iterable;如果一个理解有多个 for 子句,内部的iterables 对于 从句在理解范围内进行评估:

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

这个设计决策是为了在genexp创建时抛出错误,而不是在创建生成器表达式的最外层iterable时抛出错误,或者在最外层iterable结果不是iterable时抛出错误。理解共享这种行为以保持一致性。

从引擎盖下面看;或者,比你想要的要详细得多

您可以使用 dis module . 我在下面的示例中使用Python3.3,因为它添加了 qualified names 能够清楚地识别我们要检查的代码对象。生成的字节码在功能上与Python3.2相同。

创造 作为一个类,python基本上采用了构成类体的整个套件(因此所有的东西都比 class <name>: ,并将其作为函数执行:

>>> 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 (<code object Foo at 0x10a436030, file "<stdin>", 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 这里为 类body,然后将其转换为函数并调用它。这个 结果 然后使用该调用创建类的命名空间 __dict__ . 到现在为止,一直都还不错。

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

这里要记住的重要一点是,python在编译时创建这些结构; suite是一个代码对象( <code object Foo at 0x10a436030, file "<stdin>", line 2> )已经编译好了。

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

>>> foo.__code__.co_consts
(None, <code object Foo at 0x10a436030, file "<stdin>", 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.<locals>.Foo') 
             13 STORE_NAME               2 (__qualname__) 

  3          16 LOAD_CONST               1 (5) 
             19 STORE_NAME               3 (x) 

  4          22 LOAD_CONST               2 (<code object <listcomp> at 0x10a385420, file "<stdin>", line 4>) 
             25 LOAD_CONST               3 ('foo.<locals>.Foo.<listcomp>') 
             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 ,它加载另一个代码对象;这是列表理解;它像类主体一样被包装在函数对象中;创建的函数接受一个位置参数, 范围(1) 可用于循环代码,转换为迭代器。如字节码所示, 范围(1) 在类作用域中求值。

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

python 2.x在那里使用内联字节码,这里是python2.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 循环以内联方式运行。所以在Python3.x中,列表生成器被赋予了一个自己的适当代码对象,这意味着它有自己的作用域。

然而,当解释器第一次加载模块或脚本时,理解是与python源代码的其余部分一起编译的,而编译器确实 将类套件视为有效范围。列表理解中的任何引用变量都必须在作用域中查找 周围的 类定义,递归地。如果编译器找不到该变量,则将其标记为全局变量。对list comprehension code对象的反汇编表明 X 确实作为全局加载:

>>> foo.__code__.co_consts[1].co_consts
('foo.<locals>.Foo', 5, <code object <listcomp> at 0x10a385420, file "<stdin>", line 4>, 'foo.<locals>.Foo.<listcomp>', 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         

这个字节码块加载传入的第一个参数 范围(1) 迭代器),就像python 2.x版本使用 福里斯特 循环它并创建它的输出。

我们确定了吗 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__ 属性。由于为comprehension code对象创建的函数再次被丢弃,我们无法检查该函数的闭包。要查看闭包的运行情况,我们必须检查嵌套函数:

>>> 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只需查看globals或当前执行对象的闭包。由于编译器没有将类体作为作用域包含,因此不考虑临时函数命名空间。

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

如果要为 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]
<code object y at 0x10a5df5d0, file "<stdin>", 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'),
       # ...
    ]]
6 年前
回复了 Martijn Pieters 创建的主题 » 为什么在windows上python 3下创建模块后导入会失败?

我想我知道发生了什么。新的python 3进口机器 高速缓存 它在目录中找到的文件名。当 mtime ,目录更改的修改时间。

importlib._bootstrap_external.FileFinder.find_spec() method implementation ,其中包含:

try:
    mtime = _path_stat(self.path or _os.getcwd()).st_mtime
except OSError:
    mtime = -1
if mtime != self._path_mtime:
    self._fill_cache()
    self._path_mtime = mtime

在这里 _path_stat 只是一个 os.stat() 调用,但本地化以避免导入。这个 _fill_cache() 方法执行 os.listdir() 打电话。

在一些windows文件系统中, 纽约时报 是出了名的低,高达2秒。对于您的情况,分辨率显然仍然很低,缓存无法 在尝试加载第二个模块时更新。虽然ntfs文件系统可以以100ns为增量记录时间,但实际上,限制因素似乎是windows系统时钟,据我所知,它通常被限制为15ms的分辨率。 print2.py 写作后15分钟内 print1.py ,则python不会注意到。

python确实提供了清除这个缓存的方法;使用 importlib.invalidate_caches() method ;这将重置 _path_mtime 属性 FileFinder 实例返回到 -1 ,强制 _填充缓存() 打电话。

正如职能部门的文件所述:

如果在程序运行时创建/安装了任何模块,则应调用此函数,以确保所有查找程序都会注意到新模块的存在。

6 年前
回复了 Martijn Pieters 创建的主题 » 使flask服务器和jquery通信[复制]

首先, .json 属性是委托给 request.get_json() method ,你为什么会看到 None 在这里。

您需要将请求内容类型设置为 application/json 对于 杰森 财产和 .get_json() 方法(不带参数)将产生 没有 否则。见 Flask Request documentation :

如果mimetype指示json,则将包含解析的json数据( 应用程序/json is_json() ),否则 没有 .

你看得出 请求。获取json() 通过传递内容类型要求 force=True 关键字参数。

注意,如果 例外 此时引发(可能导致400个错误的请求响应),您的json 数据 无效。它在某种程度上格式不正确;您可能需要使用json验证器来检查它。

6 年前
回复了 Martijn Pieters 创建的主题 » 如何跳过python中*args之前的默认参数[duplicate]

*args 仅捕获未另行定义的任何位置参数; y=10 并不意味着 y 不能用作位置参数。所以 Y 指定第一个位置参数。

你可以阻止 Y 通过使其成为 keyword-only argument . 你这样做是通过提出论点 之后 这个 *精氨酸 var positional catch all参数,或者如果没有 *name 参数,在 * 单个星号:

def add_args(*args, y=10, **kwargs):
    return y, args, kwargs

def keyword_only_args(*, y=10, **kwargs):
    return y, kwargs

现在 Y 将不再捕获位置参数:

>>> def add_args(*args, y=10, **kwargs):
...     return y, args, kwargs
...
>>> add_args(1, 5, 10, 20, 50)
(10, (1, 5, 10, 20, 50), {})          # y is still 10
>>> add_args(1, 5, 10, 20, 50, y=42)  # setting y explicitly 
(42, (1, 5, 10, 20, 50), {})

你不需要 **kwargs 关键字catch all要么:

def add_args(*args, y=10):
    return y, args

但如果它存在,它需要列在最后。

仅限关键字的参数不必具有默认值, =10 可以省略,但随后该参数变为必需的,并且只能通过使用 y=value :

>>> def add_args(*args, y):  # mandatory keyword-only argument
...     return y, args
...
>>> add_args(1, 5, 10, 20, 50)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: add_args() missing 1 required keyword-only argument: 'y'
>>> add_args(1, 5, 10, 20, 50, y=42)
(42, (1, 5, 10, 20, 50))
6 年前
回复了 Martijn Pieters 创建的主题 » importerror:“time”中的错误幻数:django中的b'\x03\xf3\r\n'

包括在您的结帐中的是 .pyc 文件夹。这些是 字节缓存文件 ,存储缓存的字节码,以便python可以避免解析和编译源文件。除非计划分发没有源文件的项目,否则不应包含这些文件。

全部删除 PYC 与位于同一目录中的文件 .py 文件夹。

错误消息中的“magic number”是存储的字节码的版本号,特定的python版本只处理特定的字节码magic number;错误中的数字等于十进制的62211(当解释为一个小的尾数时),这表示 .pyc files were created with a Python 2.7 interpreter .

Python3.2切换到存储 PYC 分开归档 __pycache__ 目录,并在文件名中包含python版本。但是,任何 PYC 文件仍位于 Py 仍然支持文件,以便只允许字节码版本。删除这样的文件是安全的,因为如果将来要使用Python2.7解释器,那么将重新创建这些文件。

6 年前
回复了 Martijn Pieters 创建的主题 » 如何在python中将命名参数动态格式化为字符串?

因为您的字符串输入已经使用了有效的 string formatting placeholders ,您只需将现有数据结构转换为听写映射名称和值:

template_values = {d['name']: d['value'] for d in list_of_dictionaries}

然后将该字典应用于模板字符串, **mapping 调用语法到 str.format() method 在模板字符串上:

result = template_string.format(**template_values)

演示:

>>> list_of_dictionaries = [{'name': "a", 'value': "123"}, {'name': "b", 'value': "456"}]
>>> template_string = "blabla {a}"
>>> template_values = {d['name']: d['value'] for d in list_of_dictionaries}
>>> template_values
{'a': '123', 'b': '456'}
>>> template_string.format(**template_values)
'blabla 123'
7 年前
回复了 Martijn Pieters 创建的主题 » exec函数未按预期工作(python)[重复]

两者之间有很大的区别 exec 在python 2和 exec() 在python 3中。你正在治疗 执行程序 作为函数,但它实际上是 陈述 在python 2中。

由于这种差异,不能使用 执行程序 ,即使在python 2中也是可能的。甚至不是以前声明的变量。

locals() 只在一个方向上反映局部变量。以下内容从未在2或3中起作用:

def foo():
    a = 'spam'
    locals()['a'] = 'ham'
    print(a)              # prints 'spam'

在python 2中,使用 执行程序 语句意味着编译器知道关闭本地范围优化(从 LOAD_FAST LOAD_NAME 例如,在本地和全局范围中查找变量)。用 执行() 作为函数,该选项不再可用,函数作用域现在 总是 优化。

而且,在python 2中, 执行程序 语句显式复制在中找到的所有变量 本地人() 返回函数局部变量使用 PyFrame_LocalsToFast ,但如果没有 全局变量 当地人 提供了参数。

正确的解决方法是为您的 执行() 呼叫:

def execute(a, st):
    namespace = {}
    exec("b = {}\nprint('b:', b)".format(st), namespace)
    print(namespace['b'])

这个 exec() documentation 对此限制非常明确:

注: 违约 当地人 按功能描述行事 本地人() 以下:对默认值的修改 当地人 不应尝试使用字典。传递显式 当地人 字典,如果需要查看代码对函数后局部变量的影响 执行() 返回。

6 年前
回复了 Martijn Pieters 创建的主题 » python defaultdict深度嵌套数据结构

你的规格说明你想要的 'Category' 引用一个 列表 :

data = {0:{'data':0, 'Category':[
#                               ^ a list opening bracket

但是,你的代码使它成为一本字典:

data[i]['category'] = defaultdict(list) 

但是您的代码的其余部分会尝试处理 'category' 通过使用,再次将对象作为列表 j 作为索引。因为它是一本字典 data[i]['category'][j] 生成列表,以及 data[i]['category'][j]['name'] data[i]['category'][j]['subcategory'] 尝试用字符串索引该列表。

建造这个结构并不需要 defaultdict ;你已经知道你想要 建造 数据,您正在用循环构建嵌套结构。您只需使用常规词典和列表:

cateList = ["Main Dish", "Drink"]
n = 3 # n means the number of datasets

data = {}
for i in range(n):
    data[i] = {
        'data': i,
        'category': []
    }
    category = data[i]['category']
    for name in cateList:
        category.append({
            'name': name,
            'subcategory': []
        })

我不太清楚为什么要用从0开始的整数键构建一个外部字典。你也可以把它列出来。

6 年前
回复了 Martijn Pieters 创建的主题 » 带增强赋值的python运算符优先级

是的,这些都是一样的。python的增强赋值是 不是表达式 ,它是一个语句,在表达式优先规则中不起作用。 += 不是运算符,而是扩充赋值语句语法的一部分。

所以一切 += 是一个表达式,但是 += 本身不是,所以分配总是最后处理。

而且因为(增广的)赋值不是表达式,它也不能产生一个值来用于周围的表达式。没有 (a += b) / 2 ,这是一个语法错误,当然不是 if (a += b / 2): 或者其他类似的恶作剧。

reference documentation on Augmented assignment statements ,表示语法为:

augmented_assignment_stmt ::=  augtarget augop (expression_list | yield_expression)
augtarget                 ::=  identifier | attributeref | subscription | slicing
augop                     ::=  "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**="
                           | ">>=" | "<<=" | "&=" | "^=" | "|="

所以 augop 是语句语法的一部分,只有后面的部分是表达式(特别是 expression_list yield_expression 语法规则)。

此外,解释表明:

增强赋值计算目标(与普通赋值语句不同,它不能是解包语句)和表达式列表,对两个操作数执行特定于赋值类型的二进制操作,并将结果分配给原始目标。目标只评估一次。

所以 augtarget 首先处理部分,然后处理表达式列表(或yield表达式),然后扩展赋值应用运算符并返回结果。

此外,表达式引用文档 does include a precedence table ,但该表不包括赋值(增广或其他),因为赋值不是表达式而是语句。