2009-12-10 60 views
8

Tôi muốn tạo ra một đối tượng "struct" để giữ các cờ trạng thái khác nhau. Cách tiếp cận đầu tiên của tôi là này (javascript phong cách)đối tượng struct trong python

>>> status = object() 
>>> status.foo = 3 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'object' object has no attribute 'foo' 

Chắc chắn không phải những gì tôi mong đợi, bởi vì công trình này:

>>> class Anon: pass 
... 
>>> b=Anon() 
>>> b.foo = 4 

Tôi đoán đây là vì đối tượng() không có một __dict__. Tôi không muốn sử dụng một từ điển, và giả sử tôi không muốn tạo đối tượng Anon, có giải pháp nào khác không?

+2

Xem http://stackoverflow.com/questions/1264833/python-class-factory-to-produce-simple-struct-like-classes –

+0

Tôi đang sử dụng trăn 2.5, và trong mọi trường hợp, bộ tuple có tên không cho phép, theo như tôi hiểu, để tự động kết nối các thành viên mới sau này. Nó không rõ ràng từ các ví dụ được đưa ra. –

+0

@Stefano Borini: vì vậy bạn về cơ bản yêu cầu một dict nơi bạn có thể nói 'foo.bar' thay vì' foo ['bar'] '? –

Trả lời

21

Cách ngắn gọn nhất để làm cho "một đối tượng chung chung mà bạn có thể gán/lấy thuộc tính" có lẽ là:

b = lambda:0 

Như hầu hết câu trả lời khác chỉ ra, có rất nhiều cách khác, nhưng thật khó để đánh dấu cái này cho sự phù hợp (lambda:0 chính xác là cùng một số ký tự như object() ... ;-).

+20

Chỉ khi bạn không đếm các nhân vật giải thích những gì nó là của nó! : D –

+0

woah! : D +1000 cho Alex –

+1

@Stefano, cảm ơn! @gnibbler, lambda của đầy đủ thần bí mà bạn không cần phải giải thích, bạn chỉ cần thực hiện cử chỉ ngón tay bí ẩn trong không khí và tất cả mọi người trở lại trong sợ hãi (tùy chọn, tiếng thì thầm "lambda, Ultimate ...!", http: // lambda-the-ultimate.org/ và/hoặc xem http://en.wikipedia.org/wiki/Lambda cho nhiều tài liệu tham khảo tối nghĩa khác). –

3

Hãy thử điều này

>>> status=type('status',(object,),{})() 
>>> status.foo=3 
>>> status.foo 
3 

Bạn không cần phải cung cấp cho các lớp một tên nếu bạn không muốn

>>> status=type('',(object,),{})() 
>>> status.__class__.__name__ 
'' 
+0

điều này thật tuyệt và hacky :) –

+0

Xin lỗi gnibbler, bạn trả lời là tốt, nhưng Alex 'lại khiến tôi ngạc nhiên :) –

+0

không ai thấy trò đùa ở đây? nó giống như 'trạng thái lớp (đối tượng): pass'. –

15

Từ Python Official Documentation:

9,7. Tỷ lệ cược và kết thúc

Đôi khi nó rất hữu ích để có một dữ liệu loại tương tự như “kỷ lục” Pascal hoặc C “struct”, bundling cùng một vài mục dữ liệu được đặt tên. Rỗng lớp định nghĩa sẽ làm độc đáo:

class Employee: 
    pass 

john = Employee() # Create an empty employee record 

# Fill the fields of the record 
john.name = 'John Doe' 
john.dept = 'computer lab' 
john.salary = 1000 

Điều này có vẻ tự nhiên và đơn giản: Pythonic. Remember the Zen! "Đơn giản là tốt hơn phức tạp" (số 3) và "Nếu việc triển khai dễ giải thích, có thể là một ý tưởng hay" (số 11)

Ngoài ra, struct không là gì khác ngoài class (ví dụ: struct{};class{public:}; là điều tương tự (ví dụ: C++)). Bạn không nên xem xét điều này và tránh các cấu trúc nhân tạo trong chương trình Python của bạn? Python được cho là dễ đọc, dễ bảo trì và dễ hiểu.

+3

Ugh, đây là tài liệu cũ và họ nên làm sạch nó. Mã ví dụ này tạo "lớp kiểu cũ". Đây không phải là khuyến cáo thực hành nữa, và trong Python 3.x nó thậm chí sẽ không hoạt động. Để làm ví dụ này chính xác là một lớp học kiểu mới sẽ làm việc trong Python 3.x: 'class Employee (object): pass' Đó là tất cả các bạn phải làm, chỉ cần kế thừa từ 'object' và bạn có một lớp học mới. – steveha

+1

Đây chính là ví dụ Anon mà OP cho biết họ không muốn làm. –

+0

Vâng, đó là tốt. Thật khó chịu hơn bởi thực tế bạn phải định nghĩa class Status: pass và sau đó status = Status(). –

2

Bí mật ở đây là sự khác biệt giữa đối tượngtrường lớp.

Trong Python, mọi thứ đều là một đối tượng. Các lớp là các đối tượng, các số nguyên là các đối tượng, các kiểu là các đối tượng và các cá thể lớp là các đối tượng. Khi bạn nói object(), bạn sẽ nhận được đối tượng cấp cơ sở đơn giản. Không có gì. Hoàn toàn vô dụng. Mức thấp hơn bất kỳ thứ gì khác bạn có thể tham chiếu bằng Python.

Bạn có thể nghĩ gọi số object() cung cấp cho bạn phiên bản lớp. Điều này là dễ hiểu, bởi vì bạn có thể nghĩ rằng object là một lớp học. Nó không phải. Mặc dù bạn có thể nghĩ như vậy vì đó là "lớp học" cơ sở được sử dụng để định nghĩa lớp kiểu mới như:

class MyClass(object): 
    pass 

object là trong thực tế, một loại (như thế nào strint nhiều loại).Khi bạn gọi object(), bạn không xây dựng một cá thể lớp, hãy tạo một kiểu đối tượng đặc biệt của bạn. Nhưng trong trường hợp của object, nó đặc biệt trong cách hoàn toàn blah.

Chỉ các phiên bản lớp mới có khả năng đặc biệt để kết thúc mọi thứ bằng ký hiệu chấm. Đó không phải là một tài sản chung của tất cả các đối tượng. Hãy tưởng tượng nếu đó là trường hợp! Bạn có thể làm những việc điên rồ như thêm thuộc tính vào chuỗi:

s = "cat" 
s.language = "english" 

Rõ ràng là bạn không thể làm điều đó.

+3

'object()' trả về một thể hiện. Nó được sử dụng đôi khi nếu bạn cần một giá trị duy nhất –

8

Tôi đã có cùng một câu hỏi một lần. Tôi đã hỏi nó trong một danh sách gửi thư, và Alex Martelli chỉ ra rằng object là cơ sở của tất cả các thừa kế trong Python; nếu object() tạo ra một cá thể lớp với từ điển riêng của nó, thì mọi đối tượng trong Python sẽ phải có từ điển riêng của nó, và điều đó sẽ lãng phí bộ nhớ. Ví dụ: TrueFalse là các đối tượng; rõ ràng họ không có nhu cầu về từ điển của riêng họ!

tôi sẽ rất vui nếu có một số loại tích hợp tính năng Python mà tôi chỉ có thể nói:

x = struct() 
x.foo = 1 
x.bar = 2 

Nhưng nó là tầm thường để viết struct():

class struct(object): 
    pass 

Hoặc bạn có thể làm phức tạp hơn một chút:

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

Điều phức tạp hơn cho phép bạn làm thứ là:

