2010-07-26 20 views
30

JavaScript có đối tượng literals, ví dụ:Là đối tượng literals Pythonic?

var p = { 
    name: "John Smith", 
    age: 23 
} 

và .NET có các loại ẩn danh, ví dụ:

var p = new { Name = "John Smith", Age = 23}; // C# 

Something tương tự có thể được mô phỏng bằng Python bởi (ab) sử dụng đối số tên:

class literal(object): 
    def __init__(self, **kwargs): 
     for (k,v) in kwargs.iteritems(): 
      self.__setattr__(k, v) 
    def __repr__(self): 
     return 'literal(%s)' % ', '.join('%s = %r' % i for i in sorted(self.__dict__.iteritems())) 
    def __str__(self): 
     return repr(self) 

Cách sử dụng:

p = literal(name = "John Smith", age = 23) 
print p  # prints: literal(age = 23, name = 'John Smith') 
print p.name # prints: John Smith 

Nhưng là loại mã này coi là Pythonic?

+1

"pythonic", tôi thích từ này! –

+3

vòng lặp 'for' trong' __init__' của bạn có thể được thay thế bằng 'self .__ dict__ = kw' –

Trả lời

34

Bạn đã cân nhắc sử dụng named tuple?

Sử dụng ký hiệu dict của bạn

>>> from collections import namedtuple 
>>> L = namedtuple('literal', 'name age')(**{'name': 'John Smith', 'age': 23}) 

hoặc đối số từ khóa

>>> L = namedtuple('literal', 'name age')(name='John Smith', age=23) 
>>> L 
literal(name='John Smith', age=23) 
>>> L.name 
'John Smith' 
>>> L.age 
23 

Có thể quấn hành vi này thành một chức năng một cách dễ dàng đủ

def literal(**kw): 
    return namedtuple('literal', kw)(**kw) 

lambda tương đương sẽ là

literal = lambda **kw: namedtuple('literal', kw)(**kw) 

nhưng cá nhân tôi nghĩ rằng nó là tên hiến ngớ ngẩn để "ẩn danh" chức năng

+0

Còn PyRec thì sao? (http://www.valuedlessons.com/2009/10/introducing-pyrec-cure-to-bane-of-init.html) – Plumenator

+0

Có, tôi đã xem bộ tên có tên nhưng không vi phạm DRY nguyên tắc? Việc xây dựng một đối tượng yêu cầu bạn chỉ định tên của mỗi trường hai lần. Tất nhiên, điều này có thể được phá vỡ: literal = lambda ** kwargs: namedtuple ('literal', '' .join (kwargs.keys())) (** kwargs); p = literal (name = 'John Smith', age = 23) (Mã không được kiểm tra, tôi không có Py2.6 trên máy của tôi) – ShinNoNoir

+1

@ShinNoNoir, việc tạo ra một chức năng của nhà máy dễ hơn một chút so với gợi ý của bạn vì 'namedtuple' khá linh hoạt về tham số thứ hai –

59

Tại sao không chỉ sử dụng từ điển?

p = {'name': 'John Smith', 'age': 23} 

print p 
print p['name'] 
print p['age'] 
+8

Bạn cũng có thể sử dụng chức năng' dict': 'p = dict (tên = 'John Smith', tuổi = 23)' –

+0

Vâng, vâng, dicts ít nhiều tương đương. Ngoài ra, đề nghị của Tomasz là một cách thay thế tốt đẹp để xây dựng chúng. Tuy nhiên, truy cập vào 'các trường' của một dict không đẹp như trong ví dụ mã của tôi, mặc dù nó chỉ là một sự bất tiện cú pháp nhỏ. – ShinNoNoir

+2

Trong khi tôi đồng tình, tôi nghĩ có một sự khác biệt về triết học trong công việc. Triết lý hiện hành trong Python là nếu bạn cần một đối tượng với các thành viên '.name' và' .age', bạn nên tạo đối tượng đó một cách rõ ràng, với tất cả các hàm tạo của nó, v.v. –

7

Từ ActiveState:

class Bunch: 
    def __init__(self, **kwds): 
     self.__dict__.update(kwds) 

# that's it! Now, you can create a Bunch 
# whenever you want to group a few variables: 

point = Bunch(datum=y, squared=y*y, coord=x) 

# and of course you can read/write the named 
# attributes you just created, add others, del 
# some of them, etc, etc: 
if point.squared > threshold: 
    point.isok = 1 
2

Từ Python IAQ:

Tính đến Python 2.3 bạn có thể sử dụng cú pháp

dict(a=1, b=2, c=3, dee=4) 

đủ tốt cho đến mức tôi quan tâm. Khi Python 2.3 tôi đã sử dụng một dòng chức năng

def Dict(**dict): return dict 
1

Tôi nghĩ rằng đối tượng trực có ý nghĩa trong JavaScript vì hai lý do:

  1. Ở JavaScript, các đối tượng là cách duy nhất để tạo ra một “điều ”Với các thuộc tính chỉ mục chuỗi. Trong Python, như đã lưu ý trong câu trả lời khác, kiểu từ điển thực hiện điều đó.

  2. Hệ thống đối tượng của JavaScript dựa trên nguyên mẫu. Không có thứ gì như một lớp trong JavaScript (mặc dù nó đang đến trong một phiên bản tương lai) - các đối tượng có các đối tượng nguyên mẫu thay vì các lớp. Do đó, việc tạo một đối tượng “từ không có gì” là tự nhiên, thông qua một chữ, bởi vì tất cả các đối tượng chỉ yêu cầu đối tượng gốc dựng sẵn làm nguyên mẫu.Trong Python, mọi đối tượng đều có một lớp - bạn sắp được dự kiến ​​sẽ sử dụng các đối tượng cho những thứ mà bạn có nhiều phiên bản, thay vì chỉ cho một lần.

Vì vậy, không có, đối tượng literals không phải là Pythonic, nhưng chúng là JavaScripthonic.

+0

Javascriptonic, có thể? :-) – Plumenator

