在这里,我们将给大家分享关于为什么在Python中使用抽象基类?的知识,让您更了解python抽象基类的作用的本质,同时也会涉及到如何更有效地asp.net–为什么在“GlimpseWebDebugg
在这里,我们将给大家分享关于为什么在 Python 中使用抽象基类?的知识,让您更了解python抽象基类的作用的本质,同时也会涉及到如何更有效地asp.net – 为什么在“Glimpse Web Debugger”中没有显示“Route”选项卡?、bash – 为什么在[[…]]之间不执行引用删除?、c – 为什么在!= / ==和u0026u0026 / ||时gdb不能评估函数结合在一个表达式?、C# 5 异步 CTP:为什么在 EndAwait 调用之前在生成的代码中将内部“状态”设置为 0?的内容。
本文目录一览:- 为什么在 Python 中使用抽象基类?(python抽象基类的作用)
- asp.net – 为什么在“Glimpse Web Debugger”中没有显示“Route”选项卡?
- bash – 为什么在[[…]]之间不执行引用删除?
- c – 为什么在!= / ==和u0026u0026 / ||时gdb不能评估函数结合在一个表达式?
- C# 5 异步 CTP:为什么在 EndAwait 调用之前在生成的代码中将内部“状态”设置为 0?
为什么在 Python 中使用抽象基类?(python抽象基类的作用)
因为我习惯了 Python 中鸭子类型的旧方法,所以我无法理解对
ABC(抽象基类)的需求。关于如何使用它们的帮助很好。
我试图阅读PEP中的基本原理,但它超出了我的想象。如果我正在寻找一个可变序列容器,我会检查__setitem__
,或者更有可能尝试使用它(EAFP)。我还没有遇到过数字模块的实际用途,它确实使用了 ABC,但这是我必须理解的最接近的。
谁能给我解释一下原因吗?
答案1
小编典典简洁版本
ABC 在客户端和实现的类之间提供更高级别的语义契约。
长版
类与其调用者之间存在契约。该类承诺做某些事情并具有某些属性。
合同有不同的层次。
在非常低的级别上,合同可能包括方法的名称或其参数的数量。
在静态类型语言中,该契约实际上将由编译器强制执行。在 Python
中,您可以使用EAFP或类型自省来确认未知对象是否符合此预期合同。
但合同中也有更高级别的语义承诺。
例如,如果有一个__str__()
方法,它应该返回对象的字符串表示。它 可以
删除对象的所有内容,提交事务并从打印机中吐出一个空白页......但是对于它应该做什么有一个共同的理解,在 Python 手册中进行了描述。
这是一种特殊情况,在手册中描述了语义契约。方法应该print()
怎么做?它应该将对象写入打印机还是将一行写入屏幕,还是其他什么?这取决于 -
您需要阅读评论以了解此处的完整合同。一段简单地检查print()
方法是否存在的客户端代码已经确认了合同的一部分——可以进行方法调用,但没有就调用的更高级别语义达成一致。
定义抽象基类 (ABC) 是在类实现者和调用者之间产生契约的一种方式。它不仅仅是一个方法名称列表,而是对这些方法应该做什么的共同理解。如果你从这个 ABC
继承,你承诺遵循注释中描述的所有规则,包括print()
方法的语义。
Python 的鸭子类型在灵活性方面比静态类型有很多优势,但它并不能解决所有问题。ABC 提供了介于 Python
的自由形式和静态类型语言的束缚和纪律之间的中间解决方案。
asp.net – 为什么在“Glimpse Web Debugger”中没有显示“Route”选项卡?
然而,由于某些原因,当我打开Glimpse并尝试测试网络应用程序时,Routes选项卡不会显示。我的web.config文件(下图)中的Glimpse设置不会显示任何黑名单的插件:
On = True Allowed IP's = 127.0.0.1 ::1 Allowed ContentType's = text/html Blacklisted Plugins =
这些是Glimpse / Config页面正在运行的插件列表:
Glimpse.Core.Plugin.Request Glimpse.Core.Plugin.Environment Glimpse.Core.Plugin.Trace Glimpse.Core.Plugin.Config Glimpse.Core.Plugin.Server Glimpse.Core.Plugin.Session
出现的唯一选项卡是:Ajax / Config / Environment / Remote / Request / Server。 “跟踪”选项卡出现,但是显示为灰色。瞥见似乎是一个有用的工具,我想要能够测试/调试路由,但我不知道为什么它不能正常工作。我非常感谢任何帮助。
谢谢!
解决方法
在PowerShell控制台中安装Package Glimpse.MVC3,或者使用GUI安装Glimpse.MVC3。
未来,Glimpse可能会发送类似于MVC3的附加插件包。图像我们可以有Glimpse.SharePoint或Glimpse.Orchard …
bash – 为什么在[[…]]之间不执行引用删除?
$man bash
Word splitting and filename expansion are not performed on the words between the ‘[[’ and ‘]]’; tilde expansion,parameter and variable expansion,arithmetic expansion,command substitution,process substitution,and quote removal are performed.
$echo $BASH_VERSION 4.2.10(1)-release
命令1
$[[ "hello" =~ "he" ]] && echo YES || echo NO YES
命令2
$[[ "hello" =~ he.* ]] && echo YES || echo NO YES
命令3
$[[ "hello" =~ "he.*" ]] && echo YES || echo NO NO
为什么命令2和3不同?
Quoting the string argument to the [[ command’s =~ operator Now forces
string matching,as with the other pattern-matching operators.
我猜你正在使用bash> = ver 3.2进行测试.
这就是你引用正则表达式的原因,它正在进行简单的字符串匹配而不是正则表达式匹配.
更新:如果你想在双引号内匹配正则表达式,那么使用:
shopt -s compat31
根据手册:
compat31
If set,bash changes its behavior to that of version 3.1
with respect to quoted arguments to the conditional command’s =~ operator.
这会导致您的命令行为不同:
[[ "hello" =~ "he.*" ]] && echo YES || echo NO YES
c – 为什么在!= / ==和u0026u0026 / ||时gdb不能评估函数结合在一个表达式?
似乎至少涉及两个!= / ==和&& / ||的表达式对于向量或向量迭代器将无法在gdb中评估,并出现以下错误:
无法访问地址0x0处的内存
这是一个测试用例,接下来是我的编译行和测试:
#include <stdio.h> #include <iostream> #include <stdint.h> #include <vector> using namespace std; typedef char GUID[32]; int main(int argc,char **argv){ vector<int> vec; for (int i=0; i<5; i++){ vec.push_back(i); } for (vector<int>::iterator vecIter=vec.begin(); vecIter!=vec.end(); vecIter++){ int i=0;//Just need a line gdb will recognize for a breakpoint. } cout << vec[0] << endl;//g++ needs to include operator[] in the binary for this to work. return 0; }
这是我执行的测试的片段:
user@comp$g++ -g -O0 any_test.cpp user@comp$gdb a.out (gdb) b 16 (gdb) r Breakpoint 1,main (argc=1,argv=0x7fffffffe288) at any_test.cpp:16 16 int i=0;//Just need a line gdb will recognize for a breakpoint. (gdb) p *vecIter == vec[1] or *vecIter == vec[2] Cannot access memory at address 0x0
原始有用的声明不起作用.让我们减少一点,找到问题.
(gdb) p vec[1] or *vecIter == vec[2] Cannot access memory at address 0x0 (gdb) p vec[1] or *vecIter $1 = true (gdb) p 1 or *vecIter == vec[2] Cannot access memory at address 0x0
在’或’之后看起来问题是’==’.这和其他操作符一样吗?
(gdb) p 1 and *vecIter == vec[2] Cannot access memory at address 0x0 (gdb) p 1 and *vecIter != vec[2] Cannot access memory at address 0x0
这是一个响亮的回答.如果我为gdb提取所有功能怎么办?只是让它取消引用并比较一下?
(gdb) p 1 or *vecIter._M_current == vec._M_impl._M_start[1] $2 = true
好吧,让我们检查deref和函数的一些组合,以确保它不仅仅是导致问题的这些类型之一:
(gdb) p 1 or *vecIter._M_current == *vecIter Cannot access memory at address 0x0 (gdb) p 1 or vec._M_impl._M_start[1] == vec[1] Cannot access memory at address 0x0
如您所见,问题不是特定于向量或其迭代器.如果在&& / ||之后插入并且在== /!=的任一侧插入任何一个操作符(函数)将触发此问题.
编辑:再次忘记一个问题.我的问题是:
为什么我在“p * vecIter == vec [1]或* vecIter == vec [2]”行中得到“无法访问地址0x0的内存”?
解决方法
int& g() { static int i; return i; } int main() {}
同样的问题出现了(我使用的是gdb 7.8.1):
(gdb) p 0 || +g() Cannot access memory at address 0x0
解决方法是将引用转换为指针并将其间接转换:
(gdb) p 0 || +*&g() $1 = true
提起了一个错误:https://sourceware.org/bugzilla/show_bug.cgi?id=17904
C# 5 异步 CTP:为什么在 EndAwait 调用之前在生成的代码中将内部“状态”设置为 0?
昨天我正在讨论新的 C#“异步”特性,特别是深入研究生成的代码是什么样的,以及the GetAwaiter()
/BeginAwait()
/EndAwait()
调用。
我们详细查看了 C# 编译器生成的状态机,有两个方面我们无法理解:
- 为什么生成的类包含一个似乎从未使用过的
Dispose()
方法和一个变量(并且该类没有实现)。$__disposing``IDisposable
- 为什么在任何调用之前将内部
state
变量设置为 0EndAwait()
,而 0 通常看起来意味着“这是初始入口点”。
我怀疑第一点可以通过在异步方法中做一些更有趣的事情来回答,尽管如果有人有任何进一步的信息,我会很高兴听到它。然而,这个问题更多地是关于第二点。
这是一段非常简单的示例代码:
using System.Threading.Tasks;class Test{ static async Task<int> Sum(Task<int> t1, Task<int> t2) { return await t1 + await t2; }}
MoveNext()
…这是为实现状态机的方法生成的代码。这是直接从 Reflector 复制的——我还没有修复无法描述的变量名称:
public void MoveNext(){ try { this.$__doFinallyBodies = true; switch (this.<>1__state) { case 1: break; case 2: goto Label_00DA; case -1: return; default: this.<a1>t__$await2 = this.t1.GetAwaiter<int>(); this.<>1__state = 1; this.$__doFinallyBodies = false; if (this.<a1>t__$await2.BeginAwait(this.MoveNextDelegate)) { return; } this.$__doFinallyBodies = true; break; } this.<>1__state = 0; this.<1>t__$await1 = this.<a1>t__$await2.EndAwait(); this.<a2>t__$await4 = this.t2.GetAwaiter<int>(); this.<>1__state = 2; this.$__doFinallyBodies = false; if (this.<a2>t__$await4.BeginAwait(this.MoveNextDelegate)) { return; } this.$__doFinallyBodies = true; Label_00DA: this.<>1__state = 0; this.<2>t__$await3 = this.<a2>t__$await4.EndAwait(); this.<>1__state = -1; this.$builder.SetResult(this.<1>t__$await1 + this.<2>t__$await3); } catch (Exception exception) { this.<>1__state = -1; this.$builder.SetException(exception); }}
它很长,但这个问题的重要内容是:
// End of awaiting t1this.<>1__state = 0;this.<1>t__$await1 = this.<a1>t__$await2.EndAwait();// End of awaiting t2this.<>1__state = 0;this.<2>t__$await3 = this.<a2>t__$await4.EndAwait();
在这两种情况下,状态都会在下一次明显观察到之前再次发生变化......那么为什么将其设置为 0
呢?如果MoveNext()
此时再次调用(直接或通过Dispose
),它将有效地再次启动异步方法,据我所知,这将是完全不合适的......如果并且MoveNext()
没有 被调用,状态的变化是无关紧要的。
这仅仅是编译器为异步重用迭代器块生成代码的副作用,它可能有更明显的解释吗?
重要免责声明
显然这只是一个 CTP 编译器。我完全希望在最终发布之前情况会发生变化——甚至可能在下一个 CTP 发布之前。这个问题绝不是试图声称这是 C#
编译器中的一个缺陷或类似的东西。我只是想弄清楚我是否错过了一个微妙的原因:)
答案1
小编典典好吧,我终于有一个真正的答案了。我有点自己解决了这个问题,但只有在团队 VB 部分的 Lucian Wischik 确认确实有充分的理由之后。非常感谢他 -
请访问他的博客(在archive.org上),它很震撼。
这里的值 0 只是特殊的,因为它
不是await
正常情况下您可能处于的有效状态。特别是,这不是状态机最终可能会在其他地方测试的状态。我相信使用任何非正值也可以正常工作:-1
不用于此,因为它在 逻辑上 不正确,因为 -1 通常表示“完成”。我可以争辩说我们现在给状态 0
赋予了额外的含义,但最终它并不重要。这个问题的重点是找出为什么要设置状态。
如果等待以捕获的异常结束,则该值是相关的。我们最终可以再次回到相同的等待语句,但我们 不能
处于表示“我正要从那个等待中回来”的状态,否则所有类型的代码都会被跳过。用一个例子来说明这一点是最简单的。请注意,我现在使用的是第二个
CTP,因此生成的代码与问题中的代码略有不同。
这是异步方法:
static async Task<int> FooAsync(){ var t = new SimpleAwaitable(); for (int i = 0; i < 3; i++) { try { Console.WriteLine("In Try"); return await t; } catch (Exception) { Console.WriteLine("Trying again..."); } } return 0;}
从概念上讲,它SimpleAwaitable
可以是任何可等待的——也许是一个任务,也许是别的东西。就我的测试而言,它总是返回 falseIsCompleted
,并在GetResult
.
这是生成的代码MoveNext
:
public void MoveNext(){ int returnValue; try { int num3 = state; if (num3 == 1) { goto Label_ContinuationPoint; } if (state == -1) { return; } t = new SimpleAwaitable(); i = 0; Label_ContinuationPoint: while (i < 3) { // Label_ContinuationPoint: should be here try { num3 = state; if (num3 != 1) { Console.WriteLine("In Try"); awaiter = t.GetAwaiter(); if (!awaiter.IsCompleted) { state = 1; awaiter.OnCompleted(MoveNextDelegate); return; } } else { state = 0; } int result = awaiter.GetResult(); awaiter = null; returnValue = result; goto Label_ReturnStatement; } catch (Exception) { Console.WriteLine("Trying again..."); } i++; } returnValue = 0; } catch (Exception exception) { state = -1; Builder.SetException(exception); return; } Label_ReturnStatement: state = -1; Builder.SetResult(returnValue);}
我不得不移动Label_ContinuationPoint
以使其成为有效代码 - 否则它不在goto
语句的范围内 - 但这不会影响答案。
想想GetResult
抛出异常时会发生什么。我们将遍历 catch 块、增量i
,然后再次循环(假设i
仍然小于
3)。我们仍然处于GetResult
调用之前的任何状态......但是当我们进入try
块内时,我们 必须 打印“In
Try”并GetAwaiter
再次调用......并且我们只会在 state 不是 1 时这样做。没有state =0
分配,它将使用现有的等待者并跳过调用Console.WriteLine
。
这是一段相当曲折的代码,但这只是表明团队必须考虑的事情。我很高兴我不负责实施这个:)
我们今天的关于为什么在 Python 中使用抽象基类?和python抽象基类的作用的分享已经告一段落,感谢您的关注,如果您想了解更多关于asp.net – 为什么在“Glimpse Web Debugger”中没有显示“Route”选项卡?、bash – 为什么在[[…]]之间不执行引用删除?、c – 为什么在!= / ==和u0026u0026 / ||时gdb不能评估函数结合在一个表达式?、C# 5 异步 CTP:为什么在 EndAwait 调用之前在生成的代码中将内部“状态”设置为 0?的相关信息,请在本站查询。
本文标签: