2009-05-19 39 views
69

Với tính python, tôi có thể làm cho nó như vậy màMô-đun có thể có các thuộc tính giống như cách đối tượng có thể không?

obj.y 

gọi một chức năng thay vì chỉ trả lại một giá trị.

Có cách nào để thực hiện việc này với mô-đun không? Tôi có một trường hợp tôi muốn

module.y 

để gọi hàm, thay vì chỉ trả lại giá trị được lưu trữ ở đó.

+2

Có gì sai khi chỉ cần gọi một chức năng? –

+8

muốn làm cho nó ít gõ để làm một số điều mà có được thực hiện rất nhiều. –

Trả lời

50

Chỉ các phiên bản của lớp mới có thể có thuộc tính. Bạn có thể làm cho Python tin rằng một ví dụ như vậy là một mô-đun bằng cách stashing nó trong sys.modules[thename] = theinstance. Vì vậy, ví dụ, m.py mô-đun tập tin của bạn có thể là:

import sys 
class _M(object): 
    def __init__(self): 
    self.c = 0 
    def afunction(self): 
    self.c += 1 
    return self.c 
    y = property(afunction) 
sys.modules[__name__] = _M() 

Sửa: loại bỏ một sự phụ thuộc tuyệt đối vào globals (không có gì để làm với các điểm của ví dụ nhưng đã nhầm lẫn thứ bằng cách làm cho mã ban đầu không thành công!).

+0

Tôi sẽ không bao giờ nghĩ đến việc đó. Tôi thừa nhận tôi không thể sử dụng nó, nhưng bạn không bao giờ biết. Luôn vui khi tìm hiểu về những con đường chưa được khám phá trong Python ... cảm ơn. –

+1

Có ai khác thử điều này không? Khi tôi đặt mã này vào một tập tin x.py và nhập mã này từ một tệp khác, sau đó gọi kết quả xy trong AttributeError: đối tượng 'NoneType' không có thuộc tính 'c', vì _M bằng cách nào đó có giá trị None ... – Stephan202

+0

Bạn phải nhập sai một cái gì đó . Kiểm tra một phiên tương tác: $ python ... sys >>> import >>> lớp _M (object): ... c = 0 ... def afunction (tự): ... _M .c + = 1 ... trả lại _M.c ... y = thuộc tính (tiếp giáp) ... >>> sys.module [ 'bowwow'] = _M() >>> import bowwow >>> bowwow.y >>> bowwow.y >>> ... chính xác như mong đợi, tất nhiên. Vì vậy, những gì khác nhau trong những gì bạn chính xác đang làm gì? –

44

tôi sẽ làm điều này để kế thừa đúng tất cả các thuộc tính của một mô-đun, và được xác định một cách chính xác bởi isinstance()

import types 

class MyModule(types.ModuleType): 
    @property 
    def y(self): 
     return 5 


>>> a=MyModule("test") 
>>> a 
<module 'test' (built-in)> 
>>> a.y 
5 

Và sau đó bạn có thể chèn này vào sys.modules:

sys.modules[__name__] = MyModule(__name__) # remember to instantiate the class 
+0

Điều này dường như chỉ hoạt động đối với các trường hợp đơn giản nhất. Các vấn đề có thể xảy ra là: (1) một số người trợ giúp nhập khẩu cũng có thể mong đợi các thuộc tính khác như '__file__' phải được xác định theo cách thủ công, (2) nhập khẩu được thực hiện trong mô-đun có chứa lớp sẽ không" hiển thị "trong thời gian chạy, v.v. – tutuDajuju

+1

Không cần thiết phải lấy được một lớp con từ lớp 'types.ModuleType', _any_ (kiểu mới) sẽ làm. Các thuộc tính mô-đun đặc biệt chính xác nơi bạn hy vọng sẽ kế thừa? – martineau

+0

Điều gì xảy ra nếu mô đun ban đầu là một gói và tôi muốn truy cập các mô-đun bên dưới mô-đun gốc? –

1

Trường hợp sử dụng điển hình là: làm giàu mô-đun hiện tại (lớn) với một số (vài) thuộc tính động - mà không cần chuyển tất cả các thành phần mô-đun thành bố cục lớp. Thật không may là một bản vá lớp mô-đun đơn giản nhất như sys.modules[__name__].__class__ = MyPropertyModule không thành công với TypeError: __class__ assignment: only for heap types. Vì vậy, tạo mô-đun cần phải được rewired.

Cách tiếp cận này làm điều đó mà không móc nhập khẩu Python, chỉ bằng cách có một số prolog trên đầu trang của các mã mô-đun:

# propertymodule.py 
""" Module property example """ 

if '__orgmod__' not in globals(): 

    # constant prolog for having module properties/supports reload() 

    print "PropertyModule stub execution", __name__ 
    import sys, types 
    class PropertyModule(types.ModuleType): 
     def __str__(self): 
      return "<PropertyModule %r from %r>" % (self.__name__, self.__file__) 
    modnew = PropertyModule(__name__, __doc__) 
    modnew.__modclass__ = PropertyModule   
    modnew.__file__ = __file__ 
    modnew.__orgmod__ = sys.modules[__name__] 
    sys.modules[__name__] = modnew 
    exec sys._getframe().f_code in modnew.__dict__ 

else: 

    # normal module code (usually vast) .. 

    print "regular module execution" 
    a = 7 

    def get_dynval(module): 
     return "property function returns %s in module %r" % (a * 4, module.__name__)  
    __modclass__.dynval = property(get_dynval) 

Cách sử dụng:

>>> import propertymodule 
PropertyModule stub execution propertymodule 
regular module execution 
>>> propertymodule.dynval 
"property function returns 28 in module 'propertymodule'" 
>>> reload(propertymodule) # AFTER EDITS 
regular module execution 
<module 'propertymodule' from 'propertymodule.pyc'> 
>>> propertymodule.dynval 
"property function returns 36 in module 'propertymodule'" 

Lưu ý: Một cái gì đó như from propertymodule import dynval sẽ sản xuất một đông lạnh bản sao của khóa học - tương ứng với dynval = someobject.dynval

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