+3

Không, đó là một loại soda thường trộn lẫn với DOM Gin. –

+2

Tôi không đồng ý - trong JavaScript thực sự chỉ có một cách để tạo đối tượng giống như dict, nhưng nó có thể được truy cập theo nhiều cách - thông qua các cú pháp 'obj.prop' và' obj ["prop"] '- đó là khá ý tưởng hay, có thể được thực hiện bằng Python nếu bạn muốn (câu trả lời Unode dưới đây). Ngoài ra - các lớp cũng là các đối tượng (bằng Python), vì vậy việc sử dụng chúng như các thùng chứa một lần cho các thuộc tính có thể hữu ích theo thời gian (khi giao dịch với các API muốn thực hiện '__getattr__' khi truyền một cái gì đó). – cji

2

Tôi không thấy điều gì sai khi tạo các lớp/phiên bản "ẩn danh". Nó thường rất thuận tiện để tạo một cái với chức năng gọi đơn giản trong một dòng mã. Cá nhân tôi sử dụng một cái gì đó như thế này:

def make_class(*args, **attributes): 
    """With fixed inability of using 'name' and 'bases' attributes ;)""" 
    if len(args) == 2: 
     name, bases = args 
    elif len(args) == 1: 
     name, bases = args[0], (object,) 
    elif not args: 
     name, bases = "AnonymousClass", (object,) 
    return type(name, bases, attributes) 

obj = make_class(something = "some value")() 
print obj.something 

Để tạo các đối tượng giả hoạt động tốt. Namedtuple là ok, nhưng không thay đổi, đôi khi có thể bất tiện. Và từ điển là ... tốt, một từ điển, nhưng có những tình huống khi bạn phải vượt qua một cái gì đó với __getattr__ được xác định, thay vì __getitem__.

Tôi không biết liệu đó có phải là pythonic hay không, nhưng đôi khi nó tăng tốc mọi thứ và với tôi đó là lý do đủ tốt để sử dụng nó (đôi khi).

+0

Cách tiếp cận thú vị, ngoại trừ 'make_class' thực sự đang xây dựng một đối tượng. Ngoài ra còn có vấn đề mà bạn không thể có một thuộc tính được gọi là 'tên' với cách tiếp cận của bạn. (Nhưng tôi nhận thấy tôi có một vấn đề tương tự trong lớp 'literal' của tôi ... Tôi không thể có một thuộc tính được gọi là' self'). – ShinNoNoir

+2

Thực ra nó là 'đối tượng lớp' - nó được khởi tạo ở đây: 'make_class (...)()'. Tôi nghĩ? Và đối với các xung đột tên - Đúng vậy. – cji

1

Một từ điển đơn giản là đủ cho hầu hết các trường hợp.

Nếu bạn đang tìm kiếm một API tương tự như bạn đã chỉ rõ đối với trường hợp theo nghĩa đen, bạn vẫn có thể sử dụng từ điển và đơn giản là ghi đè lên đặc biệt __getattr__ chức năng:

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

p = CustomDict(user='James', location='Earth') 
print p.user 
print p.location 

Note: Cũng nên lưu ý ngược lại với các tên đã đặt tên, các trường không được xác thực và bạn chịu trách nhiệm đảm bảo các đối số của bạn là lành mạnh. Các đối số như p['def'] = 'something' được dung thứ trong từ điển nhưng bạn sẽ không thể truy cập chúng thông qua p.def.

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