2009-12-02 25 views
6

Tôi cần phải đọc tất cả các mô-đun (được biên dịch trước) từ một tệp zip (được xây dựng bởi py2exe nén) vào bộ nhớ và sau đó tải tất cả. Tôi biết điều này có thể được thực hiện bằng cách tải trực tiếp từ tệp zip nhưng tôi cần tải chúng từ bộ nhớ. Bất kỳ ý tưởng nào? (Tôi đang sử dụng python 2.5.2 trên cửa sổ) TIA SteveLàm thế nào để tải các mô-đun python biên dịch từ bộ nhớ?

+0

Bạn có thể cung cấp thêm một số nền không? Tại sao bạn cần tải mã vào bộ nhớ ngay từ đầu? Tại sao tải từ tệp ZIP không phù hợp? – Ber

Trả lời

30

Nó phụ thuộc vào chính xác những gì bạn có là "mô-đun (được biên dịch trước)". Giả sử đó là chính xác nội dung của một tập tin .pyc, ví dụ, ciao.pyc như xây dựng bởi:

$ cat>'ciao.py' 
def ciao(): return 'Ciao!' 
$ python -c'import ciao; print ciao.ciao()' 
Ciao! 

IOW, đã như vậy, xây dựng ciao.pyc, nói rằng bây giờ bạn làm:

$ python 
Python 2.5.1 (r251:54863, Feb 6 2009, 19:02:12) 
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> b = open('ciao.pyc', 'rb').read() 
>>> len(b) 
200 

và mục tiêu của bạn là để đi từ chuỗi byte đó b đến mô-đun có thể nhập ciao. Dưới đây là cách thực hiện:

>>> import marshal 
>>> c = marshal.loads(b[8:]) 
>>> c 
<code object <module> at 0x65188, file "ciao.py", line 1> 

đây là cách bạn lấy đối tượng mã từ nội dung nhị phân .pyc. Chỉnh sửa: nếu bạn tò mò, 8 byte đầu tiên là "số ma thuật" và dấu thời gian - không cần thiết ở đây (trừ khi bạn muốn kiểm tra sự tỉnh táo và nêu ra ngoại lệ nếu được bảo đảm, nhưng điều đó có vẻ nằm ngoài phạm vi câu hỏi; marshal.loads sẽ tăng lên nếu phát hiện chuỗi bị hỏng).

Sau đó:

>>> import types 
>>> m = types.ModuleType('ciao') 
>>> import sys 
>>> sys.modules['ciao'] = m 
>>> exec c in m.__dict__ 

tức là: làm cho một đối tượng mô-đun mới, cài đặt nó trong sys.modules, cư nó bằng cách thực hiện các đối tượng mã trong __dict__ của nó. Chỉnh sửa: thứ tự mà bạn thực hiện việc chèn sys.modulesexec các vấn đề nếu và chỉ khi bạn có thể nhập khẩu vòng tròn - nhưng, đây là thứ tự của Python import thường sử dụng, vì vậy tốt hơn là bắt chước nó (không có nhược điểm).

Bạn có thể "làm cho một đối tượng mô-đun mới" bằng nhiều cách (ví dụ, từ chức năng trong module thư viện chuẩn như newimp), nhưng "gọi kiểu để có được một ví dụ" là Python cách bình thường những ngày này, và vị trí bình thường để có được loại (trừ khi nó có tên tích hợp hoặc bạn đã có sẵn nó) từ mô-đun thư viện chuẩn types, vì vậy đó là những gì tôi đề nghị.

Bây giờ, cuối cùng:

>>> import ciao 
>>> ciao.ciao() 
'Ciao!' 
>>> 

... bạn có thể nhập các mô-đun và sử dụng chức năng của mình, các lớp học, và vân vân. Các câu lệnh khác import (và from) sau đó sẽ tìm mô-đun là sys.modules['ciao'], vì vậy bạn sẽ không cần phải lặp lại chuỗi hoạt động này (thực tế là bạn không cần cần câu lệnh cuối cùng này là tất cả những gì bạn muốn là đảm bảo mô-đun có sẵn để nhập từ những nơi khác - tôi chỉ thêm nó để hiển thị nó hoạt động ;-).

