كيفية التحميل الزائد على طريقة __init__ بناءً على نوع الوسيطة؟

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

سؤال

لنفترض أن لدي فصلًا يحتوي على عضو يسمى البيانات وهو عبارة عن قائمة.

أريد أن أكون قادرًا على تهيئة الفصل الدراسي، على سبيل المثال، باسم ملف (يحتوي على بيانات لتهيئة القائمة) أو بقائمة فعلية.

ما هي التقنية الخاصة بك للقيام بذلك؟

هل مجرد التحقق من النوع من خلال النظر في __class__?

هل هناك بعض الخدعة التي قد أفتقدها؟

أنا معتاد على لغة C++ حيث يكون التحميل الزائد حسب نوع الوسيطة أمرًا سهلاً.

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

المحلول

الطريقة الأكثر إتقانًا للحصول على "المنشئين البديلين" هي استخدام أساليب الفصل.على سبيل المثال:

>>> class MyData:
...     def __init__(self, data):
...         "Initialize MyData from a sequence"
...         self.data = data
...     
...     @classmethod
...     def fromfilename(cls, filename):
...         "Initialize MyData from a file"
...         data = open(filename).readlines()
...         return cls(data)
...     
...     @classmethod
...     def fromdict(cls, datadict):
...         "Initialize MyData from a dict's items"
...         return cls(datadict.items())
... 
>>> MyData([1, 2, 3]).data
[1, 2, 3]
>>> MyData.fromfilename("/tmp/foobar").data
['foo\n', 'bar\n', 'baz\n']
>>> MyData.fromdict({"spam": "ham"}).data
[('spam', 'ham')]

والسبب في أنه أكثر دقة هو أنه لا يوجد شك حول النوع المتوقع، ولست مجبرًا على تخمين ما ينوي المتصل أن تفعله بنوع البيانات الذي قدمه لك.المشكلة مع isinstance(x, basestring) هو أنه لا توجد طريقة للمتصل لإخبارك، على سبيل المثال، أنه على الرغم من أن النوع ليس سلسلة أساسية، فيجب التعامل معه كسلسلة (وليس تسلسل آخر.) وربما يرغب المتصل في استخدام نفس الشيء اكتب لأغراض مختلفة، أحيانًا كعنصر واحد، وأحيانًا كسلسلة من العناصر.إن كونك صريحًا يزيل كل الشكوك ويؤدي إلى كود أكثر قوة ووضوحًا.

نصائح أخرى

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

إليك عينة (هذه read طريقة وليست منشئًا ولكن الفكرة هي نفسها):

def read(self, str=None, filename=None, addr=0):
    """ Read binary data and return a store object. The data
        store is also saved in the interal 'data' attribute.

        The data can either be taken from a string (str 
        argument) or a file (provide a filename, which will 
        be read in binary mode). If both are provided, the str 
        will be used. If neither is provided, an ArgumentError 
        is raised.
    """
    if str is None:
        if filename is None:
            raise ArgumentError('Please supply a string or a filename')

        file = open(filename, 'rb')
        str = file.read()
        file.close()
    ...
    ... # rest of code

الفكرة الأساسية هنا هي استخدام دعم بايثون الممتاز للوسائط المسماة لتنفيذ ذلك.الآن، إذا أردت قراءة البيانات من ملف، أقول:

obj.read(filename="blob.txt")

ولقراءتها من الوتر أقول:

obj.read(str="\x34\x55")

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

إصلاح سريع وقذر

class MyData:
    def __init__(string=None,list=None):
        if string is not None:
            #do stuff
        elif list is not None:
            #do other stuff
        else:
            #make data empty

ثم يمكنك الاتصال به

MyData(astring)
MyData(None, alist)
MyData()

أفضل طريقة هي استخدام isinstance ونوع التحويل.إذا كنت أفهمك جيدًا، فأنت تريد هذا:

def __init__ (self, filename):
    if isinstance (filename, basestring):
        # filename is a string
    else:
        # try to convert to a list
        self.path = list (filename)

مع python3، يمكنك استخدام تنفيذ الإرسال المتعدد مع التعليقات التوضيحية للوظيفة كما كتب كتاب بايثون للطبخ:

import time


class Date(metaclass=MultipleMeta):
    def __init__(self, year:int, month:int, day:int):
        self.year = year
        self.month = month
        self.day = day

    def __init__(self):
        t = time.localtime()
        self.__init__(t.tm_year, t.tm_mon, t.tm_mday)

ويعمل مثل:

>>> d = Date(2012, 12, 21)
>>> d.year
2012
>>> e = Date()
>>> e.year
2018

يجب عليك استخدام isinstance

isinstance(...)
    isinstance(object, class-or-type-or-tuple) -> bool

    Return whether an object is an instance of a class or of a subclass thereof.
    With a type as second argument, return whether that is the object's type.
    The form using a tuple, isinstance(x, (A, B, ...)), is a shortcut for
    isinstance(x, A) or isinstance(x, B) or ... (etc.).

ربما تريد isinstance وظيفة مدمجة:

self.data = data if isinstance(data, list) else self.parse(data)

الحل المفضل لدي هو:

class MyClass:
    _data = []
    __init__(self,data=None):
        # do init stuff
        if not data: return
        self._data = list(data) # list() copies the list, instead of pointing to it.

ثم استدعائه مع أي منهما MyClass() أو MyClass([1,2,3]).

امل ان يساعد.ترميز سعيد!

حسنا عظيم.لقد جمعت للتو هذا المثال مع صف، وليس اسم ملف، ولكن هذا سهل.شكرا لكم جميعا.

class MyData:
    def __init__(self, data):
        self.myList = []
        if isinstance(data, tuple):
            for i in data:
                self.myList.append(i)
        else:
            self.myList = data

    def GetData(self):
        print self.myList

أ = [1,2]

ب = (2،3)

ج = بياناتي (أ)

د = بياناتي (ب)

ج.جيتداتا ()

د.جيتداتا ()

[1, 2]

[2, 3]

لماذا لا تذهب أكثر بيثونية؟

class AutoList:
def __init__(self, inp):
    try:                        ## Assume an opened-file...
        self.data = inp.read()
    except AttributeError:
        try:                    ## Assume an existent filename...
            with open(inp, 'r') as fd:
                self.data = fd.read()
        except:
            self.data = inp     ## Who cares what that might be?
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top