การเรียก "ชื่อส่วนกลาง" foo "ไม่ได้กำหนดไว้" ด้วยเวลาของ Python


92

ฉันพยายามค้นหาว่าต้องใช้เวลาเท่าไรในการดำเนินการคำสั่ง Python ดังนั้นฉันจึงดูออนไลน์และพบว่าไลบรารีมาตรฐานมีโมดูลที่เรียกว่าtimeitซึ่งอ้างว่าจะทำอย่างนั้น:

import timeit

def foo():
    # ... contains code I want to time ...

def dotime():
    t = timeit.Timer("foo()")
    time = t.timeit(1)
    print "took %fs\n" % (time,)

dotime()

อย่างไรก็ตามสิ่งนี้ก่อให้เกิดข้อผิดพลาด:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in dotime
  File "/usr/local/lib/python2.6/timeit.py", line 193, in timeit
    timing = self.inner(it, self.timer)
  File "<timeit-src>", line 6, in inner
NameError: global name 'foo' is not defined

ฉันยังใหม่กับ Python และฉันไม่เข้าใจปัญหาการกำหนดขอบเขตทั้งหมดที่มี แต่ฉันไม่รู้ว่าทำไมตัวอย่างข้อมูลนี้ใช้ไม่ได้ ความคิดใด ๆ ?

คำตอบ:


93

เปลี่ยนบรรทัดนี้:

t = timeit.Timer("foo()")

สำหรับสิ่งนี้:

t = timeit.Timer("foo()", "from __main__ import foo")

ตรวจสอบลิงค์ที่คุณให้ไว้ที่ด้านล่างสุด

เพื่อให้โมดูล timeit เข้าถึงฟังก์ชันที่คุณกำหนดคุณสามารถส่งพารามิเตอร์การตั้งค่าซึ่งมีคำสั่งนำเข้า:

ฉันเพิ่งทดสอบบนเครื่องของฉันและมันใช้งานได้กับการเปลี่ยนแปลง


28
มันได้ผล! อย่างไรก็ตามนี่เป็นการออกแบบอินเทอร์เฟซที่ค่อนข้างโง่หากฉันต้องใส่ทั้งคำสั่งที่ฉันต้องการใช้เวลาเป็นสตริงและเพื่อนำเข้าโมดูลหลักเพื่อให้มันใช้งานได้
Kyle Cronin

2
การกำหนดเนมสเปซของ Python นั้นทำให้ฉันคลั่ง ฉันคิดว่ามันสมเหตุสมผลสำหรับจิตใจบางอย่าง แต่ความคิดแบบนั้นไม่ใช่สิ่งที่ฉันเกิดขึ้นกับการวางตัว ขอบคุณ $ DEITY สำหรับ Ruby ในกรณีของฉัน
womble

5
womble นี่คือหูดไม่ใช่ปัญหาเนมสเปซของหลามทั่วไป กระทู้หลัก: writeonly.wordpress.com/2008/09/12/… มีลิงก์ไปยังการสนทนาอื่น ๆ เกี่ยวกับเรื่องนี้
Gregg Lind

1
@Gregg ลิงก์ไม่สามารถเข้าถึงได้อีกต่อไป (ข้อผิดพลาด 404) มีอะไรอยู่ในการสนทนานั้น?
ovgolovin

2
ลิงค์เหล่านั้นตายหมดแล้ว
endolith

25

ด้วย Python 3 คุณสามารถใช้ globals=globals()

t = timeit.Timer("foo()", globals=globals())

จากเอกสารประกอบ :

อีกทางเลือกหนึ่งคือการส่งผ่านglobals()ไปยังglobalsพารามิเตอร์ซึ่งจะทำให้โค้ดถูกเรียกใช้ภายในเนมสเปซส่วนกลางปัจจุบันของคุณ วิธีนี้สะดวกกว่าการระบุการนำเข้าทีละรายการ


3
ใช้งานได้กับ Python 3 เท่านั้น globalsไม่ใช่พารามิเตอร์สำหรับ Python 2timeit
tony_tiger

21

คุณสามารถลองแฮ็คนี้:

import timeit

def foo():
    print 'bar'

def dotime():
    t = timeit.Timer("foo()")
    time = t.timeit(1)
    print "took %fs\n" % (time,)

import __builtin__
__builtin__.__dict__.update(locals())

dotime()

1
การแฮ็กนี้ดีมากหากคุณต้องการโค้ดการตั้งค่าที่ซับซ้อน
Luís Marques

ดีกว่าทางเลือกรหัสเริ่มต้นที่ระบุในการตอบกลับอื่น ๆ (เช่นดีกว่าt = timeit.Timer("foo()", "from __main__ import foo")) โดยเฉพาะอย่างยิ่งหากคุณต้องการทดสอบฟังก์ชั่นต่างๆจะช่วยประหยัดการพิมพ์ได้มาก!
อาทิตย์

1
ฉันมีการนำเข้าประมาณ 20 รายการดังนั้นการส่งผ่านเป็นอาร์กิวเมนต์จะยุ่งอย่างรวดเร็ว แฮ็คนี้ยอดเยี่ยมมาก!
kramer65

7
เยี่ยมมาก! ใน python3 แต่คุณต้องการimport builtinsและ 'builtins .__ dict __. update (local ())'
greole

คุณสามารถจับเวลาหลายฟังก์ชันในฟังก์ชัน Time () ได้หรือไม่?
edo101

8
t = timeit.Timer("foo()", "from __main__ import foo")

เนื่องจากเวลาไม่ได้อยู่ในขอบเขตของคุณ


0

เพิ่มในการตั้งค่าของคุณ "import thisfile;"

จากนั้นเมื่อคุณเรียกใช้ฟังก์ชันการตั้งค่า myfunc () ให้ใช้ "thisfile.myfunc ()"

เช่น "thisfile.py"

def myfunc():

 return 5

def testable(par):

 pass



t=timeit.timeit(stmt="testable(v)",setup="import thisfile; v=thisfile.myfunc();").repeat(10)

print( t )
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.