2013-06-06 44 views
5

Tôi có nhu cầu cho các hàm có đối số mặc định phải được đặt ở thời gian chạy hàm (chẳng hạn như danh sách trống, giá trị bắt nguồn từ các đối số hoặc dữ liệu được lấy từ cơ sở dữ liệu) và hiện tôi đang sử dụng sau mẫu để đối phó với điều này:Đối số mặc định động trong hàm python

def foo(bar, baz=None): 
    baz = baz if baz else blar() 
    # Stuff 

đâu blar() cung cấp cho các giá trị mặc định thích hợp của baz mà có thể thay đổi trong khi thực hiện. Tuy nhiên, dòng baz = baz if baz else ... tấn công tôi là không phù hợp. Có ai khác có một phương pháp tốt hơn để tránh các ràng buộc một thời gian của các đối số chức năng mặc định? Các thư viện nhỏ, đa nền tảng có thể cài đặt bằng pip là các thay thế được chấp nhận.

Trả lời

8

Không, đó là khá nhiều. Thông thường, bạn kiểm tra is None vì vậy bạn có thể yên tâm vượt qua trong các giá trị falsey như 0 hoặc "", vv

def foo(bar, baz=None): 
    baz = baz if baz is not None else blar() 

Cách cũ thời là hai lót. Một số người có thể thích này

def foo(bar, baz=None): 
    if baz is None: 
     baz = blar() 
+3

Cách cũ sẽ tránh việc gán lại không cần thiết khi 'baz' không phải là' Không có'. – chepner

0

Một nhanh chóng & dụ bẩn thực hiện một cái gì đó mà có thể làm việc:

class DynDefault(object): 
    def __init__(self, callback): 
     self.callback = callback 
    def __call__(self): 
     return self.callback() 

def dyn_default(func): 
    def wrapper(*args, **kw): 
     args = [arg() for arg in args if isinstance(arg, DynDefault) else arg] 
     for k, v in kw.items(): 
      if isinstance(v, DynDefault): 
       kw[k] = v() 
     return func(*args, **kw) 
    return wrapper 

@dyn_default 
def foo(bar, baaz=DynDefault(blar)): 
    # problem solved 
+0

Giải pháp này bị hỏng. Bằng cách xử lý args, bạn không phải là lười biếng đánh giá các mặc định động args, nhưng bất kỳ có thể 'DynDefault' cung cấp khi bạn thực sự gọi hàm. Một giải pháp thực tế có thể thay thế 'foo.func_defaults' bằng một đối tượng mô tả, tuy nhiên func_defaults chỉ có thể là tuple. Mặc dù subclassing một tuple, và overloading __iter__ và __getitem__ có thể giữ cho chúng ta chơi, một phân tích nhỏ về nguồn CPython cho thấy rằng các thành viên của đối tượng 'func_defaults' được truy cập trực tiếp trong bộ nhớ trong PyObject, chứ không phải thông qua giao diện lớp kiểu mới. không thể giải được. :( –

1

Bạn có thể thay

baz = baz if baz else blar() 

với

baz = baz or blar() 

nếu bạn vẫn hài lòng với việc chỉ thử nghiệm các giá trị giả thay vì None.

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