2015-05-27 12 views
12

Tôi biết việc tạo phương thức tùy chỉnh __repr__ hoặc __add__ (v.v.), để sửa đổi hành vi của các toán tử và chức năng. Có ghi đè phương pháp cho len không?Có thể sửa đổi hành vi của len() không?

Ví dụ:

class Foo: 
    def __repr__(self): 
     return "A wild Foo Class in its natural habitat." 

foo = Foo() 

print(foo)   # A wild Foo Class in its natural habitat. 
print(repr(foo)) # A wild Foo Class in its natural habitat. 

này có thể được thực hiện cho len, với một danh sách? Thông thường, nó sẽ trông như sau:

foo = [] 
print(len(foo)) # 0 

foo = [1, 2, 3] 
print(len(foo)) # 3 

Nếu tôi muốn loại bỏ các loại tìm kiếm thì sao? Như thế này:

class Bar(list): 
    pass 

foo = [Bar(), 1, ''] 
print(len(foo)) # 3 

count = 0 
for item in foo: 
    if not isinstance(item, Bar): 
     count += 1 

print(count)  # 2 

Có cách nào để thực hiện việc này từ trong lớp con list không?

+3

Bạn đã có câu trả lời tốt, nhưng trong trường hợp bạn muốn tìm hiểu thêm về phương pháp kỳ diệu Tôi có thể đề nghị [Hướng dẫn phương pháp kỳ diệu của Python] (http: // www. rafekettler.com/magicmethods.html);) – swenzel

+0

Điều này sẽ có ích một chút! Cám ơn vì đã chia sẻ. @swenzel –

+0

Bạn có một lớp con danh sách, không phải là một siêu lớp danh sách. – wim

Trả lời

19

Vâng, thực hiện __len__ method: Demo

def __len__(self): 
    return 42 

:

>>> class Foo(object): 
...  def __len__(self): 
...   return 42 
... 
>>> len(Foo()) 
42 

Từ các tài liệu:

gọi để thực hiện tích hợp chức năng len(). Nên trả về độ dài của đối tượng, một số nguyên >= 0. Ngoài ra, một đối tượng không xác định phương thức __bool__() và phương thức __len__() trả về số không được coi là sai trong ngữ cảnh Boolean.

Đối với trường hợp cụ thể của bạn:

>>> class Bar(list): 
...  def __len__(self): 
...   return sum(1 for ob in self if not isinstance(ob, Bar)) 
... 
>>> len(Bar([1, 2, 3])) 
3 
>>> len(Bar([1, 2, 3, Bar()])) 
3 
+0

Liệu 'tổng hợp (không phải là sự phục hồi (ob, Bar) cho ob trong tự)' là một chút sạch hơn? – TigerhawkT3

+0

@ TigerhawkT3: lúc này bạn phải giải thích rằng kiểu boolean của Python là một lớp con của int và 'True' có giá trị nguyên là 1 và' False' là giá trị 0. Không phải lúc nào cũng có giá trị ít hơn một chút khi bạn phải giải thích rằng mỗi lần duy nhất. –

+0

Rất đúng; Tôi đã không nghĩ về nó theo cách đó. – TigerhawkT3

7

Vâng, cũng giống như bạn đã phát hiện ra rằng bạn có thể ghi đè lên hành vi của một cuộc gọi repr() chức năng bằng cách thực hiện các __repr__ magic method, bạn có thể chỉ định các hành vi từ một cuộc gọi len() chức năng bằng cách thực hiện (ngạc nhiên ngạc nhiên) sau đó __len__ kỳ diệu:

>>> class Thing: 
...  def __len__(self): 
...   return 123 
...  
>>> len(Thing()) 
123 

một pedant có thể đề cập rằng bạn không sửa đổi hành vi của len(), bạn đang sửa đổi hành vi của lớp học. len cũng thực hiện điều tương tự, bao gồm việc kiểm tra thuộc tính __len__ trên đối số.

3

Bạn chỉ có thể thêm phương thức __len__ vào lớp học của mình.

class Test: 
    def __len__(self): 
     return 2 

a=Test() 
len(a) # --> 2 
5

Ghi nhớ: Python là ngôn ngữ động và Duck Typed.

Nếu nó hoạt động như một thứ gì đó có thể có độ dài;

class MyCollection(object): 

    def __len__(self): 
     return 1234 

Ví dụ:

>>> obj = MyCollection() 
>>> len(obj) 
1234 

nếu nó không hành động như nó có một chiều dài;KABOOM!

class Foo(object): 

    def __repr___(self): 
     return "<Foo>" 

Ví dụ:

>>> try: 
...  obj = Foo() 
...  len(obj) 
... except: 
...  raise 
... 
Traceback (most recent call last): 
    File "<stdin>", line 3, in <module> 
TypeError: object of type 'Foo' has no len() 

Từ Typing:

Python sử dụng gõ vịt và đã gõ đối tượng nhưng không định kiểu biến tên. Loại ràng buộc không được kiểm tra tại thời gian biên dịch; thay vào đó, các hoạt động trên một đối tượng có thể không thành công, biểu thị rằng đối tượng đã cho là không phải là loại phù hợp. Mặc dù được nhập động, nhưng Python được đánh máy mạnh mẽ, cấm hoạt động không được xác định rõ ràng (ví dụ , thêm số vào chuỗi) thay vì âm thầm cố gắng để hiểu chúng.

Ví dụ:

>>> x = 1234 
>>> s = "1234" 
>>> x + s 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unsupported operand type(s) for +: 'int' and 'str' 
Các vấn đề liên quan