هل من الممكن تحويل وحدة نمطية في بيثون؟ (ResourceX تحويلها إلى ResourceXSimulated)

StackOverflow https://stackoverflow.com/questions/1443173

سؤال

وأريد أن محاكاة اسم التطبيق ان واردات وحدة نمطية (ResourceX) الذي يتطلب موارد ليست متاحة في ذلك الوقت ولن ينجح.

وهناك حل لهذا هو جعل واستيراد وحدة وهمية من ResourceX (يسمى ResourceXSimulated) وتحويل ذلك إلى اسم التطبيق كما ResourceX. أريد أن أفعل هذا من أجل تجنب كسر الكثير من رمز والحصول على جميع أنواع استثناء من اسم التطبيق.

وأستخدمه بيثون، وينبغي أن يكون شيئا مثل:

و"استيراد ResourceXSimulated كما ResourceX"

و"ResourceX.getData ()"، ويدعو في الواقع ResourceXSimultated.getData ()

ونتطلع إلى معرفة ما إذا كان بيثون تدعم هذا النوع من إعادة التوجيه.

وابتهاج.

وINFO الإضافية: لدي الوصول إلى الملفات المصدر

.

وUPDATE: أنا أفكر إضافة كرمز أقل قدر ممكن لاسم التطبيق فيما يتعلق باستخدام وحدة وهمية وإضافة هذا الرمز بالقرب من البيانات استيراد

.
هل كانت مفيدة؟

المحلول

ومجرد تغيير جميع خطوط import ResourceX في MyApp إلى import ResourceXSimulated as ResourceX، وخطوط مثل from ResourceX import Y إلى from ResourceXSimulated import Y.

ولكن إذا لم يكن لديك الوصول إلى مصدر MyApp أو هناك أسباب أخرى لا لتغييره، يمكنك وضع وحدة الخاص بك إلى sys.modules قبل يتم تحميل MyApp نفسه:

import ResourceXSimulated
sys.modules['ResourceX'] = ResourceXSimulated

ملحوظة: إذا ResourceX هو حزمة، قد تتطلب المزيد من الجهد

نصائح أخرى

وهذا ما يسمى القرد الترقيع، وانها تقنية إلى حد ما على نطاق واسع المستخدمة في لغات ديناميكية مثل بايثون.

وهكذا يفترض أن يكون لديك فئة:

class MyOriginal(object):

    def method_x(self):
        do_something_expensive_you_dont_want_in_testing()


obj = MyOriginal()
obj.method_x()

وذلك في اختبار كنت تريد أن تفعل شيئا آخر بدلا من method_x، ولكن يجب أن تكون شفافة. لذلك أنت فقط الاستفادة من لغة ديناميكية بايثون:

def new_method_x(self):
    pretend_were_doing_something_expensive()

test_obj = MyOriginal()
test_obj.method_x = new_method_x # here's the monkeypatch
test_obj_method_x() # calls the new method

ومن الممكن مع sys.modules الإختراق، كما قال بالفعل.

لاحظ أنه إذا كان لديك السيطرة على وحدة ResourceX انها بالتأكيد أفضل أن الأمر يتطلب العناية بها نفسها. هذا هو في الواقع النمط الشائع عند كتابة الوحدات التي تعمل على نحو أفضل عند بعض الموارد هو الحاضر، على سبيل المثال:

# foo.py
'''A module that provides interface to foo. 

Falls back to a dummy interface if foo is not available.
'''

try:
    from _foo import *
except ImportError:
    from _foo_dummy import *

والناس في بعض الأحيان تفعل ذلك بطريقة أكثر وجوه المنحى:

# foo.py
'''A module that provides interface to foo if it exists or to a dummy interface. 

Provides:
    frobnicate()   self-explanatory
    ...
'''

class DummyFoo:
    def frobnicate(self):
        pass
    ...

class UnixFoo(DummyFoo):
    def frobnicate(self):
        a_posix_call()
    ...

class GenericFoo(DummyFoo):
    def frobnicate(self):
        do_something_complicated()
    ...

# Create a default instance.
try:
   if (system == UNIX)
       instance = UnixFoo(system)
   else:
       instance = GenericFoo()
except Exception:
    instance = DummyFoo()

# Now export the public interface.
frobnicate = instance.frobnicate

نعم، فمن الممكن. بعض المبتدئين:

ويمكنك "تحويل" وحدات عن طريق التلاعب sys.modules. إنها تحافظ على قائمة الوحدات المستوردة، وهناك يمكنك جعل الوحدة النمطية الخاص بك تظهر تحت نفس الاسم الاصل واحد. يجب عليك أن تفعل هذا التلاعب من قبل أية وحدة نمطية التي تستورد وحدة تريد همية بالرغم من ذلك.

ويمكنك أيضا جعل مجموعة تسمى باسم مختلف، ولكن في تلك الحزمة فعلا استخدام اسم الوحدة النمطية الأصلي، على وحدة بك مختلفة تماما. هذا يعمل بشكل جيد طالما لم يتم تثبيت وحدة الأصلي.

في أي من هذه الحالات يمكنك استخدام كل وحدات في نفس الوقت. لذلك تحتاج إلى قرد التصحيح وحدة الأصلي.

وبالطبع: من الممكن تماما أن مجرد دعوة وحدة جديدة مع الاسم القديم. ولكن قد يكون مربكا.

نعم، يمكن بيثون أن تفعل ذلك، وطالما أن أساليب كشفها في وحدة "نظرة ورائحة" ResourceXSimulated مثل هذه وحدة الأصلي، يجب أن التطبيق لا يرى أي فرق كثيرا (ما عدا، أفترض، الحشو بيانات وهمية، وأوقات استجابة مختلفة وكذا).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top