มีวิธีที่ตรงไปตรงมาในการค้นหาโมดูลทั้งหมดที่เป็นส่วนหนึ่งของแพ็คเกจ python หรือไม่? ฉันพบการสนทนาเก่า ๆ นี้ซึ่งยังไม่สามารถสรุปได้ แต่ฉันอยากได้คำตอบที่ชัดเจนก่อนที่จะเปิดตัวโซลูชันของตัวเองโดยใช้ os.listdir ()
มีวิธีที่ตรงไปตรงมาในการค้นหาโมดูลทั้งหมดที่เป็นส่วนหนึ่งของแพ็คเกจ python หรือไม่? ฉันพบการสนทนาเก่า ๆ นี้ซึ่งยังไม่สามารถสรุปได้ แต่ฉันอยากได้คำตอบที่ชัดเจนก่อนที่จะเปิดตัวโซลูชันของตัวเองโดยใช้ os.listdir ()
คำตอบ:
ใช่คุณต้องการบางอย่างที่อิงpkgutil
หรือคล้ายกัน - วิธีนี้จะทำให้คุณสามารถปฏิบัติต่อแพ็คเกจทั้งหมดได้ไม่ว่าจะอยู่ในไข่หรือซิปหรือมากกว่านั้น (โดยที่ os.listdir จะไม่ช่วย)
import pkgutil
# this is the package we are inspecting -- for example 'email' from stdlib
import email
package = email
for importer, modname, ispkg in pkgutil.iter_modules(package.__path__):
print "Found submodule %s (is a package: %s)" % (modname, ispkg)
วิธีการนำเข้าด้วย? คุณสามารถใช้งานได้__import__
ตามปกติ:
import pkgutil
# this is the package we are inspecting -- for example 'email' from stdlib
import email
package = email
prefix = package.__name__ + "."
for importer, modname, ispkg in pkgutil.iter_modules(package.__path__, prefix):
print "Found submodule %s (is a package: %s)" % (modname, ispkg)
module = __import__(modname, fromlist="dummy")
print "Imported", module
importer
ส่งคืนโดยpkgutil.iter_modules
อะไร? ฉันสามารถใช้เพื่อนำเข้าโมดูลแทนการใช้ "แฮ็ก" ได้__import__(modname, fromlist="dummy")
หรือไม่
m = importer.find_module(modname).load_module(modname)
แล้วก็m
เป็นโมดูลตัวอย่างเช่น:m.myfunc()
_path_
) ควรมีสองด้านรวมเป็นสี่ (กล่าวคือ__path__
)
เครื่องมือที่เหมาะสมสำหรับงานนี้คือ pkgutil.walk_packages
ในการแสดงรายการโมดูลทั้งหมดในระบบของคุณ:
import pkgutil
for importer, modname, ispkg in pkgutil.walk_packages(path=None, onerror=lambda x: None):
print(modname)
โปรดทราบว่า walk_packages นำเข้าแพ็กเกจย่อยทั้งหมด แต่ไม่ใช่โมดูลย่อย
หากคุณต้องการแสดงรายการโมดูลย่อยทั้งหมดของแพ็คเกจบางชุดคุณสามารถใช้สิ่งนี้:
import pkgutil
import scipy
package=scipy
for importer, modname, ispkg in pkgutil.walk_packages(path=package.__path__,
prefix=package.__name__+'.',
onerror=lambda x: None):
print(modname)
iter_modules แสดงเฉพาะโมดูลที่มีความลึกระดับเดียว walk_packages รับโมดูลย่อยทั้งหมด ในกรณีของ scipy ตัวอย่างเช่น walk_packages จะส่งกลับ
scipy.stats.stats
ในขณะที่ iter_modules ส่งคืนเท่านั้น
scipy.stats
เอกสารประกอบเกี่ยวกับ pkgutil ( http://docs.python.org/library/pkgutil.html ) ไม่แสดงรายการฟังก์ชันที่น่าสนใจทั้งหมดที่กำหนดไว้ใน /usr/lib/python2.6/pkgutil.py
บางทีหมายความว่าฟังก์ชันนี้ไม่ได้เป็นส่วนหนึ่งของอินเทอร์เฟซ "สาธารณะ" และอาจมีการเปลี่ยนแปลงได้
อย่างไรก็ตามอย่างน้อยที่สุดใน Python 2.6 (และอาจเป็นเวอร์ชันก่อนหน้านี้?) pkgutil มาพร้อมกับวิธีการ walk_packages ซึ่งจะเดินผ่านโมดูลทั้งหมดที่มีอยู่ซ้ำ ๆ
walk_packages
อยู่ในเอกสารประกอบ: docs.python.org/library/pkgutil.html#pkgutil.walk_packages
_
) สองอันก่อนและหลังpath
นั่นคือใช้package.__path__
แทนpackage._path_
. อาจจะง่ายกว่าที่จะลองตัดและวางโค้ดแทนที่จะพิมพ์ซ้ำ
package
ชี้ไปที่แพ็คเกจไม่ใช่โมดูล โมดูลคือไฟล์ในขณะที่แพ็กเกจเป็นไดเร็กทอรี แพ็คเกจทั้งหมดมี__path__
แอตทริบิวต์ (... เว้นแต่จะมีใครลบแอตทริบิวต์ด้วยเหตุผลบางประการ)
สิ่งนี้ใช้ได้กับฉัน:
import types
for key, obj in nltk.__dict__.iteritems():
if type(obj) is types.ModuleType:
print key
ฉันกำลังมองหาวิธีโหลดโมดูลย่อยทั้งหมดที่กำลังแก้ไขอยู่ในแพ็กเกจของฉันซ้ำ เป็นการรวมคำตอบ / ความคิดเห็นด้านบนดังนั้นฉันจึงตัดสินใจโพสต์ที่นี่เป็นคำตอบแทนที่จะแสดงความคิดเห็น
package=yourPackageName
import importlib
import pkgutil
for importer, modname, ispkg in pkgutil.walk_packages(path=package.__path__, prefix=package.__name__+'.', onerror=lambda x: None):
try:
modulesource = importlib.import_module(modname)
reload(modulesource)
print("reloaded: {}".format(modname))
except Exception as e:
print('Could not load {} {}'.format(modname, e))
นี่เป็นวิธีหนึ่งที่ปิดด้านบนของหัวของฉัน:
>>> import os
>>> filter(lambda i: type(i) == type(os), [getattr(os, j) for j in dir(os)])
[<module 'UserDict' from '/usr/lib/python2.5/UserDict.pyc'>, <module 'copy_reg' from '/usr/lib/python2.5/copy_reg.pyc'>, <module 'errno' (built-in)>, <module 'posixpath' from '/usr/lib/python2.5/posixpath.pyc'>, <module 'sys' (built-in)>]
สามารถทำความสะอาดและปรับปรุงได้อย่างแน่นอน
แก้ไข:นี่เป็นเวอร์ชันที่ดีกว่าเล็กน้อย:
>>> [m[1] for m in filter(lambda a: type(a[1]) == type(os), os.__dict__.items())]
[<module 'copy_reg' from '/usr/lib/python2.5/copy_reg.pyc'>, <module 'UserDict' from '/usr/lib/python2.5/UserDict.pyc'>, <module 'posixpath' from '/usr/lib/python2.5/posixpath.pyc'>, <module 'errno' (built-in)>, <module 'sys' (built-in)>]
>>> [m[0] for m in filter(lambda a: type(a[1]) == type(os), os.__dict__.items())]
['_copy_reg', 'UserDict', 'path', 'errno', 'sys']
หมายเหตุ:นอกจากนี้ยังจะพบโมดูลที่อาจไม่จำเป็นต้องอยู่ในไดเร็กทอรีย่อยของแพ็กเกจหากถูกดึงเข้ามาใน__init__.py
ไฟล์ดังนั้นจึงขึ้นอยู่กับความหมายของ "ส่วนหนึ่งของแพ็กเกจ"