在 Cython 文档中有一个 example他们给出了两种编写 C/Python 混合方法的方法。一个显式的,带有用于快速 C 访问的 cdef 和用于从 Python 访问的包装器 def:
cdef class Rectangle:
cdef int x0, y0
cdef int x1, y1
def __init__(self, int x0, int y0, int x1, int y1):
self.x0 = x0; self.y0 = y0; self.x1 = x1; self.y1 = y1
cdef int _area(self):
cdef int area
area = (self.x1 - self.x0) * (self.y1 - self.y0)
if area < 0:
area = -area
return area
def area(self):
return self._area()
cdef class Rectangle:
cdef int x0, y0
cdef int x1, y1
def __init__(self, int x0, int y0, int x1, int y1):
self.x0 = x0; self.y0 = y0; self.x1 = x1; self.y1 = y1
cpdef int area(self):
cdef int area
area = (self.x1 - self.x0) * (self.y1 - self.y0)
if area < 0:
area = -area
return area
最佳答案
chrisb 的回答为您提供了所有您需要知道的信息,但如果您喜欢血腥的细节......
但首先,从冗长的分析中得出的结论概括如下:
cpdef 没有太大区别并通过 cdef 推出它+ def性能方面。生成的 c 代码几乎相同。 cpdef -approach 在存在继承层次结构的情况下可以稍微快一点,但没有什么值得兴奋的。 cpdef -syntax 有其优势,因为生成的代码更清晰(至少对我而言)和更短。 cpdef do_nothing_cp():
pass
__pyx_f_3foo_do_nothing_cp,因为我的扩展名为 foo,但实际上您只需要查找 f 前缀)。 __pyx_pf_3foo_2do_nothing_cp - 前缀 pf ),它不会复制代码并在途中的某个地方调用快速函数。 __pyx_pw_3foo_3do_nothing_cp (前缀 pw)do_nothing_cp方法定义发出,这就是python-wrapper的作用,这是存放foo.do_nothing_cp时应该调用哪个函数的地方被调用。 static PyMethodDef __pyx_methods[] = {
{"do_nothing_cp", (PyCFunction)__pyx_pw_3foo_3do_nothing_cp, METH_NOARGS, 0},
{0, 0, 0, 0}
};
cdef函数,只有第一步发生,对于 def - 功能仅步骤 2-4。foo并调用 foo.do_nothing_cp()发生以下情况:do_nothing_cp找到了,在我们的例子中是 python-wrapper pw -功能。 pw -function 通过函数指针调用,并调用 pf -function(作为 C 功能)pf -函数调用快速f -功能。 do_nothing_cp 会发生什么在 cython 模块内?def call_do_nothing_cp():
do_nothing_cp()
f -function 通过 c 函数调用,绕过 pw和 pf职能。cdef 会发生什么def 中的函数-功能?cdef _do_nothing():
pass
def do_nothing():
_do_nothing()
_do_nothing -function 被创建,对应于f - 以上功能。 pf -功能为 do_nothing创建,调用 _do_nothing在路上的某个地方。 pw创建了包装 pf 的函数-功能foo.do_nothing通过函数指针指向 python 包装器 pw -功能。 cpdef 没有太大区别-方法。cdef -functions 只是简单的 c-function,但是 def和 cpdef函数是第一类的python函数 - 你可以这样做:foo.do_nothing=foo.do_nothing_cp
>>> import foo
>>> %timeit foo.do_nothing_cp
51.6 ns ± 0.437 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
>>> %timeit foo.do_nothing
51.8 ns ± 0.369 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
objdump -d foo.so ),我们可以看到 C 编译器已经内联了对 cpdef 版本 do_nothing_cp 的所有调用。 : 0000000000001340 <__pyx_pw_3foo_3do_nothing_cp>:
1340: 48 8b 05 91 1c 20 00 mov 0x201c91(%rip),%rax
1347: 48 83 00 01 addq $0x1,(%rax)
134b: c3 retq
134c: 0f 1f 40 00 nopl 0x0(%rax)
do_nothing (我必须承认,我有点惊讶,还不明白原因):0000000000001380 <__pyx_pw_3foo_1do_nothing>:
1380: 53 push %rbx
1381: 48 8b 1d 50 1c 20 00 mov 0x201c50(%rip),%rbx # 202fd8 <_DYNAMIC+0x208>
1388: 48 8b 13 mov (%rbx),%rdx
138b: 48 85 d2 test %rdx,%rdx
138e: 75 0d jne 139d <__pyx_pw_3foo_1do_nothing+0x1d>
1390: 48 8b 43 08 mov 0x8(%rbx),%rax
1394: 48 89 df mov %rbx,%rdi
1397: ff 50 30 callq *0x30(%rax)
139a: 48 8b 13 mov (%rbx),%rdx
139d: 48 83 c2 01 add $0x1,%rdx
13a1: 48 89 d8 mov %rbx,%rax
13a4: 48 89 13 mov %rdx,(%rbx)
13a7: 5b pop %rbx
13a8: c3 retq
13a9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
cpdef version 稍微快一点,但无论如何与 python 函数调用的开销相比,差别不大。cdef class A:
cpdef do_nothing_cp(self):
pass
f发出函数的 -prefix-version pf)版本,它调用 f -功能pw)包装了 pf -version 并用于注册。 do_nothing_cp注册为类 A 的方法通过 tp_methods -PyTypeObject 的指针. static PyMethodDef __pyx_methods_3foo_A[] = {
{"do_nothing", (PyCFunction)__pyx_pw_3foo_1A_1do_nothing_cp, METH_NOARGS, 0},
...
{0, 0, 0, 0}
};
....
static PyTypeObject __pyx_type_3foo_A = {
...
__pyx_methods_3foo_A, /*tp_methods*/
...
};
self作为一个额外的论点 - 但还有更多: f -function 如果不是从相应的 pf 调用,则执行函数调度函数,这个调度如下(我只保留重要部分):static PyObject *__pyx_f_3foo_1A_do_nothing_cp(CYTHON_UNUSED struct __pyx_obj_3foo_A *__pyx_v_self, int __pyx_skip_dispatch) {
if (unlikely(__pyx_skip_dispatch)) ;//__pyx_skip_dispatch=1 if called from pf-version
/* Check if overridden in Python */
else if (look-up if function is overriden in __dict__ of the object)
use the overriden function
}
do the work.
foo :cdef class A:
cpdef do_nothing_cp(self):
pass
cdef class B(A):
cpdef call_do_nothing(self):
self.do_nothing()
B().call_do_nothing() 时会发生什么?B-pf-call_do_nothing , B-f-call_do_nothing , A-f-do_nothing_cp ,绕过 pw和 pf -版本。 C ,覆盖 do_nothing_cp -功能?import foo
def class C(foo.B):
def do_nothing_cp(self):
print("I do something!")
C().call_do_nothing()造成:call_do_nothing' of the C -class being located and called which means, B 的 pw-call_do_nothing' -class 被定位和调用,B-pf-call_do_nothing , B-f-call_do_nothing , A-f-do_nothing (正如我们已经知道的!),绕过 pw和 pf -版本。 A-f-do_nothing() 中调度调用为了得到正确的C.do_nothing()称呼!幸运的是,我们手头的函数中有这个调度!C 会怎样?也是cdef -类(class)?发送通过 __dict__不会工作,因为 cdef 类没有 __dict__ ?B.call_do_nothing() 中f-do_nothing -function 不是直接调用,而是通过指针调用,该指针取决于对象的类(可以看到在 __pyx_pymod_exec_XXX 中设置的那些“虚拟表”,例如 __pyx_vtable_3foo_B.__pyx_base )。因此__dict__ -调度在A-f-do_nothing()在纯 cdef 层次结构的情况下不需要 -function。cpdef与 cdef + def我得到: cpdef def+cdef
A.do_nothing 107ns 108ns
B.call_nothing 109ns 116ns
cpdef稍微快一点。
关于python - cpdef 和封装在 def 中的 cdef 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48864631/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何