2011-07-01 39 views
9

Tôi có một đối tượng cần phải có một số giá trị 4-5 được truyền cho nó. Để minh họa:Khởi tạo các biến đối tượng - một cách tiếp cận Java, một cách tiếp cận Python?

class Swoosh(): 
    spam = '' 
    eggs = '' 
    swallow = '' 
    coconut = '' 

    [... methods ...] 

Ngay bây giờ, cách sử dụng Swoosh là:

swoosh = Swoosh() 
swoosh.set_spam('Spam!') 
swoosh.set_eggs('Eggs!') 
swoosh.set_swallow('Swallow!') 
swoosh.set_coconut('Migrated.') 

Tôi đang gặp sự nghi ngờ cho dù đây là Pythonic hoặc là ảnh hưởng Java quá nhiều này. Hoặc là nó chỉ cần thiết? Ngoài ra, trong trường hợp bạn đang tự hỏi tại sao tôi đang sử dụng setters thay vì chỉ đơn giản là truy cập vào các biến đối tượng - một số xác nhận cơ bản phải được thực hiện ở đó, do đó các phương pháp set_.

Tôi nghĩ tôi có thể cung cấp cách khác để khởi tạo số Swoosh - cung cấp __init__() có thể chấp nhận dict/list?

Dù sao, tôi chỉ đang tìm kiếm trợ giúp/lời khuyên từ một người nào đó có kinh nghiệm hơn về nội dung này.

Cảm ơn trước về bất kỳ đầu vào nào về điều này.

+0

Tại sao nhiều người hiện nay viết 'class SomeThing():' nếu các parens trống phục vụ ab không có mục đích? Hay là quá khó để chèn 'đối tượng' vào giữa những thứ đó? – pillmuncher

Trả lời

15

Trước hết bạn đang sử dụng các lớp kiểu cũ. Bạn thực sự, thực sự nên sử dụng new style classes that inherit from object:

class Swoosh(object): 

Xác định một phương pháp __init__ mà sẽ đưa lập luận chắc chắn là cách Pythonic điều thực hiện:

def __init__(self,spam,eggs,swallow,coconut): 
    self.spam = spam 
    self.eggs = eggs 
    self.swallow = swallow 
    self.coconut = coconut 

Điều này sẽ cho phép bạn làm:

s = Swoosh('Spam!','Eggs','Swallow','Migrated') 

Giống như bất kỳ hàm Python nào khác, phương thức __init__ có thể có defau lt giá trị cho các đối số, ví dụ:

def __init__(self,spam,eggs,swallow,coconut='Migrated.'): 
     self.spam = spam 
     self.eggs = eggs 
     self.swallow = swallow 
     self.coconut = coconut 

Nếu bạn muốn xác thực các thuộc tính khi chúng được đặt, bạn nên sử dụng tiêu chuẩn property attributes thay vì tạo bộ giải mã của riêng bạn. Nếu bạn làm theo cách này, bạn có thể sử dụng myobject.spam trong mã của mình như với thuộc tính thông thường nhưng phương thức setter của bạn vẫn chạy.

Ví dụ:

@property 
def spam(self): 
    """I'm the 'spam' property.""" 
    return self._spam 

@spam.setter 
def spam(self, value): 
    if not value.endswith("!"): 
     raise ValueError("spam must end with !") 
    # Store the value in "private" _spam attribute 
    self._spam = value 

@spam.deleter 
def spam(self): 
    del self._spam 

Lưu ý: property sẽ không hoạt động trừ khi bạn đang sử dụng các lớp học kiểu mới như mô tả ở trên.

Trong ví dụ của bạn, bạn có:

class Swoosh(): 
    spam = '' 
    eggs = '' 
    swallow = '' 
    coconut = '' 

này thường được trình bày như là một cách nhanh chóng để thiết lập giá trị mặc định cho các thuộc tính cho một đối tượng. Nó ổn nhưng bạn cần phải hiểu những gì đang thực sự xảy ra. Điều đang diễn ra là bạn đang đặt thuộc tính trên lớp lớp. Nếu một đối tượng không có thuộc tính Python sẽ xem xét xem nó có được định nghĩa trên lớp không và trả về giá trị từ đó (vì đây là những gì bạn muốn cho các phương thức).

Nếu bạn muốn đặt giá trị mặc định cho thuộc tính đối tượng, bạn nên đặt giá trị mặc định cho đối số trong __init__ như được mô tả ở trên thay vì sử dụng thuộc tính class.

+1

+1 cho các lớp kiểu mới và cảnh báo về lớp so với thuộc tính ví dụ! –

+0

câu trả lời rất hay –

1

Chức năng __init__() là những gì bạn muốn sử dụng để đặt giá trị khi đối tượng được tạo lần đầu tiên.

Ví dụ:

class Swoosh: 
    __init__(self, arg1, arg2, arg3): 
     self.arg1 = arg1 
     self.arg2 = arg2 
     self.arg3 = arg3 
10

Trước hết, điều này:

class Swoosh(): 
    spam = '' 
    eggs = '' 
    swallow = '' 
    coconut = '' 

bộ lớp thuộc tính spam, eggs vv phương pháp set_spam của bạn sau đó sẽ có lẽ đi trước và tạo đối tượng thuộc tính cùng tên mà ẩn các thuộc tính lớp. Nói cách khác, việc xác định các thuộc tính này không có tác dụng và chỉ gây nhầm lẫn mọi thứ.

tôi sẽ làm điều đó như thế này, nếu tất cả các biến là không bắt buộc:

