2009-03-16 10 views
37

Tôi đang gỡ lỗi một số Python cần, như đầu vào, danh sách các đối tượng, mỗi đối tượng có một số thuộc tính.Có thể tạo các đối tượng ẩn danh bằng Python không?

Tôi muốn mã hóa một số giá trị thử nghiệm - giả sử danh sách bốn đối tượng có thuộc tính "foo" được đặt thành một số.

Có cách nào ngắn gọn hơn không?

x1.foo = 1 
x2.foo = 2 
x3.foo = 3 
x4.foo = 4 
myfunc([x1, x2, x3, x4]) 

Lý tưởng nhất, tôi chỉ muốn để có thể nói điều gì đó như:

myfunc([<foo=1>, <foo=2>, <foo=3>, <foo=4>]) 

(Rõ ràng, đó là thực hiện-up cú pháp Nhưng có một cái gì đó tương tự mà thực sự hoạt động.?)

Lưu ý: Điều này sẽ không bao giờ được đăng ký. Nó chỉ là một số mã gỡ rối. Vì vậy, đừng lo lắng về khả năng đọc hoặc bảo trì.

Trả lời

36

Tôi thích giải pháp Tetha, nhưng đó là không cần thiết phức tạp.

Dưới đây là một cái gì đó đơn giản hơn:

>>> class MicroMock(object): 
...  def __init__(self, **kwargs): 
...   self.__dict__.update(kwargs) 
... 
>>> def print_foo(x): 
...  print x.foo 
... 
>>> print_foo(MicroMock(foo=3)) 
3 
+0

Tuy nhiên, nếu bạn đang tạo toàn bộ các gói này, bạn có thể tiết kiệm thời gian/bộ nhớ bằng cách sử dụng từ điển đã cho thay vì tạo từ mới và sao chép tất cả các mục nhập. Không * thực sự * quan trọng, mặc dù. –

+1

tốt, tôi có thể chủ quan, nhưng tôi thấy không có đơn giản hóa đáng kể. Có, bạn sử dụng __init__ và cập nhật, nhưng bạn vẫn đang loay hoay xung quanh với __dict__. – Tetha

+1

Bạn nói đúng, không có đơn giản hóa đáng kể nào. Nó chỉ ngắn hơn và không sử dụng __new__, đó là tất cả. – DzinX

15

Có xem xét này:


class MiniMock(object): 
    def __new__(cls, **attrs): 
     result = object.__new__(cls) 
     result.__dict__ = attrs 
     return result 

def print_foo(x): 
    print x.foo 

print_foo(MiniMock(foo=3)) 
4

Non sang trọng:

def mock(**attrs): 
    r = lambda:0 
    r.__dict__ = attrs 
    return r 

def test(a, b, c, d): 
    print a.foo, b.foo, c.foo, d.foo 

test(*[mock(foo=i) for i in xrange(1,5)]) 
# or 
test(mock(foo=1), mock(foo=2), mock(foo=3), mock(foo=4)) 
3

Một rõ ràng hack:

class foo1: x=3; y='y' 
class foo2: y=5; x=6 

print(foo1.x, foo2.y) 

Nhưng đối với usecase chính xác của bạn, gọi một hàm với các đối tượng ẩn danh trực tiếp, tôi không biết bất kỳ một lót ít tiết hơn

myfunc(type('', (object,), {'foo': 3},), type('', (object,), {'foo': 4})) 

Ugly, không công việc, nhưng không thực sự.

2

Vì vậy, ngắn gọn, chẳng hạn Python! O.o

>>> Object = lambda **kwargs: type("Object",(), kwargs) 
>>> person = Object(name = "Bernhard", gender = "male", age = 42) 
>>> person.name 
'Bernhard' 
>>> 

EDIT: Được rồi, về mặt kỹ thuật việc này tạo đối tượng lớp, không phải đối tượng đối tượng. Nhưng bạn có thể đối xử với nó như một đối tượng ẩn danh hoặc bạn sửa đổi dòng đầu tiên bằng cách thêm một cặp ngoặc đơn để tạo một thể hiện ngay lập tức:

>>> Object = lambda **kwargs: type("Object",(), kwargs)() 
1

Tính đến Python 3.3, có types.SimpleNamespace thực hiện chính xác những gì bạn muốn:

myfunc([types.SimpleNamespace(foo=1), types.SimpleNamespace(foo=2), types.SimpleNamespace(foo=3), types.SimpleNamespace(foo=4)]) 

đó là một chút dài dòng, nhưng bạn có thể làm sạch nó lên với một bí danh:

_ = types.SimpleNamespace 
myfunc([_(foo=1), _(foo=2), _(foo=3), _(foo=4)]) 

Và bây giờ mà thực sự khá gần với cú pháp hư cấu trong câu hỏi của bạn.

+0

Tín dụng cho @RoadieRich để gợi ý '_' làm tên lớp trong một chú thích trước đó. –