如果將一個project中的所有程式碼都放在一個檔案裡,會增加編寫與維護的困難,同時也難以進行團隊合作。
將大文件拆分為多個檔案 (module) 的好處:
example 1
in ano_module.py
def one_func():
print("Hello from another module.")
in try.py
from ano_module import one_func
one_func() # Hello from another module.
example 2
in ano_module.py
def one_func():
print("Hello from another module.")
def two_func():
print("Here's another function from another module.")
in try.py
from ano_module import one_func, two_func
def hello():
print("This is a hello.")
one_func() # module裡的function
hello() # try.py內部的function
two_func() # module裡的function
# Hello from another module.
# This is a hello.
# Here's another function from another module.
example 3
architecture
in some_code.py
def some_code():
print("We have some code.")
in some_more_code.py
def here_is_some_more():
print("We got some more codes here.")
in hello.py
def small_hello():
print("This is a small hello.")
in try.py
from myPackage import some_code, some_more_code
from myPackage.subPackage import hello
some_code.some_code()
some_more_code.here_is_some_more()
hello.small_hello()
# We have some code.
# We got some more codes here.
# This is a small hello.
pycache dir
執行import ...
時,module.py中的內容會被轉為byte codes ,之後電腦可以直接執行,不須再重新讀,藉此增加運行速度。
import *moduleName*
用到名字複雜的module,可能會讓程式碼看起來雜亂
import matplotlib, matplotlib_inline
matplotlib_inline.__dict__ # 看起來很複雜
import *moduleName* as *something*
(highly recommended!)
import random as rd
print(rd.randint(0, 5)) # 4
from *moduleName* import *
此方法容易遺忘functions之間的關聯。且容易有shadow name的問題。
from random import *
# 此處可以直接用randint
print(randint(0, 5)) # 2
shadow name problem
# shadow name case
from tryfile import hello
from tryfile2 import hello
hello() # Hello from try file 2. (tryfile的hello被覆蓋了)
from tryfile2 import hello
from tryfile import hello
hello() # Hello from try file. (tryfile2的hello被覆蓋了)
shadow name可以用from … import … as … 來解決
from tryfile2 import hello as hello2
from tryfile import hello as hello1
hello1() # Hello from try file.
hello2() # Hello from try file 2.
from *moduleName* import *oneFunction, anotherFunction, …*
和方法3有相同的問題
from random import randint
# 此處可以直接用randint
print(randint(0, 5)) # 3
python程式碼執行時,會生成一個包含所有資料夾的list,可以用於尋找modules。
用sys.path
import sys
print(sys.path)
# ['c:\\\\Users\\\\user\\\\Desktop', 'C:\\\\Users\\\\user\\\\miniconda3\\\\python312.zip', 'C:\\\\Users\\\\user\\\\miniconda3\\\\DLLs', 'C:\\\\Users\\\\user\\\\miniconda3\\\\Lib', 'C:\\\\Users\\\\user\\\\miniconda3', 'C:\\\\Users\\\\user\\\\miniconda3\\\\Lib\\\\site-packages']
Where can we put our self-defined modules?
放到sys.path
裡任意一個path之中 (Simplest!)
放在與要執行的py檔同一個路徑下
如果別的project也要使用的話會找不到
隨意放,之後再將其路徑加進sys.path的list中
use sys.path.append()
未來如果此路徑修改了,所有使用到其內部module的檔案也需要修改。
change python environment variable
到sys.path
中任一路徑下建立sitecustomize.py
# in **sitecustomize.py**
import site
site.addsitedir('C:\\\\Users\\\\user\\\\miniconda3\\\\new_path')
# in try.py
import sys
print(sys.path) # [..., ..., 'C:\\\\Users\\\\user\\\\miniconda3\\\\new_path']
可以在namespace中找到我們定義的variables及其對應的值
Python中的三種namespace
built-in namespace
每當執行python檔時就會自動import __builtins__
,builtins 在python中是一個object,其中包含了 python built-in functions。e.g. len(), int(), str() …
print(__builtins__) # <module 'builtins' (built-in)>
print(dir(__builtins__))
# ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BaseExceptionGroup', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning',
# 'EOFError', 'Ellipsis', 'EncodingWarning', 'EnvironmentError', 'Exception', 'ExceptionGroup', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError',
# 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError',
# 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError',
# 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'aiter', 'all',
# 'anext', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals',
# 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr',
# 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
global namespace
在main program定義的global variables, functions or import modules,都會被儲存到global namespace中。
print(globals()) # return global namespace as a dict
# {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000028AE25499D0>,
# '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'c:\\\\Users\\\\USER\\\\Desktop\\\\python codes\\\\try.py',
# '__cached__': None}
import sys
x = 10
def hello():
print("Hello")
print(globals())
# {..., 'sys': <module 'sys' (built-in)>, 'x': 10, 'hello': <function hello at 0x0000022E0E54A340>}
local namespace
當function被叫用時,local namespace會產生,但當function return或是終止時,local namespace就會被刪除。
def hello():
x = 5
print(locals())
print("Hello")
hello()
# {'x': 5}
# Hello
LEGB rules in Python