class Swoosh(): 
    def __init__(self, spam="", eggs="", swallow="", coconut=""): 
     self.spam = spam 
     self.eggs = eggs 
     self.swallow = swallow 
     self.coconut = coconut 

Sau đó, bạn có thể tạo các đối tượng như thế này:

o1 = Swoosh(eggs="Eggs!", coconut="Carried by the husk") 

Nếu, ví dụ, thư rác và trứng là bắt buộc, sau đó thay thế bằng

def __init__(self, spam, eggs, swallow="", coconut=""): 

Và không sử dụng định vị và getters. Nếu bạn cần sau này, bạn liên tục có thể thay thế một thuộc tính thường xuyên với một tài sản bằng cách thêm mã như thế này để lớp học của bạn:

def get_spam(self): 
     return self._spam 
    def set_spam(self, value): 
     self._spam = " ".join([str(value)] * 5) 
    spam = property(get_spam, set_spam) 

Với sự thay đổi ở trên, điều này:

o2 = Swoosh(eggs="yes", spam="spam") 
print o2.spam 

in

spam spam spam spam spam 

Lưu ý: Như Dave Webb chỉ ra trong câu trả lời của mình, bạn cần phải phân loại object cho thuộc tính để hoạt động, trừ khi bạn sử dụng py thon 3.0+, trong đó các lớp chữ thường là lớp con object.Oh, và do theo liên kết của Sean Vieira với Python không phải là Java bài viết. Đó là một-phải đọc.

3

Để khởi Swoosh giá trị mà bạn có nhiều lựa chọn:

Thứ nhất, args constructor:

class Swoosh(object): 
    def __init__(self, spam, eggs, swallow, coconut): 
     self.spam = spam 
     self.eggs = eggs 
     self.swallow = swallow 
     self.coconut = coconut 

Và sau đó instanciate obejct của bạn như thế này:

swoosh = Swoosh("spam", "eggs", "swallow", "coconut") 

Nếu bạn cần kiểm soát nhiều hơn trên đường bạn nhận/thiết lập các giá trị, bạn có thể sử dụng phương pháp property.

class Swoosh(): 
    def __init__(self, spam, eggs, swallow, coconut): 
     self.spam = spam 
     self.eggs = eggs 
     self.swallow = swallow 
     self.coconut = coconut 

    def set_spam(self, value): 
    #do verification stuff 
    self._spam = value 

    def get_spam(self): 
    #do what you want/need before get the value 
    return self._spam 

    spam = property(get_spam, set_spam) 

Và sau đó, mọi cuộc gọi như swoosh.spam = spam_value sẽ gọi phương thức set_spam, và foo = swoosh.spam sẽ gọi phương thức get_spam.

4

Xác thực cơ bản có thể được thực hiện bằng cách ghi đè get and set methods on the class thích hợp (nếu việc xác thực cần được thực hiện trong mọi trường hợp) hoặc bằng cách thay đổi thuộc tính cụ thể bằng cách tích hợp sẵn property. Hãy nhớ rằng, Python is not Java (Tất nhiên, Java is not Python, either).

Đối với cách bạn muốn làm tạo lớp học của bạn, bạn có một vài lựa chọn:

1) Sử dụng các phương pháp __init__ với args từ khóa để cho mọi người cung cấp càng nhiều hoặc ít nhất là họ muốn xây dựng của bạn :

class Swoosh(object): # Get new-object goodness 
    def __init__(self, spam='', eggs='', swallow='', coconut=''): 
     # We are going to be using properties in this example 
     self._spam = spam 
     self._eggs = eggs 
     self._swallow = swallow 
     self._coconut = coconut 

2) tiếp tục làm mọi thứ theo cách bạn đang có, nhưng cập nhật các lớp thuộc tính là dụ thuộc tính:

class Swoosh(object): # Get new-object goodness 
    def __init__(self): 
     self.spam = '' 
     self.eggs = '' 
     self.swallow = '' 
     self.coconut = '' 

cách yo bạn đang thực hiện nó, mỗi phiên bản Swoosh chia sẻ cùng giá trị cho các biến này và thay đổi giá trị spam trên Swoosh sẽ thay đổi cho mỗi trường hợp Swoosh chưa thiết lập thuộc tính dụ cùng tên (Có thể không phải là điều bạn muốn.)

Dù bằng cách nào, bạn nên xem xét việc loại bỏ các getters và setters và thay thế chúng bằng các thuộc tính (khi bạn làm điều này tất nhiên sẽ phụ thuộc vào cách công khai và sử dụng rộng rãi API này) :

# Inside class Swoosh's definition 
@property 
def spam(self): 
    return self._spam 
@spam.setter 
def spam(self, value): 
    # Validate that it's really SPAM, not WHAM! 
    # And only then replace the underlying value 
    self._spam = value 
@spam.deleter 
def spam(self): 
    del self._spam 
# Rinse and repeat for other properties that need access control 
+0

+1 cho Python không phải là liên kết Java. Thật tuyệt vời! –

+0

'Cách bạn đang thực hiện nó, mọi phiên bản của Swoosh chia sẻ cùng giá trị cho các biến này, và thay đổi giá trị của thư rác trong một cá thể sẽ thay đổi nó cho mọi trường hợp spam (Có thể không phải là thứ bạn muốn.) 'Đây là sai – Dikei

+0

@Dikei - khá chính xác - được cập nhật để chính xác hơn" thay đổi giá trị của 'spam' trên' Swoosh' sẽ thay đổi nó cho mọi trường hợp 'Swoosh' chưa thiết lập thuộc tính instance với cùng Tên". Cảm ơn vì đã bắt! –

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