我做了一个实际测量最大递归限制的小函数:
def f(x):
r = x
try:
r = f(x+1)
except Exception as e:
print(e)
finally:
return r
Run Code Online (Sandbox Code Playgroud)
知道我期待什么我检查过:
In [28]: import sys
In [29]: sys.getrecursionlimit()
Out[29]: 1000
Run Code Online (Sandbox Code Playgroud)
然而
In [30]: f(0)
maximum recursion depth exceeded
Out[30]: 970
Run Code Online (Sandbox Code Playgroud)
数字不固定,总是在~970左右,并且在python的不同实例之间略有变化(例如从spyder到system cmd提示符).
请注意我在python3上使用ipython.
这是怎么回事?为什么实际限制我会低于sys.getrecursionlimit()价值?
我正在将csh脚本转换为python脚本.该脚本调用内存密集型可执行文件,需要非常大的堆栈,因此csh脚本将stacksize设置为unlimited:
limit stacksize unlimited
Run Code Online (Sandbox Code Playgroud)
当我尝试在python中重现这个脚本时,我以一种非常天真的方式执行它们os.system,例如:
os.system('some_executable')
Run Code Online (Sandbox Code Playgroud)
但我不知道如何通过无限制的堆栈大小来告诉操作系统运行这些可执行文件.有没有办法为python脚本中的调用指定stacksize?是否有一些我应该使用的低级系统调用?是否有一个控制它的模块(类似于shutil)?
我使用以下代码解决了Euler项目的问题10,该代码通过强力实施:
def isPrime(n):
for x in range(2, int(n**0.5)+1):
if n % x == 0:
return False
return True
def primeList(n):
primes = []
for i in range(2,n):
if isPrime(i):
primes.append(i)
return primes
def sumPrimes(primelist):
prime_sum = sum(primelist)
return prime_sum
print (sumPrimes(primeList(2000000)))
Run Code Online (Sandbox Code Playgroud)
这三个功能的工作原理如下:
然后我编写了一个新函数primeListRec,它与primeList完全相同,以帮助我更好地理解递归:
def primeListRec(i, n):
primes = []
#print i
if (i != n):
primes.extend(primeListRec(i+1,n))
if (isPrime(i)):
primes.append(i)
return primes
return primes
Run Code Online (Sandbox Code Playgroud)
上面的递归函数有效,但仅适用于非常小的值,如'500'.当我输入'1000'时,该功能导致我的程序崩溃.当我输入类似'2000'的值时,Python给了我这个:
RuntimeError:超出最大递归深度.
我的递归函数出了什么问题?或者是否有一些特定的方法来避免递归限制?
我知道这个问题已得到很好的讨论但是我遇到了一个案例,我并不真正理解递归方法比使用"reduce,lambda,xrange"的方法"慢".
def factorial2(x, rest=1):
if x <= 1:
return rest
else:
return factorial2(x-1, rest*x)
def factorial3(x):
if x <= 1:
return 1
return reduce(lambda a, b: a*b, xrange(1, x+1))
Run Code Online (Sandbox Code Playgroud)
我知道python不会优化尾递归,所以问题不在于它.根据我的理解,生成器仍然应该使用+1运算符生成n个数字.所以从技术上讲,fact(n)应该n像递归一样添加一些次数.该lambda在reduce将被称为n时间就像递归方法......所以,既然我们没有尾巴调用优化在这两个情况下,堆栈将创建/销毁和返回n时间.并且if生成器中的a应检查何时引发StopIteration异常.
这让我想知道为什么递归方法仍然比另一个慢,因为递归方法使用简单的算法而不使用生成器.
在一个测试中,我用递归方法代替rest*x,x花费的时间与使用的方法相当reduce.
这是我的事实时间(400),1000次
factorial3:1.22370505333
factorial2:1.79896998405
编辑:
从制作方法开始1,以n不利于无论是不是n来1.所以不是开销-1.
此外,我们可以更快地使递归方法.我尝试了多个像全局变量这样的东西,我可以改变...使用可变上下文,将变量放在我可以像数组一样修改的单元格中,并保持不带参数的递归方法.将用于递归的方法作为参数发送,这样我们就不必在我们的范围内"取消引用"它了??!但是,没有什么能让它变得更快.
我会指出我有一个事实版本,使用比这两种方法都快得多的forloop,所以有明显的改进空间,但我不希望任何比forloop更快的东西.
我有一个带kerasRegressor的scikit-learn pipline:
estimators = [
('standardize', StandardScaler()),
('mlp', KerasRegressor(build_fn=baseline_model, nb_epoch=5, batch_size=1000, verbose=1))
]
pipeline = Pipeline(estimators)
Run Code Online (Sandbox Code Playgroud)
之后,训练pipline,我试图使用joblib保存到磁盘...
joblib.dump(pipeline, filename , compress=9)
Run Code Online (Sandbox Code Playgroud)
但我收到一个错误:
RuntimeError:超出最大递归深度
你如何将管道保存到磁盘?
我试图使用Zeep来描述给定WSDL中的操作和类型,以便程序知道操作名称,它们的参数名称,参数类型和参数属性.
此信息将用于动态生成给定WSDL的UI.
到目前为止我所获得的仅仅是操作和类型的字符串表示.使用与此答案中的代码类似的代码.
这是一个例子:
from zeep import Client
import operator
wsdl = 'http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl'
client = Client(wsdl)
# get each operation signature
for service in client.wsdl.services.values():
print("service:", service.name)
for port in service.ports.values():
operations = sorted(
port.binding._operations.values(),
key=operator.attrgetter('name'))
for operation in operations:
print("method :", operation.name)
print(" input :", operation.input.signature())
print()
print()
# get a specific type signature by name
complextype = client.get_type('ns0:CartGetRequest')
print(complextype.name)
print(complextype.signature())
Run Code Online (Sandbox Code Playgroud)
这给出了如下输出(为简洁起见缩短)
[...]
method : CartCreate
input : MarketplaceDomain: xsd:string, AWSAccessKeyId: xsd:string, AssociateTag: xsd:string, Validate: xsd:string, XMLEscaping: …Run Code Online (Sandbox Code Playgroud) 我有嵌套字典:
{'key0': {'attrs': {'entity': 'p', 'hash': '34nj3h43b4n3', 'id': '4130'},
u'key1': {'attrs': {'entity': 'r',
'hash': '34njasd3h43b4n3',
'id': '4130-1'},
u'key2': {'attrs': {'entity': 'c',
'hash': '34njasd3h43bdsfsd4n3',
'id': '4130-1-1'}}},
u'key3': {'attrs': {'entity': 'r',
'hash': '34njasasasd3h43b4n3',
'id': '4130-2'},
u'key4': {'attrs': {'entity': 'c',
'hash': '34njawersd3h43bdsfsd4n3',
'id': '4130-2-1'}},
u'key5': {'attrs': {'entity': 'c',
'hash': '34njawersd3h43bdsfsd4n3',
'id': '4130-2-2'}}}},
'someohterthing': 'someothervalue',
'something': 'somevalue'}
Run Code Online (Sandbox Code Playgroud)
给予id - 一个ids喜欢4130的4130-2-2.
导航到正确字典的最简单方法是什么?
就像给定id的4130-2-1那样它应该到达字典key=key5
非xml方法请.
编辑(1):筑巢之间1到4的水平,但我知道我的嵌套前解析.
编辑(2):修复了代码.
**编辑(3):**再次固定代码的字符串值 …
可能重复:
最大递归深度?
我的代码有另一个问题.我正在研究我在Vpython中的第一个程序,我必须模拟混合两种气体.首先我遇到了边界问题,但现在当球(代表气体粒子)留在边界内时,存在不同的错误.几秒钟后,我收到一个错误,该错误显示在我的函数的源代码下面.码:
def MovingTheBall(listOfBalls,position,numCell,flagOfExecution):
flag = 0
if flagOfExecution==0:
positionTmp = position
else:
positionTmp = (position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0)
for i in range( 0, len(listOfBalls) ):
if positionTmp==listOfBalls[i].pos:
flag=1
if flag==1:
return MovingTheBall(lista,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
else:
if positionTmp[0]==0 or positionTmp[0]>=numCell or positionTmp[0]<=-numCell or positionTmp[1]>=numCell or positionTmp[1]<=-numCell:
return MovingTheBall(lista,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
return positionTmp
Run Code Online (Sandbox Code Playgroud)
错误是:
return MovingTheBall(listOfBalls,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
File "gaz.txt", line 138, in MovingTheBall
return MovingTheBall(listOfBalls,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
File "gaz.txt", line 138, in MovingTheBall
return MovingTheBall(listOfBalls,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
File "gaz.txt", line 138, in MovingTheBall
return MovingTheBall(listOfBalls,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
File "gaz.txt", line 138, in MovingTheBall
return …Run Code Online (Sandbox Code Playgroud) Python具有最大递归深度,但没有最大迭代深度.为什么递归受限制?像迭代这样处理递归是不是更自然,而不是限制递归调用的数量?
我只想说这个问题的根源来自于尝试实现一个流(有关流的更多详细信息,请参阅此问题).例如,假设我们要编写一个流来生成自然数:
def stream_accum(s, n): # force the stream to a list of length n
def loop(s, acc):
if len(acc) == n:
return acc
hd, tl = s()
return loop(tl, acc + [hd])
return loop(s, [])
def nats():
def loop(n):
return n, lambda: loop(n+1)
return loop(1)
Run Code Online (Sandbox Code Playgroud)
流的递归定义非常吸引人.但是,我想更好/更pythonic的方法是使用发电机.
我已经在python中编写了一个verilog(逻辑门及其连接描述)模拟器作为实验的一部分.
我遇到了堆栈限制的问题,所以我做了一些阅读,发现Python没有"尾调用优化"功能(即随着递归的进行动态删除堆栈条目)
我在这方面主要有两个问题:
1)如果我提高了堆栈限制,sys.setrecursionlimit(15000)它是否会影响性能(内存 - 我不在乎)?
2)我有什么方法可以绕过这个限制,假设我可以没有堆栈跟踪.
我问这个是因为Verilog主要处理可以使用递归函数以优雅方式实现的状态机.
另外,如果我可以添加,在递归函数调用的情况下,如果有错误,我更依赖于导致此错误的输入而不是堆栈跟踪.
我是Python新手,所以也许专家可能认为Python堆栈跟踪对于调试递归函数调用非常有用......如果是这种情况,我会非常乐意学习如何做到这一点.
最后,建议在Python中编写递归函数还是应该转移到其他语言?
如果有任何解决方法,我可以继续使用python进行递归函数,我想知道是否有任何性能影响(我可以做分析).
python ×10
recursion ×6
stack ×2
csh ×1
dictionary ×1
joblib ×1
keras ×1
nested ×1
optimization ×1
parsing ×1
scikit-learn ×1
simulation ×1
soap ×1
soappy ×1
struct ×1
vpython ×1
wsdl ×1
zeep ×1