2009-10-28 30 views
36

tôi nhập khẩu từ một CSV và nhận dữ liệu gần ở định dạngTạo thuộc tính thể hiện của lớp từ một từ điển?

{ 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 } 

Tên của các lĩnh vực năng động. (À, chúng năng động ở chỗ có thể có nhiều hơn Field1 và Field2, nhưng tôi biết Field1Field2 luôn ở đó.

Tôi muốn có thể chuyển từ điển này vào lớp học của mình . allMyFields vì vậy mà tôi có thể truy cập các dữ liệu trên như tài sản

class allMyFields: 
    # I think I need to include these to allow hinting in Komodo. I think. 
    self.Field1 = None 
    self.Field2 = None 

    def __init__(self,dictionary): 
     for k,v in dictionary.items(): 
      self.k = v 
      #of course, this doesn't work. I've ended up doing this instead 
      #self.data[k] = v 
      #but it's not the way I want to access the data. 

q = { 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 } 
instance = allMyFields(q) 
# Ideally I could do this. 
print q.Field1 

Mọi góp ý theo như lý do tại sao? - tôi muốn để có thể tận dụng lợi thế của mã gián tiếp, và nhập dữ liệu vào một từ điển được gọi là data như tôi đã làm không đủ khả năng cho tôi.

(Vì tên biến không được giải quyết cho đến khi chạy, tôi vẫn sẽ phải ném một cái xương đến Komodo - Tôi nghĩ rằng self.Field1 = None là đủ.)

Vậy - làm cách nào để làm những gì tôi muốn? Hay tôi đang sủa một cây không phải python được thiết kế kém?

+1

Bạn không cần thuộc tính lớp cho gợi ý Chỉnh sửa Komodo. Nó có thể đọc một phương thức '__init__' để tìm các biến' self.'. Về cơ bản hơn, tại sao bạn không sử dụng 'csv.DictReader' đơn giản cho việc này và tạo từ điển từ mỗi hàng? –

+0

SLott - Tôi sửa đổi tiêu đề theo cách thủ công bằng re.sub() và thêm vào tiêu đề 'giả'. Nó không phải là một lý do thực sự tốt, nhưng đổi tên chìa khóa sau khi một DictReader là rất nhiều tốn kém hơn. –

Trả lời

66

Bạn có thể sử dụng setattr (cẩn thận mặc dù: không phải mọi chuỗi là một tên thuộc tính hợp lệ):

>>> class AllMyFields: 
...  def __init__(self, dictionary): 
...   for k, v in dictionary.items(): 
...    setattr(self, k, v) 
... 
>>> o = AllMyFields({'a': 1, 'b': 2}) 
>>> o.a 
1 

Edit: cho tôi giải thích sự khác biệt giữa các mã trên và SilentGhost's answer. Đoạn mã trên tạo một lớp trong đó thuộc tính dụ được dựa trên một từ điển nhất định. Mã của SilentGhost tạo một lớp có thuộc tính lớp được dựa trên một từ điển nhất định.

Tùy thuộc vào tình huống cụ thể của bạn, một trong hai giải pháp này có thể phù hợp hơn. Bạn có đồng bằng để tạo một hoặc nhiều phiên bản lớp không? Nếu câu trả lời là một, bạn cũng có thể bỏ qua việc tạo đối tượng hoàn toàn và chỉ xây dựng kiểu (và do đó đi với câu trả lời của SilentGhost).

+1

Mã với bản chỉnh sửa tiền thưởng giải thích sự khác biệt giữa cả hai câu trả lời hay là thực sự hữu ích, cảm ơn! – aimbire

24
>>> q = { 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 } 
>>> q = type('allMyFields', (object,), q) 
>>> q.Field1 
3000 

tài liệu cho type giải thích rõ những gì đang diễn ra ở đây (xem sử dụng như một constructor).

chỉnh sửa: trong trường hợp bạn cần biến Ví dụ, sau đây cũng làm việc:

>>> a = q()    # first instance 
>>> a.Field1 
3000 
>>> a.Field1 = 1 
>>> a.Field1 
1 
>>> q().Field1   # second instance 
3000 
+3

+1, nhưng tôi nghĩ bạn nên giải thích OP về mã này và/hoặc cung cấp liên kết đến tài liệu. – Stephan202

+5

Tôi đoán tên của anh ấy * là * "SilentGhost" –

+0

Cách tiếp cận gọn gàng, nhưng thực tế là các biến lớp của chúng ít hấp dẫn hơn các biến mẫu. –

5

Bạn cũng có thể sử dụng dict.update thay vì bằng tay Looping trên items (và nếu bạn đang looping, iteritems là tốt hơn) .

class allMyFields(object): 
    # note: you cannot (and don't have to) use self here 
    Field1 = None 
    Field2 = None 

    def __init__(self, dictionary): 
     self.__dict__.update(dictionary) 

q = { 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 } 
instance = allMyFields(q) 

print instance.Field1  # => 3000 
print instance.Field2  # => 6000 
print instance.RandomField # => 5000 
2

Sử dụng setattr cho cách đẹp. Cách nhanh chóng-n-dơ bẩn là cập nhật từ điển nội bộ cá thể:

>>> class A(object): 
... pass 
... 
>>> a = A() 
>>> a.__dict__.update({"foo": 1, "bar": 2}) 
>>> a.foo 
1 
>>> a.bar 
2 
>>> 
4

Sử dụng tuples được đặt tên (Python 2.6):

>>> from collections import namedtuple 

>>> the_dict = {'Field1': 3, 'Field2': 'b', 'foo': 4.9} 
>>> fields = ' '.join(the_dict.keys()) 
>>> AllMyFields = namedtuple('AllMyFields', fields) 
>>> instance = AllMyFields(**the_dict) 

>>> print instance.Field1, instance.Field2, instance.foo 
3 b 4.9 
3

Bạn có thể làm cho một lớp con của dict cho phép thuộc tính tra cứu cho các phím:

class AttributeDict(dict): 
    def __getattr__(self, name): 
     return self[name] 

q = AttributeDict({ 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }) 
print q.Field1    
print q.Field2    
print q.RandomField 

Nếu bạn cố gắng tìm kiếm một thuộc tính mà dict đã có (nói keys hoặc get), bạn sẽ nhận được thuộc tính lớp dict (một phương thức). Nếu khóa bạn yêu cầu không tồn tại trên lớp dict, thì phương thức __getattr__ sẽ được gọi và sẽ thực hiện tra cứu khóa của bạn.

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