2011-11-18 33 views
58

Giả sử có một lớp với hàm tạo (hoặc hàm khác) lấy một số đối số và sau đó đặt chúng làm thuộc tính lớp có điều kiện.Làm thế nào bạn có thể thiết lập các thuộc tính lớp từ các đối số biến (kwargs) trong python

Tôi có thể đặt chúng theo cách thủ công, nhưng có vẻ như các thông số biến là đủ phổ biến trong python rằng cần có một thành ngữ phổ biến để thực hiện việc này. Nhưng tôi không chắc chắn làm thế nào để làm điều này tự động.

Tôi có ví dụ sử dụng eval, nhưng điều đó hầu như không an toàn. Tôi muốn biết cách thích hợp để làm điều này - có lẽ với lambda?

class Foo: 
    def setAllManually(self, a=None, b=None, c=None): 
     if a!=None: 
      self.a = a 
     if b!=None: 
      self.b = b 
     if c!=None: 
      self.c = c 
    def setAllWithEval(self, **kwargs): 
     for key in **kwargs: 
      if kwargs[param] != None 
       eval("self." + key + "=" + kwargs[param]) 
+0

Dường như những câu hỏi tương tự như: http://stackoverflow.com/questions/3884612/automatically-setting-class-member- biến-in-python http://stackoverflow.com/questions/356718/how-to-handle-constructors-or-methods-with-a-different-set-or-type-of-argument http: // stackoverflow. com/questions/1446555/python-decorator-to-đảm bảo-that-kwargs-là-chính xác vì vậy nó trông giống như những gì tôi muốn là có lẽ này - self .__ dict __ [key] = kwargs [key] – fijiaaron

+0

Không thực sự liên quan đến câu hỏi, nhưng bạn có thể muốn kiểm tra [PEP8] (http://www.python.org/dev/peps/pep-0008/) để biết một vài gợi ý về kiểu dáng Python thông thường. –

+0

Có một thư viện tuyệt vời cho người được gọi là attrs này. đơn giản là 'pip install attrs', trang trí lớp của bạn với' @ attr.s', và đặt arg là 'a = attr.ib(); b = attr.ib() 'v.v. Đọc thêm [ở đây] (https://glyph.twistedmatrix.com/2016/08/attrs.html). –

Trả lời

105

Bạn có thể sử dụng phương pháp setattr:

class Foo: 
    def setAllWithKwArgs(self, **kwargs): 
    for key, value in kwargs.items(): 
     setattr(self, key, value) 

Có một getattr phương pháp tương tự để lấy các thuộc tính.

+0

@larsks cảm ơn nhưng bất kỳ ý tưởng nào về cách chúng tôi có thể giải nén chỉ một khóa từ điển? http://stackoverflow.com/questions/41792761/calling-and-using-an-attribute-stored-in-variable-using-beautifulsoup-4 – JinSnow

0

của họ có thể là một giải pháp tốt hơn nhưng những gì nói đến cái tâm đối với tôi là:

class Test: 
    def __init__(self, *args, **kwargs): 
     self.args=dict(**kwargs) 

    def getkwargs(self): 
     print(self.args) 

t=Test(a=1, b=2, c="cats") 
t.getkwargs() 


python Test.py 
{'a': 1, 'c': 'cats', 'b': 2} 
+0

Điều tôi đang tìm là đặt thuộc tính dựa trên xác thực có điều kiện. Tôi nhận ra rằng vấn đề với việc sử dụng kwargs là nó không xác nhận (hoặc tài liệu) mà các thuộc tính được chấp nhận – fijiaaron

+0

Vâng, tôi nhận ra câu trả lời @larsks là tốt hơn. Tìm hiểu điều gì đó mới mẻ hàng ngày tại SO! – Tom

-1

tôi nghi ngờ nó có thể là tốt hơn trong hầu hết các trường hợp sử dụng args tên (đối với tốt hơn đang tự chủ tài liệu) để nó có thể trông một cái gì đó như thế này:

class Foo: 
    def setAll(a=None, b=None, c=None): 
     for key, value in (a, b, c): 
      if (value != None): 
       settattr(self, key, value) 
+0

Lặp lại này không hoạt động: 'cho khóa, giá trị trong (a, b, c)' – rerx

2
class SymbolDict(object): 
    def __init__(self, **kwargs): 
    for key in kwargs: 
     setattr(self, key, kwargs[key]) 

x = SymbolDict(foo=1, bar='3') 
assert x.foo == 1 

tôi gọi là lớp SymbolDict bởi vì nó thực chất là một cuốn từ điển mà hoạt động sử dụng ký tự thay vì các chuỗi. Nói cách khác, bạn làm x.foo thay vì x['foo'] nhưng dưới bìa nó thực sự là điều tương tự đang diễn ra.

65

Điều này có dễ dàng hơn không?

class Bar(object): 
    def __init__(self, **kwargs): 
     self.__dict__.update(kwargs) 

sau đó bạn có thể:

>>> bar = Bar(a=1, b=2) 
>>> bar.a 
1 

và với một cái gì đó như:

allowed_keys = ['a', 'b', 'c'] 
self.__dict__.update((k, v) for k, v in kwargs.iteritems() if k in allowed_keys) 

bạn có thể lọc các phím trước.

+1

Thậm chí tốt hơn để làm cho allow_keys một tập hợp :) – PascalVKooten

4

Tôi đề nghị một biến thể của câu trả lời fqxp 's, trong đó, ngoài việc phép thuộc tính, cho phép bạn thiết lập giá trị mặc định cho các thuộc tính:

class Foo(): 
    def __init__(self, **kwargs): 
     # define default attributes 
     default_attr = dict(a=0, b=None, c=True) 
     # define (additional) allowed attributes with no default value 
     more_allowed_attr = ['d','e','f'] 
     allowed_attr = list(default_attr.keys()) + more_allowed_attr 
     default_attr.update(kwargs) 
     self.__dict__.update((k,v) for k,v in default_attr.items() if k in allowed_attr) 

Đây là Python 3.x mã, cho Python 2.x bạn cần ít nhất một điều chỉnh, iteritems() thay cho items().

1

này là đơn giản nhất thông qua larsks

class Foo: 
    def setAllWithKwArgs(self, **kwargs): 
     for key, value in kwargs.items(): 
      setattr(self, key, value) 

ví dụ của tôi:

class Foo: 
    def __init__(self, **kwargs): 
     for key, value in kwargs.items(): 
      setattr(self, key, value) 

door = Foo(size='180x70', color='red chestnut', material='oak') 
print(door.size) #180x70 
+0

có thể smb giải thích kwargs.items() là gì? –

+0

'kwargs' là từ điển của các đối số từ khóa và' items() 'là phương thức trả về một bản sao của danh sách các cặp' (khóa, giá trị) 'của từ điển. – harryscholes

4

Hầu hết các câu trả lời ở đây không bao gồm một cách tốt để khởi tạo tất cả các phép tính để chỉ một giá trị mặc định. Vì vậy, để thêm vào các câu trả lời được đưa ra bởi @fqxp và @mmj:

class Myclass: 

    def __init__(self, **kwargs): 
     # all those keys will be initialized as class attributes 
     allowed_keys = set(['attr1','attr2','attr3']) 
     # initialize all allowed keys to false 
     self.__dict__.update((key, False) for key in allowed_keys) 
     # and update the given keys by their given values 
     self.__dict__.update((key, value) for key, value in kwargs.items() if key in allowed_keys) 
+0

Tôi nghĩ đây là câu trả lời hoàn chỉnh nhất do việc inizialization thành 'False'. Điểm tốt! – Kyrol

Các vấn đề liên quan