x = struct(foo=1, bar=2) 
print(x.foo) # prints 1 
print(x.bar) # prints 2 
x.baz = 3 
print(x.baz) # prints 3 

Nhưng nó quá tầm thường để viết struct() mà tôi đoán nó không được coi là đáng để thêm vào ngôn ngữ. Có lẽ chúng ta nên đẩy để có một tính năng tiêu chuẩn được thêm vào mô-đun collections hoặc gì đó.

+0

Để khuyến khích tư duy pythonic và mã có thể đọc được, bạn có thể tận dụng 'struct'. 'Struct' rõ ràng là một' lớp' và không phải là một hàm dựng sẵn hoặc hàm. Nhưng tôi có thể đánh giá cao suy nghĩ của bạn rằng bạn đang tạo một "nội trang" cá nhân rất giống với lớp 'object' được dựng sẵn. Và 'struct' thường trông đơn giản hơn. – hobs

+0

Thực ra, tôi thường gọi lớp tầm thường này là 'Box()' khi tôi viết nó trong các chương trình của mình. Ở đây tôi đã đề xuất một nội trang dựng sẵn và các nội trang Python là chữ thường (như 'deque'), trừ khi chúng không (giống như' Counter'). Tôi thích viết hoa các tên lớp hơn, nhưng tôi đoán tôi sẽ không chỉnh sửa câu trả lời. – steveha

+0

@steveha Lớp vỏ của Python được xây dựng trong biểu thị ngôn ngữ mà chúng được triển khai. Nếu chúng được thực hiện trong C, chúng đều là chữ thường, nhưng nếu chúng được triển khai bằng Python thì chúng được ClassCased. Xem câu trả lời này (http://stackoverflow.com/a/14974045/1490091) để biết thêm chi tiết. –

4

Cá nhân tôi nghĩ rằng giải pháp sạch nhất là những gì bạn đã đoán:

class Scratch(object): 
    pass 

s = Scratch() 
s.whatever = 'you want' 

Tôi biết bạn nói rằng bạn không muốn có một __dict__, nhưng gây bối rối cho tôi khi tôi không thể nhìn thấy một lý do để quan tâm đến điều đó. Bạn không cần phải tham chiếu __dict__, đó là một chi tiết triển khai Python bên trong. Dù sao, bất kỳ cá thể nào trong Python cho phép các thuộc tính tự động thêm sẽ có một __dict__ vì đó là cách mà Python làm các thuộc tính động. Ngay cả khi trường hợp được tạo ra một cách thực sự thông minh, nó sẽ có một __dict__.

Nếu bạn chưa làm như vậy, tôi khuyên bạn nên đọc PEP 20 và PEP 8 (không có danh tiếng, vì vậy chỉ có một liên kết cho tôi). Không phải PEP liên quan trực tiếp đến câu hỏi của bạn, nhưng tôi nghĩ rằng nó hữu ích khi bắt đầu sử dụng Python theo cách Pythonic.

2

Tất nhiên, luôn có namedtuple. Nó rẻ và nhanh, nhưng không thay đổi - bạn phải biết trước tên và giá trị thuộc tính của mình, và bạn không thể thay đổi giá trị của chúng sau này. Nhưng ít nhất nó có cấu trúc thuộc tính struct/object. Và nó sẽ hoạt động với Python 2 và 3

>>> from collections import namedtuple 
>>> Status = namedtuple('Status', 'a b') 
>>> s = Status(a=1, b=2) 
>>> s.a + s.b 
3 
1

Nếu bạn muốn ngữ nghĩa của đối tượng Javascript, bạn có thể xem xét sử dụng namespaces library. Bạn chỉ cần pip install namespaces trước tiên.

>>> import namespaces as ns 
>>> b = ns.Namespace() 
>>> b.foo = 4 
>>> b 
Namespace(foo=4) 

tuyên bố miễn trừ đầy đủ: Tôi là tác giả của thư viện namespaces.

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