Ответ 1
Самый питонический путь - это то, что вы уже написали. Если вы с удовольствием требуете именованные аргументы, вы можете сделать это:
class foo:
def __init__(self, **kwargs):
vars(self).update(kwargs)
Я часто нахожу, что создаю конструкторы классов следующим образом:
class foo:
def __init__(self, arg1, arg2, arg3):
self.arg1 = arg1
self.arg2 = arg2
self.arg3 = arg3
Это может стать болью, если число аргументов (и атрибутов класса) становится высоким. Я ищу самый pythonic способ прокрутить список аргументов конструктора и соответственно присвоить атрибуты. Я работаю с Python 2.7, поэтому в идеале я ищу помощь с этой версией.
Самый питонический путь - это то, что вы уже написали. Если вы с удовольствием требуете именованные аргументы, вы можете сделать это:
class foo:
def __init__(self, **kwargs):
vars(self).update(kwargs)
Предоставленные ответы полагаются на аргументы *vargs
и **kargs
, что может быть совсем не удобно, если вы хотите ограничить определенный набор аргументов конкретными именами: вам нужно будет все проверить вручную.
Здесь хранитель, который хранит предоставленные аргументы метода в связанном экземпляре как атрибуты с их соответствующими именами.
import inspect
import functools
def store_args(method):
"""Stores provided method args as instance attributes."""
argspec = inspect.getargspec(method)
defaults = dict(zip( argspec.args[-len(argspec.defaults):], argspec.defaults ))
arg_names = argspec.args[1:]
@functools.wraps(method)
def wrapper(*positional_args, **keyword_args):
self = positional_args[0]
# Get default arg values
args = defaults.copy()
# Add provided arg values
list(map( args.update, ( zip(arg_names, positional_args[1:]), keyword_args.items() ) ))
# Store values in instance as attributes
self.__dict__.update(args)
return method(*positional_args, **keyword_args)
return wrapper
Затем вы можете использовать его следующим образом:
class A:
@store_args
def __init__(self, a, b, c=3, d=4, e=5):
pass
a = A(1,2)
print(a.a, a.b, a.c, a.d, a.e)
Результат будет 1 2 3 4 5
на Python3.x или (1, 2, 3, 4, 5)
на Python2.x
class foo:
def __init__(self, **kwargs):
for arg_name, arg_value in kwargs.items():
setattr(self, arg_name, arg_value)
Для этого требуются имена аргументов:
obj = foo(arg1 = 1, arg2 = 2)
Вы можете сделать это как для позиционных, так и для аргументов ключевого слова:
class Foo(object):
def __init__(self, *args, **kwargs):
for arg in args:
print arg
for kwarg in kwargs:
print kwarg
*
помещает позиционные аргументы в кортеж и **
аргументы ключевого слова в словарь:
foo = Foo(1, 2, 3, a=4, b=5, c=6) // args = (1, 2, 3), kwargs = {'a' : 4, ...}
Как насчет этого?
class foo:
def __init__(self, arg1, arg2, arg3):
for _prop in dir():
setattr(self, _prop, locals()[_prop])
Это использует встроенную функцию dir для python для итерации по всем локальным переменным. Он имеет незначительный побочный эффект создания посторонней самооценки, но вы можете отфильтровать его, если хотите. Кроме того, если вы должны были объявить какие-либо другие локали перед вызовом dir(), они также будут добавлены как созданные атрибуты объекта.
Как отмечали другие, в большинстве случаев вы должны, вероятно, придерживаться своего оригинального метода "pythonic".
Однако, если вы действительно хотите пройти целых девять ярдов, вот какой-то код, который аккуратно обрабатывает args, ключевое слово args, если это необходимо, и избегает повторения шаблонов:
def convert_all_args_to_attribs(self, class_locals):
class_locals.pop('self')
if 'kwargs' in class_locals:
vars(self).update(class_locals.pop('kwargs'))
vars(self).update(class_locals)
class FooCls:
def __init__(self, foo, bar):
convert_all_args_to_attribs(self, locals())
class FooClsWithKeywords:
def __init__(self, foo, bar, **kwargs):
convert_all_args_to_attribs(self, locals())
f1 = FooCls(1,2)
f2 = FooClsWithKeywords(3,4, cheese='stilton')
print vars(f1) #{'foo': 1, 'bar': 2}
print vars(f2) #{'cheese': 'stilton', 'foo': 3, 'bar': 4}
Как насчет повторения имен явных переменных?
т.е.
class foo:
def __init__(self, arg1, arg2, arg3):
for arg_name in 'arg1,arg2,arg3'.split(','):
setattr(self, arg_name, locals()[arg_name])
f = foo(5,'six', 7)
Результат с помощью
print vars(f)
{'arg1': 5, 'arg2': 'six', 'arg3': 7}
Мое предложение похоже на @peepsalot, за исключением его более явного и не использует dir()
, который согласно документации
его подробное поведение может меняться через выпуски
* args - последовательность, поэтому вы можете обращаться к элементам с помощью индексации:
def __init__(self, *args):
if args:
self.arg1 = args[0]
self.arg2 = args[1]
self.arg3 = args[2]
...
или вы можете просмотреть все из них
for arg in args:
#do assignments