Chỉnh sửa: Nếu bạn hoàn toàn phải nhập bằng cách này gói và mô-đun từ đó, thay vì "mô-đun đơn giản" như tôi vừa cho thấy, đó là doable, quá, nhưng phức tạp hơn một chút. Vì câu trả lời này đã được khá dài, và tôi hy vọng bạn có thể đơn giản hóa cuộc sống của bạn bằng cách gắn bó với mô-đun đồng bằng cho mục đích này, tôi sẽ trốn tránh một phần của câu trả lời ;-).Cũng lưu ý rằng điều này có thể hoặc không thể làm những gì bạn muốn trong trường hợp "nạp cùng một mô-đun từ bộ nhớ nhiều lần" (điều này sẽ xây dựng lại mô-đun mỗi lần, bạn có thể muốn kiểm tra sys.modules và bỏ qua mọi thứ nếu các mô đun đã có) và đặc biệt khi lặp đi lặp lại "tải từ bộ nhớ" xảy ra từ nhiều chủ đề (cần khóa - nhưng, một kiến ​​trúc tốt hơn là có một chủ đề chuyên dụng dành riêng để thực hiện nhiệm vụ, với các mô-đun khác giao tiếp với nó thông qua một Hàng đợi).

Cuối cùng, không có thảo luận về cách cài đặt chức năng này như một "móc nhập" minh bạch tự động tham gia vào cơ chế của chính nội dung tuyên bố import - đó là khả thi, nhưng không chính xác những gì bạn đang yêu cầu về, vì vậy ở đây, quá, tôi hy vọng bạn có thể đơn giản hóa cuộc sống của bạn bằng cách làm những điều theo cách đơn giản để thay thế, như câu trả lời này vạch ra.

+1

Chỉ tò mò thôi, nó cũng sẽ hoạt động cho các tệp .pyd? – YOU

+1

Tôi đã có yêu cầu tương tự và đang tìm kiếm giải pháp, cảm ơn Alex :) – Parthan

+0

@ S.Mark, no, '.pyc' hoặc' .pyo' only - '.pyd's về cơ bản là' .dll ' dưới một tên giả và hiện tại ** hoàn toàn ** các vấn đề khác nhau. @Technofreak, bạn được chào đón! -) –

9

Biên soạn tập tin Python bao gồm

  1. con số kỳ diệu (4 byte) để xác định loại và phiên bản của Python,
  2. timestamp (4 byte) để kiểm tra xem chúng tôi có nguồn mới hơn,
  3. marshaled đang vật.

Để tải mô-đun, bạn phải tạo đối tượng mô-đun với imp.new_module(), thực thi mã chưa được mã hóa trong không gian tên của mô-đun mới và đặt trong sys.modules. Dưới đây trong việc thực hiện mẫu:

import sys, imp, marshal 

def load_compiled_from_memory(name, filename, data, ispackage=False): 
    if data[:4]!=imp.get_magic(): 
     raise ImportError('Bad magic number in %s' % filename) 
    # Ignore timestamp in data[4:8] 
    code = marshal.loads(data[8:]) 
    imp.acquire_lock() # Required in threaded applications 
    try: 
     mod = imp.new_module(name) 
     sys.modules[name] = mod # To handle circular and submodule imports 
           # it should come before exec. 
     try: 
      mod.__file__ = filename # Is not so important. 
      # For package you have to set mod.__path__ here. 
      # Here I handle simple cases only. 
      if ispackage: 
       mod.__path__ = [name.replace('.', '/')] 
      exec code in mod.__dict__ 
     except: 
      del sys.modules[name] 
      raise 
    finally: 
     imp.release_lock() 
    return mod 

Cập nhật: mã được cập nhật để xử lý gói đúng cách.

Lưu ý rằng bạn phải cài đặt móc nhập khẩu để xử lý nhập khẩu bên trong các mô-đun đã tải. Một cách để làm điều này là thêm công cụ tìm của bạn vào sys.meta_path. Xem PEP302 để biết thêm thông tin.

Các vấn đề liên quan