|
给出以下代码有什么作用?if __name__ == "__main__":?9 u' T1 q1 }+ ` z! c" y
# Threading exampleimport time,threaddef myfunction(string,sleeptime,lock,*args): while True: lock.acquire() time.sleep(sleeptime) lock.release() time.sleep(sleeptime)if __name__ == "__main__": lock = thread.allocate_lock() thread.start_new_thread(myfunction,("Thread #: 1",2,lock)) thread.start_new_thread(myfunction,("Thread #: 2",2,lock)), Q0 `' G+ R* H1 V
$ O( _4 M K$ v: b5 j0 ^1 I 解决方案: : A/ ^+ Q" X) z5 ]) Q
简答它是模型代码,可以防止用户无意中调用脚本。以下是脚本中省略守卫的一些常见问题:% i/ I* Z+ z/ b) G7 ~- p p; m8 G
如果你在另一个脚本(例如(例如)import my_script_without_a_name_eq_main_guard)导入无保护脚本时,第二个脚本将触发第一个脚本在导入时运行并使用第二个脚本的命令行参数。这几乎总是一个错误。$ M; {3 H/ S, e! t
如果你在guardless 脚本中有一个自定义类,并将其保存到pickle 如果在另一个脚本中取消触发guardless 脚本的引入与上一个项目符号中概述的问题相同。长答案为了更好地理解为什么以及它有多重要,我们需要退一步来理解 Python 如何初始化脚本,如何与模块导入机制交互。2 A2 l, U0 o/ v% C/ @; [
每当 Python 当解释器读取源文件时,它会做两件事:
. Z2 ~' w+ H i4 O7 P( G3 j它设置了一些特殊的变量,如__name__,然后
/ v o5 P! _& m, G$ g) z* y+ a' O在执行文件中找到的所有代码。让我们看看它是如何工作的,以及它和它__name__我们在 Python 脚本中经常看到的检查相关问题有什么关系?3 U4 k K4 r9 T* W
代码示例让我们用稍微不同的代码示例来探索导入和脚本的工作方法。假设以下内容在名称中foo.py.6 g: j4 b8 P( H1 A( b4 e
# Suppose this is foo.py.print("before import")import mathprint("before functionA")def functionA(): print("Function A")print("before functionB")def functionB(): print("Function B {}".format(math.sqrt(100)))print("before __name__ guard")if __name__ == '__main__ functionA() functionB()print("after __name__ guard")! L& O* c3 g# @* E2 \
特殊变量当 Python 当解释器读取源文件时,它首先定义了一些特殊的变量。在这种情况下,我们关心__name__变量。
0 u. F1 d/ j+ _; K当你的模块是主程序时
; I, U" V2 V \以模块(源文件)为主程序,例如% K, c" p6 Z+ s$ F" X
python foo.py
: [5 w$ ~1 R3 S R 解释器将硬编码字符串赋值"__main__"给__name__变量,即
* R' I6 _, x# R( v! j. @# It's as if the interpreter inserts this at the top# of your module when run as the main program.__name__ = "__main__"
, K# L* h" ?6 p) Z' Y8 R 当您的模块被另一个导入时- f: p' Q" \1 i ]% d* X% I
另一方面,假设其他模块是主程序,并导入您的模块。这意味着主程序或主程序导入的其他模块中有这样的句子:8 ^' \9 y4 P8 r* W. C4 n0 A/ Z
# Suppose this is in some other main program.import foo( o. `) E' l' n' B# X) F: e4 D9 K
解释器会搜索你的foo.py文件(以及搜索其他一些变体),它将在执行该模块之前"foo"导入语句中的名称分配给__name__变量,即
' u( V1 M) ?8 O# Z; |2 S0 [# It's as if the interpreter inserts this at the top# of your module when it's imported from another module.__name__ = "foo"
8 M( ]( A8 m* ]2 W, q 代码执行模块设置特殊变量后,解释器执行模块中的所有代码,一次一句。您可能希望在带有代码示例的一侧打开另一个窗口,以便您可以按照此说明操作。
" I* D3 x8 I+ }7 S总是
1 e/ ~8 {, Y+ D+ ][ol]它打印字符串"before import"(无引号)。
7 y% g* ^2 Z8 u+ M/ @3 ^" N它加载math将模块分配给名称math. 这相当于替换import math以下内容(请注意)__import__是 Python 接受字符串并触发实际导入的低级函数:[/ol]
2 M9 m, f7 s) ^6 U# Find and load a module given its string name,"math",# then assign it to a local variable called math.math = __import__("math")
& a7 F7 A) N) V' v2 r% [ [ol]它打印字符串"before functionA"。4 C1 Z: w ~9 B- X5 F
它执行def块,创建函数对象,然后将函数对象分配给一个名为 的变量functionA。
+ Q9 W J8 F( G4 t7 @, Q% y它打印字符串"before functionB"。+ l- @8 S9 K* P2 V2 z |8 M0 G8 u
它执行第二个def块,创建另一个函数对象,然后分配给 变量functionB。
0 _" W/ A8 I. D7 t0 {, q. ~它打印字符串"before __name__ guard"。[/ol]只有当你的模块是主程序时
) m ^/ X1 E% c& E+ U2 ^[ol]假如你的模块是主程序,它会看到的__name__确实设置为"__main__"并调用两个函数打印字符串"Function A"和"Function B 10.0".[/ol]只有当您的模块被另一个导入时 ]4 i0 t3 K$ V( K
[ol](相反)假如你的模块不是主程序,而是由另一个程序导入,那么__name__will "foo",not "__main__",它将跳过if句子的主体。[/ol]总是
; f* g! n; n# ] x$ x4 o[ol]它会"after __name__ guard"在两种情况下打印字符串。[/ol]概括
( O: E6 c7 i# B) Z0 n( d6 Y总之,在两种情况下打印以下内容:$ i- W) Z" q5 r) A
# What gets printed if foo is the main programbefore importbefore functionAbefore functionBbefore __name__ guardFunction AFunction B 10.0after __name__ guard# What gets printed if foo is imported as a regular modulebefore importbefore functionAbefore functionBbefore __name__ guardafter __name__ guard
, g. S* D7 _. Z 为什么这样工作?你自然会想知道为什么有人想要这个。嗯,有时候你想写一个。.py其他程序和/或模块都可以用作模块,也可以用作主程序本身。* N' v3 U- I, v/ h, W
您的模块是一个库,但您想要一个脚本模式,它运行一些单元测试或演示。" _" Q) {6 b; I2 C4 m! q
您的模块仅用作主程序,但它有一些单元测试,通过导入测试框架.py脚本和其他文件并运行特殊的测试功能来工作。您不希望它尝试运行脚本,因为它正在导入模块。8 ?6 t9 ~* L0 P! K ]" H7 [
您的模块主要用作主程序,但也为高级用户提供了对程序员友好的 API。除此之外, Python 操作脚本只设置一些魔法变量并导入脚本,非常优雅。操作脚本是导入脚本模块的副作用。
+ K- W. u" F- |+ [$ g+ h问答问:我能有多个__name__答:这很奇怪,但语言不会阻止你。
- u- L/ a7 w9 Y5 ^+ m" }7 g假设以下内容是foo2.py. 如果你python foo2.py说命令行会发生什么?为什么?6 g$ q" T, }4 [4 C* x: X
# Suppose this is foo2.py.import os,sys; sys.path.insert(0,os.path.dirname(__file__)) # needed for some interpretersdef functionA(): print("a1") from foo2 import functionB print("a2") functionB() print("a3")def functionB(): print("b")print("t1")if __name__ == "__main__": print("m1") functionA() print("m2")print("t2")
3 j) V% H. z) J 现在,如果你取消取消了它__name__签入会发生什么?foo3.py:; r8 \$ i+ o5 _% Y2 X
# Suppose this is foo3.py.import os,sys; sys.path.insert(0,os.path.dirname(__file__)) # needed for some interpretersdef functionA(): print("a1") from foo3 import functionB print("a2") functionB() print("a3")def functionB(): print("b")print("t1")print("m1")functionA()print("m2")print("t2")
4 N4 {5 R, i, z' v. f 当它被用作脚本时,它会做什么?导入模块时?8 L4 |0 C; Q9 j9 D' i3 R
# Suppose this is in foo4.py__name__ = "__main__"def bar(): print("bar")print("before __name__ guard")if __name__ == "__main__": bar()print("after __name__ guard")# m- a+ T0 C; F
|
|