Python中的更多perl样式功能模板
这是 Perl样式功能模板中的后续。同样,我是 pythonizer ,而自动perl python转换器的作者编写广义代码以将一些有趣的Perl构造转换为Python,并遇到一些困难。同样,当我生成我认为等效的代码时,循环变量的值是最后一个值,而不是函数模板成立时的值,但是在其他类似情况下,它是i的最后一个值想要,而不是原始价值。由于我喜欢使用TDD,所以让我们看一下我的测试用例,在实现引用问题中给出的解决方案之前,我写了这件事:
# test function templates per the perlref documentation
use Carp::Assert;
sub _colors {
return qw(red blue green yellow orange purple white black);
}
my $namemod = 'blue';
for my $name (_colors()) {
$name2 = $name;
my $name1 = $name;
no strict 'refs';
*$name = sub { $name3 = $name; $name4 = $name2; $name5 = $name1; $name6 = $namemod; $namemod .= 'x'; return "<FONT COLOR='$name'>@_</FONT>" };
$name1 = "$name$name";
}
$namemod = 'yellow';
assert(red("careful") eq "<FONT COLOR='red'>careful</FONT>");
assert($name3 eq 'red');
assert($name4 eq 'black');
assert($name5 eq 'redred');
assert($name6 eq 'yellow');
assert($namemod eq 'yellowx');
assert(green("light") eq "<FONT COLOR='green'>light</FONT>");
assert($name3 eq 'green');
assert($name4 eq 'black');
assert($name5 eq 'greengreen');
assert($name6 eq 'yellowx');
assert($namemod eq 'yellowxx');
print "$0 - test passed!\n";
这是我当前版本的Pythonizer生成的等效代码:
#!/usr/bin/env python3
# Generated by "pythonizer -v0 -m test_function_templates.pl" v0.978 run by JO2742 on Fri Jun 17 17:48:09 2022
# test function templates per the perlref documentation
import builtins, sys, perllib
_str = lambda s: "" if s is None else str(s)
perllib.init_package("main")
# SKIPPED: use Carp::Assert;
def _colors(*_args):
return "red blue green yellow orange purple white black".split()
_args = perllib.Array()
builtins.__PACKAGE__ = "main"
namemod = "blue"
for name in _colors():
name2 = name
name1 = name
pass # SKIPPED: no strict 'refs';
def _f14(*_args):
global name2, name3, namemod, name4, name, name1, name6, name5
name3 = name
name4 = name2
name5 = name1
name6 = namemod
namemod += "x"
return f"<FONT COLOR='{name}'>{perllib.LIST_SEPARATOR.join(map(_str,_args))}</FONT>"
globals()[name] = _f14
name1 = f"{name}{name}"
namemod = "yellow"
assert _str(red("careful")) == "<FONT COLOR='red'>careful</FONT>"
assert name3 == "red"
assert name4 == "black"
assert name5 == "redred"
assert name6 == "yellow"
assert namemod == "yellowx"
assert _str(green("light")) == "<FONT COLOR='green'>light</FONT>"
assert name3 == "green"
assert name4 == "black"
assert name5 == "greengreen"
assert name6 == "yellowx"
assert namemod == "yellowxx"
perllib.perl_print(f"{sys.argv[0]} - test passed!")
此代码在此错误中失败:assert:
assert。 _str(main.red(“ cypecle”))==“&lt; font color ='red'&gt; cypecy&lt;/font&gt;
,因为它使用了名称的最后值(黑色),而不是名称的值在循环中定义函数时。 //stackoverflow.com/users/7438379/kamel">@kamel 都可以解决此问题,但是,他们也将无法获得name3,name4,name5或nameMod的其他值我试图理解我应该在哪些情况下应用修复程序(例如,在@cyrille pontvieux案例中,将值作为参数传递而不是标记全局,并使用functools.partials.partials.partial。案例,我应该不理会我现有的代码。
This is a follow up to perl style Function Templates in python. Again, I'm the author of pythonizer, and automatic perl to python converter, and I'm trying to write generalized code to convert some interesting perl constructs to python, and having some difficulty. Again, when I generate what I think is the equivalent code, the value of the loop variable is the last value instead of the value that it was when the function template comes into existence, but in other similar cases it IS the last value that I want, not the original value. Since I love using TDD, let's look at my test case, which I wrote before implementing the solution given in the referenced question:
# test function templates per the perlref documentation
use Carp::Assert;
sub _colors {
return qw(red blue green yellow orange purple white black);
}
my $namemod = 'blue';
for my $name (_colors()) {
$name2 = $name;
my $name1 = $name;
no strict 'refs';
*$name = sub { $name3 = $name; $name4 = $name2; $name5 = $name1; $name6 = $namemod; $namemod .= 'x'; return "<FONT COLOR='$name'>@_</FONT>" };
$name1 = "$name$name";
}
$namemod = 'yellow';
assert(red("careful") eq "<FONT COLOR='red'>careful</FONT>");
assert($name3 eq 'red');
assert($name4 eq 'black');
assert($name5 eq 'redred');
assert($name6 eq 'yellow');
assert($namemod eq 'yellowx');
assert(green("light") eq "<FONT COLOR='green'>light</FONT>");
assert($name3 eq 'green');
assert($name4 eq 'black');
assert($name5 eq 'greengreen');
assert($name6 eq 'yellowx');
assert($namemod eq 'yellowxx');
print "$0 - test passed!\n";
Here is the equivalent code generated by my current version of pythonizer:
#!/usr/bin/env python3
# Generated by "pythonizer -v0 -m test_function_templates.pl" v0.978 run by JO2742 on Fri Jun 17 17:48:09 2022
# test function templates per the perlref documentation
import builtins, sys, perllib
_str = lambda s: "" if s is None else str(s)
perllib.init_package("main")
# SKIPPED: use Carp::Assert;
def _colors(*_args):
return "red blue green yellow orange purple white black".split()
_args = perllib.Array()
builtins.__PACKAGE__ = "main"
namemod = "blue"
for name in _colors():
name2 = name
name1 = name
pass # SKIPPED: no strict 'refs';
def _f14(*_args):
global name2, name3, namemod, name4, name, name1, name6, name5
name3 = name
name4 = name2
name5 = name1
name6 = namemod
namemod += "x"
return f"<FONT COLOR='{name}'>{perllib.LIST_SEPARATOR.join(map(_str,_args))}</FONT>"
globals()[name] = _f14
name1 = f"{name}{name}"
namemod = "yellow"
assert _str(red("careful")) == "<FONT COLOR='red'>careful</FONT>"
assert name3 == "red"
assert name4 == "black"
assert name5 == "redred"
assert name6 == "yellow"
assert namemod == "yellowx"
assert _str(green("light")) == "<FONT COLOR='green'>light</FONT>"
assert name3 == "green"
assert name4 == "black"
assert name5 == "greengreen"
assert name6 == "yellowx"
assert namemod == "yellowxx"
perllib.perl_print(f"{sys.argv[0]} - test passed!")
This code fails with this error: assert _str(main.red("careful")) == "<FONT COLOR='red'>careful</FONT>
because it's using the last value of name (black), not the value of name when the function was defined in the loop. The fixes recommended by @Cyrille Pontvieux and @Kamel would both fix this issue, however, they would also fail to get the other values of name3, name4, name5, or namemod correct. So I'm left trying to understand in which circumstances should I apply the fix (e.g. in the @Cyrille Pontvieux case, passing the value as an argument instead of marking it global, and using the functools.partial on the reference to the function), and which case I should leave my existing generated code alone.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
老实说,我实际上并不了解此代码以及为什么在Perl中工作,因此制作Python版本确实很具有挑战性。我能够通过所有测试案例,但两个案例都可以通过。
其余两个测试用例都是我不明白为什么它们在Perl中工作的案例。
servert name5 =='redred'
和assert name5 =='greengreen'
希望这包含一些至少可以帮助您比以前更进一步的东西。
编辑:糟糕,错过了一行
name1 = name
- 对测试没有影响I'll be honest, I don't actually understand this code and why works in Perl, so it's really challenging to make a Python version of it. I was able to get all tests cases to pass but two though.
The remaining two test cases are both ones that I don't understand why they work in Perl.
assert name5 == 'redred'
andassert name5 == 'greengreen'
Hope this contains something that at least helps you get a little further along than you were though.
edit: oops, missed a line
name1 = name
- it had no impact on the tests though