سؤال

ويبدو ذلك في كثير من الأحيان __init__ الأساليب مشابهة لهذا:

def __init__(self, ivar1, ivar2, ivar3):
    self.ivar1 = ivar1
    self.ivar2 = ivar2
    self.ivar3 = ivar3

هل هناك طريقة ما لتحويل الحجج إلى قائمة (دون اللجوء إلى *args أو **kwargs) ثم استخدم setattr لتعيين متغيرات المثيل، مع اسم المعلمة والوسيطة التي تم تمريرها؟وربما شريحة القائمة، على سبيل المثال.ستحتاج إلى تقطيعها على الأقل [1:] لأنك لا تريد self.self.

(في الواقع أعتقد أنه يجب أن يكون قاموسًا ليحمل الاسم والقيمة)

مثله:

def __init__(self, ivar1, ivar2, ivar3, optional=False):
    for k, v in makedict(self.__class__.__init__.__args__): # made up __args__
        setattr(self, k, v)

شكرًا!

الرد على إجابة Unknown، وجدت أن هذا يعمل:

Class A(object):
    def __init__(self, length, width, x):
        self.__dict__.update(dict([(k, v) for k, v in locals().iteritems() if k != 'self']))

أو

Class A(object):
    def __init__(self, length, width, x):
        self.__dict__.update(locals())
        del self.__dict__['self']

ليس سيئا جدا..

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

المحلول

وهنا تذهب. نعم هذا هو الإختراق الشر قبيح. نعم الكائن يحتاج متغير __dict__. ولكن مهلا، لها القليل أنيق بطانة واحد!

def __init__(self):
    self.__dict__.update(locals())

ومنشئ يمكن أن تتخذ أي نوع من الحجج.

class test(object):
    def __init__(self, a, b, foo, bar=5)...

a = test(1,2,3)
dir(a)

['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'foo', 'bar', 'self']

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

نصائح أخرى

هل يمكن استخدام inspect.getargspec وتغليف بأنها الديكور. وبحث الحجج الاختيارية والكلمة هي صعبة بعض الشيء، ولكن هذا ينبغي أن نفعل ذلك:

def inits_args(func):
    """Initializes object attributes by the initializer signature"""
    argspec = inspect.getargspec(func)
    argnames = argspec.args[1:]
    defaults = dict(zip(argnames[-len(argspec.defaults):], argspec.defaults))
    @functools.wraps(func)
    def __init__(self, *args, **kwargs):
        args_it = iter(args)
        for key in argnames:
            if key in kwargs:
                value = kwargs[key]
            else:
                try:
                    value = args_it.next()
                except StopIteration:
                    value = defaults[key]
            setattr(self, key, value)
        func(self, *args, **kwargs)
    return __init__

ويمكنك بعد ذلك استخدام مثل هذا:

class Foo(object):
    @inits_args
    def __init__(self, spam, eggs=4, ham=5):
        print "Foo(%r, %r, %r)" % (self.spam, self.eggs, self.ham)

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

inspect.getargspec :

In [31]: inspect.getargspec(C.__init__)

Out[31]: ArgSpec(args=['self', 'ivar1', 'ivar2', 'ivar3', 'optional'],

                 varargs=None, keywords=None, defaults=(False,))

ومعرفة ما إذا كان namedtuple جديدة (جديد في بيثون 2.6) من وحدة المجموعات قد عمل لك.

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

وهذا الرمز القصير يعمل في معظم الحالات (تحسن من المجهول سبيل المثال):

>>> class Foo:
...   def __init__(self, labamba, **kw):
...       params = locals().copy()
...       del params['self']
...       if 'kw' in params:
...           params.update(params['kw'])
...           del params['kw']
...       self.__dict__.update(params)

ولكن انها الإختراق القبيح، مما يجعل رمز أقل قابلية للقراءة بدون سبب معين إلا الكسل، لذلك لا تفعل ذلك. وأيضا، كيف وغالبا ما كنت <م> حقا ديهم الفئات التي لديها أكثر من 5-6 معلمات الحرف الأول؟

وأنا أحب هذا الشكل أكثر، لم يمض وقت طويل جدا، وكلا نسخ pasteable ودون classable:

class DynamicInitClass(object):
      __init_defargs=('x',)
      def __init__(self,*args,**attrs):
        for idx,val in enumerate(args): attrs[self.__init_defargs[idx]]=val
        for key,val in attrs.iteritems(): setattr(self,key,val)

ماذا عن الاشتقاق من فئة خاصة؟أعتقد أنه من أكثر وضوحا وأكثر مرونة من هنا:

class InitMe:
    def __init__(self, data):
        if 'self' in data:
             data = data.copy()
             del data['self']
        self.__dict__.update(data)


class MyClassA(InitMe):
    def __init__(self, ivar1, ivar2, ivar3 = 'default value'):
        super().__init__(locals())


class MyClassB(InitMe):
    def __init__(self, foo):
        super().__init__({'xxx': foo, 'yyy': foo, 'zzz': None})
# or    super().__init__(dict(xxx=foo, yyy=foo, zzz=None))

class MyClassC(InitMe):
    def __init__(self, foo, **keywords):
        super().__init__(keywords)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top