Автоматическая установка переменных члена класса в Python - PullRequest
28 голосов
/ 07 октября 2010

Скажите, у меня есть следующий класс в Python

class Foo(object):
    a = None
    b = None
    c = None
    def __init__(self, a = None, b = None, c = None):
        self.a = a
        self.b = b
        self.c = c

Есть ли способ упростить этот процесс?Всякий раз, когда я добавляю новый член в класс Foo, я вынужден изменять конструктор.

Ответы [ 3 ]

30 голосов
/ 07 октября 2010

Обратите внимание, что

class Foo(object):
    a = None

устанавливает пару ключ-значение в Foo dict:

Foo.__dict__['a']=None

, в то время как

def __init__(self, a = None, b = None, c = None):
    self.a = a

устанавливаетпара ключ-значение в dict объекта экземпляра Foo:

foo=Foo()
foo.__dict__['a']=a

Таким образом, установка членов класса в верхней части вашего определения не имеет прямого отношения к настройке атрибутов экземпляра в нижней половине вашего определения (внутри __init__.

Также полезно знать, что __init__ - это инициализатор Python . __new__ - это конструктор класса .


Если вы ищете способ автоматического добавления некоторых атрибутов экземпляра на основе аргументов __init__, вы можете использовать это:

import inspect
import functools

def autoargs(*include,**kwargs):   
    def _autoargs(func):
        attrs,varargs,varkw,defaults=inspect.getargspec(func)
        def sieve(attr):
            if kwargs and attr in kwargs['exclude']: return False
            if not include or attr in include: return True
            else: return False            
        @functools.wraps(func)
        def wrapper(self,*args,**kwargs):
            # handle default values
            for attr,val in zip(reversed(attrs),reversed(defaults)):
                if sieve(attr): setattr(self, attr, val)
            # handle positional arguments
            positional_attrs=attrs[1:]            
            for attr,val in zip(positional_attrs,args):
                if sieve(attr): setattr(self, attr, val)
            # handle varargs
            if varargs:
                remaining_args=args[len(positional_attrs):]
                if sieve(varargs): setattr(self, varargs, remaining_args)                
            # handle varkw
            if kwargs:
                for attr,val in kwargs.iteritems():
                    if sieve(attr): setattr(self,attr,val)            
            return func(self,*args,**kwargs)
        return wrapper
    return _autoargs

Поэтому, когда вы говорите

class Foo(object):
    @autoargs()
    def __init__(self,x,path,debug=False,*args,**kw):
        pass
foo=Foo('bar','/tmp',True, 100, 101,verbose=True)

вы автоматически получаете эти атрибуты экземпляра:

print(foo.x)
# bar
print(foo.path)
# /tmp
print(foo.debug)
# True
print(foo.args)
# (100, 101)
print(foo.verbose)
# True

PS. Хотя я написал это (для забавы), я не рекомендую использовать autoargs для серьезной работы., ясный и непогрешимый. Я не могу сказать то же самое для autoargs.

PPS. Это только я или всене сломаны кнопки на Stackoverflow?Окно редактора потеряло все свои значки ...: ( Очистка кэша браузера устранила проблему.

12 голосов
/ 07 октября 2010

Есть элегантный способ сделать это.

Есть ли способ упростить этот процесс?Всякий раз, когда я добавляю новый член в класс Foo, я вынужден изменять конструктор.

Существует также способ raw .Это будет работать, но НЕ рекомендуется.Смотри и решай.

>>> class Foo(object):
    def __init__(self, **attrs):
        self.__dict__.update(**attrs)
    def __getattr__(self, attr):
        return self.__dict__.get(attr, None)


>>> f = Foo(a = 1, b = 2, c = 3)
>>> f.a, f.b
(1, 2)
>>> f = Foo(bar = 'baz')
>>> f.bar
'baz'
>>> f.a
>>> 

Конструктор аргументов с ключевыми словами позволяет вам обойтись без явного определения каких-либо аргументов. Предупреждение : это идет вразрез с принципом «явный лучше, чем неявный» .

Вам нужно переопределить __getattr__ ТОЛЬКО если вы хотите вернуть значение по умолчанию для атрибута, который отсутствует, вместо получения AttributeError.

0 голосов
/ 07 октября 2010

http://code.activestate.com/recipes/286185-automatically-initializing-instance-variables-from/

Этот рецепт и его комментарии предоставляют несколько методов.

Python: Автоматическая инициализация переменных экземпляра?

Это предыдущийвопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...