2009-09-14 29 views
5

Dường như thường __init__ phương pháp tương tự như sau:Python __init__ setattr trên đối số?

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

Có cách nọ cách kia để biến các đối số vào một danh sách (mà không cần đến *args hoặc **kwargs) và sau đó sử dụng setattr để thiết lập các biến Ví dụ, với tên của tham số và đối số được truyền? Và có thể cắt danh sách, ví dụ: bạn cần phải cắt ít nhất thành [1:] vì bạn không muốn self.self.

(thực sự tôi đoán nó sẽ cần phải là một từ điển để giữ tên và giá trị)

như thế này:

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

Cảm ơn!

Hưởng ứng Unknown của câu trả lời, tôi thấy điều này để làm việc:

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

hoặc

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

Không quá xấu ..

+1

dupe http://stackoverflow.com/questions/1389180/python-automatically-initialize-instance-variables – SilentGhost

+1

xem thêm: http://stackoverflow.com/questions/739625/setattr-with-kwargs-pythonic-or-not – Imran

Trả lời

7

Thông tin cho bạn đây. Vâng, đây là một tin tặc xấu xí. Có đối tượng cần biến __dict__. Nhưng này, một cái lót nhỏ gọn!

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

Trình tạo có thể lấy bất kỳ loại đối số nào.

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'] 

Nó cũng sẽ bao gồm bản thân, nhưng bạn có thể dễ dàng xóa hoặc tự thực hiện chức năng cập nhật tự bỏ qua bản thân.

+0

Điều này không làm những gì OP muốn: nó không có đối số ở tất cả! –

+1

@Ned, nó ... Bạn có thể chỉ định bất kỳ loại đối số nào bạn muốn. – Unknown

+2

Điều đó sẽ đặt tất cả các biến cục bộ thành các thuộc tính, cụ thể là "tự", điều này thật ngớ ngẩn. :) Bạn có thể tất nhiên bộ lọc "tự" ra khỏi người dân địa phương() đầu tiên, nhưng sau đó nó nhận được ít gọn gàng hơn. –

4

Không có cách nào tốt để có được những lý lẽ như một nếu chúng được chỉ định riêng lẻ trong chữ ký hàm. Bạn có thể có thể làm điều gì đó với kiểm tra hoặc hacks khung, nhưng điều đó sẽ xấu hơn chỉ đơn giản là chính tả nó ra như bạn đã làm.

+0

Nó không thể được thực hiện ngay cả khi nhìn vào hàm hoặc đối tượng mã. Trong khi bạn có thể làm điều gì đó khó chịu như giả định 'co_argcount' đầu tiên của' co_varnames' là các đối số, điều này sẽ không đúng khi đối mặt với giải nén chuỗi hoặc * args/** kwargs. – bobince

+0

Ned, phương pháp của tôi hoạt động đối với bất kỳ chữ ký phương thức nào mà không cần phải kiểm tra hoặc hacking khung. – Unknown

2

Xem tên mới có tên (mới trong Python 2.6) từ mô-đun bộ sưu tập có thể phù hợp với bạn hay không.

3

Hãy thử inspect.getargspec:

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

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

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

Bạn có thể sử dụng inspect.getargspec và đóng gói nó như là một trang trí. Tra cứu các đối số tùy chọn và từ khóa là một chút khó khăn, nhưng điều này nên làm điều đó:

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__ 

Sau đó bạn có thể sử dụng nó như thế này:

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

Bạn có thể làm điều đó bằng cách sử mẫn của các đối số, nhưng mã sẽ dài hơn mã bạn cố gắng thay thế. Đặc biệt là nếu bạn đang xử lý kw, mà bạn có thể phải làm.

mã ngắn này hoạt động trong hầu hết các trường hợp (được cải thiện từ ẩn dụ):

>>> 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) 

Nhưng nó là một hack xấu xí, làm cho mã dễ đọc hơn không có lý do đặc biệt, ngoại trừ sự lười biếng, vì vậy đừng làm điều đó. Ngoài ra, bạn có thường xuyên thực hiện thực sự có các lớp có hơn 5-6 tham số init không?

0

Làm thế nào để bắt nguồn từ một lớp học đặc biệt? Tôi nghĩ đó là rõ ràng hơn và linh hoạt hơn theo cách này:

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) 
1

Tôi thích điều đó tạo nhiều nhất, không phải là quá dài và cả hai bản sao-pasteable và phụ 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) 
Các vấn đề liên quan