Python 包、模塊、類的管理方案優化

須要解決的問題

在編寫Python代碼的過程當中,爲了更好的管理代碼,咱們會使用到包(package)、模塊(module)、類(class)、函數(function)。
介紹一下這幾個概念:python

  • 首先是模塊,module能夠簡單理解爲就是一個.py文件,這個文件裏面能夠包含類、變量、常量和函數等;
  • 而後是包,簡單理解含有__init__.py的目錄就算是一個包,須要明確的是在python中包實際上是一種特殊的模塊,但模塊並非包。緣由其實很簡單,sys.modules咱們獲取到的結果中包含包和模塊,而module.__package__則會獲取到包的信息;
  • 最後是類(函數在這裏就不說了),類會寫在.py文件中,通常爲了控制文件的大小,一般將一個或幾個有關聯的類寫在一個文件中。固然我的仍是以爲一個類獨佔一個文件比較好,除非你想看見一大堆亂糟糟的代碼擠在一個超大的文件裏。

而後再來看看咱們平常使用包、模塊和類的作法app

# 目錄結構
#|--demo.py
#|--package_a
#   |--__init__.py
#   |--class_a.py  類ClassA
#   |--class_b.py  類ClassB

# ./demo.py

# 導入方式一
from package_a.class_a import ClassA
from package_a.class_a import ClassB
a = ClassA()
b = ClassB()

# 導入方式二
import package_a.class_a as ca
import package_a.class_b as cb
a = ca.ClassA()
b = cb.ClassB()

好的,咱們的問題來了,怎麼樣才能減小咱們導入部分的代碼呢?或者說怎麼樣才能使得一些相關聯的模塊不須要一個一個的進行導入呢?最終實現到下面的樣子是否是會更好函數

# ./demo.py

from package_a import *
a = ClassA()
b = ClassB()

解決的方法

# ./common.py
import sys

_packet_ = {}
# 裝飾器,func是類或者函數
def export(func):
    module = sys.modules[func.__module__]        # 獲取func的模塊對象
    package = sys.modules[module.__package__]    # 由模塊對象獲得包對象
    package.__dict__[func.__name__] = func       # 把func添加到包的__dict__裏
    # 生成全部使用該解決方案的包的__all__變量,並把導出的func添加進去
    if not package.__name__ in _packet_:
        _packet_[package.__name__] = []
    _packet_[package.__name__].append(func.__name__)
    # 原封不動地把func返回
    return func

# 在包的__init__.py裏用於獲取__all__
def packet(name):
    if not name in _packet_:
        _packet_[name] = []
    return _packet_[name]

實際使用

# 目錄結構
#|--common.py(就是上面的裝飾器文件)
#|--demo.py
#|--package_a
#   |--__init__.py
#   |--class_a.py  類ClassA
#   |--class_b.py  類ClassB

首先在模塊中處理咱們建立的類code

# ./package_a/class_a.py

import common

# 使用export裝飾器,裝飾要導出的類或函數
@common.export
class ClassB(object):
    def __init__(self):
        print 'This is ClassB.'

而後在包的__init__.py中修改包自身對象

# ./package_a/__init__.py

import common

# 注意,這步很重要!!!導入將要導出的子模塊,須要具體模塊名字,此處import * 不可用
from . import class_a, class_b

# 用packet初始化包的__all__,主要是用於支持 "from . import *" 導入
__all__ = common.packet(__name__)

# 由於用__all__會影響"from . import *"。因此用export把__init__.py裏的成員,加入__all__
@common.export
def pafunc():
    """ 這是一個包內部的函數 """
    print('pafunc')

最終就能夠實現咱們前面所指望的導入方式了。it

# ./demo.py

from package_a import *
a = ClassA()
相關文章
相關標籤/搜索