2010-10-07 20 views
19

Nói, tôi có lớp sau trong PythonTự động thiết lập các biến thành viên lớp bằng 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 

Có cách nào để đơn giản hóa quá trình này? Bất cứ khi nào tôi thêm một thành viên mới vào lớp Foo, tôi buộc phải sửa đổi hàm tạo.

+2

Tôi cũng thấy rằng phân lớp có tên làtập tin - http://docs.python.org/dev/library/collections.html#collections.namedtuple không phải là một ý tưởng tồi. –

Trả lời

25

Xin lưu ý rằng

class Foo(object): 
    a = None 

đặt ra một cặp khóa-giá trị trong dict Foo 's:

Foo.__dict__['a']=None 

khi

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

đặt ra một cặp khóa-giá trị trong Foo đối tượng ví dụ của đối tượng:

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

Vì vậy, đặt thành viên lớp ở đầu định nghĩa của bạn không liên quan trực tiếp đến cài đặt thuộc tính thể hiện trong nửa dưới định nghĩa của bạn (bên trong __init__.

Ngoài ra, bạn nên lưu ý rằng __init__ là trình khởi chạy của Python. __new__ là lớp học hàm tạo.


Nếu bạn đang tìm kiếm một cách để tự động thêm một số ví dụ thuộc tính dựa trên lập luận __init__ 's, bạn có thể sử dụng này:

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 

Vì vậy, khi bạn nói

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

bạn tự động nhận được các thuộc tính dụ này:

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

PS. Mặc dù tôi đã viết này (cho vui), tôi không khuyên bạn sử dụng autoargs cho công việc nghiêm trọng. Rõ ràng là đơn giản, rõ ràng và không thể sai lầm. Tôi không thể nói tương tự cho autoargs.

PPS. Là nó chỉ cho tôi, hoặc là rất nhiều nút bị hỏng trên Stackoverflow? Cửa sổ soạn thảo đã mất tất cả các biểu tượng của nó ... :( Xoá bộ nhớ cache của trình duyệt cố định vấn đề.

+0

Tôi quên thêm - cảm ơn vì đã xóa các thuật ngữ python của tôi. –

+0

@Jeeyoung: Không sao cả; mừng vì tôi có thể giúp. – unutbu

+0

Điều này có nên ở trong thư viện chuẩn không? Tôi không thấy điểm thiết lập trên mọi __init __... –

10

elegant cách để thực hiện việc này.

Có cách nào để đơn giản hóa quy trình này không? Bất cứ khi nào tôi thêm một thành viên mới vào lớp Foo, tôi buộc phải sửa đổi hàm tạo.

Ngoài ra còn có cách thô. Nó sẽ hoạt động, nhưng KHÔNG được khuyến nghị. Xem và quyết định.

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

Trình tạo đối số từ khóa cho phép bạn thoát khỏi mà không xác định rõ ràng bất kỳ đối số nào. Cảnh báo: điều này đi ngược lại nguyên tắc "rõ ràng là tốt hơn là ẩn".

Bạn chỉ cần ghi đè __getattr__ CHỈ nếu bạn muốn trả lại giá trị mặc định cho thuộc tính không có mặt thay vì nhận được AttributeError.

+0

hoàn hảo! cách thanh lịch nhất để làm điều này. – karantan

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