2011-01-15 25 views
47

Ví dụ: — nói rằng tôi muốn thêm phương thức helloWorld() vào loại dict của Python. Tôi có thể làm được không?Tôi có thể thêm các phương thức/thuộc tính tùy chỉnh vào các kiểu Python có sẵn không?

JavaScript có đối tượng mẫu thử nghiệm hoạt động theo cách này. Có lẽ đó là thiết kế xấu và tôi nên phân lớp đối tượng dict, nhưng sau đó nó chỉ hoạt động trên các lớp con và tôi muốn nó hoạt động trên bất kỳ và tất cả các từ điển trong tương lai.

Dưới đây là làm thế nào nó sẽ đi xuống trong JavaScript:

String.prototype.hello = function() { 
    alert("Hello, " + this + "!"); 
} 
"Jed".hello() //alerts "Hello, Jed!" 

Dưới đây là một liên kết hữu ích với nhiều ví dụ — http://www.javascriptkit.com/javatutors/proto3.shtml

+0

Bạn cũng có thể thực hiện điều này bằng ruby ​​bằng cách mở lại lớp, ví dụ: class string; def new_method() ...; end; Tôi khá chắc chắn python có một cái gì đó như thế. –

+0

@Abdullah Tôi tin rằng bạn đang đề cập đến khỉ vá, mà chủ yếu là cau mày khi. –

+0

Đúng vậy. Nó được thực hiện tất cả trong Rails. –

Trả lời

53

Bạn không thể trực tiếp thêm phương thức vào loại ban đầu. Tuy nhiên, bạn có thể phân lớp các loại sau đó thay thế nó trong không gian tên được xây dựng trong/toàn cầu, mà đạt được hầu hết các hiệu ứng mong muốn. Thật không may, các đối tượng được tạo bởi cú pháp theo nghĩa đen sẽ tiếp tục là loại vani và sẽ không có các phương thức/thuộc tính mới của bạn.

Đây là những gì nó trông giống như

# Built-in namespace 
import __builtin__ 

# Extended subclass 
class mystr(str): 
    def first_last(self): 
     if self: 
      return self[0] + self[-1] 
     else: 
      return '' 

# Substitute the original str with the subclass on the built-in namespace  
__builtin__.str = mystr 

print str(1234).first_last() 
print str(0).first_last() 
print str('').first_last() 
print '0'.first_last() 

output = """ 
14 
00 

Traceback (most recent call last): 
    File "strp.py", line 16, in <module> 
    print '0'.first_last() 
AttributeError: 'str' object has no attribute 'first_last' 
""" 
+0

Tôi đoán tôi sẽ chỉ phải sử dụng phương pháp ưa thích của phân lớp phụ. Có lẽ tôi sẽ thích nó. – jedmao

+11

Lưu ý: Mô-đun '__builtin__' được đổi tên thành' nội trang 'trong Python3. – changokun

+0

Vâng, tôi gặp phải một vấn đề trong python 2. Sau đó tôi không thể kiểm tra các loại nữa> type ('') == str false <. Khi tôi nhập ("") tôi nhận được , nhưng bằng cách nào đó, so sánh không hoạt động nữa. Trước khi chạy 'dòng __builtin __. Str = mystr' kiểm tra cho loại hoạt động. – Nadu

1

Vâng, bởi subclassing các loại. Xem unifying types and classes in Python.

Không, điều này không có nghĩa là những kẻ giết người thực sự sẽ có loại này, vì điều đó sẽ gây nhầm lẫn. Subclassing một loại nội trang là cách ưa thích để thêm chức năng.

+5

Điều đó sẽ gây nhầm lẫn và rất hữu ích. –

+0

@EvgeniSergeev Tại sao bạn nghĩ nó sẽ rất hữu ích? Tôi chưa bao giờ thực sự hiểu những người mong muốn điều này. Bạn có nghĩ rằng 5 không nên là loại int, hoặc bạn có nghĩ rằng loại int nên được mutable (trong khi 5 chính nó là bất biến)? – Veky

+0

@Veky Tôi muốn 'any_dictionary_instance.len()' hoặc '.size()', ngoài 'any_dictionary_instance có sẵn .__ len __()' và 'len (any_dictionary_instance)' gọi nó. Kích thước ngữ nghĩa là thuộc tính của vùng chứa, vì vậy sẽ thuận tiện hơn khi viết như bạn nói, ví dụ: "lặp lại từ 0 đến kích thước của đối tượng" ... oops, không thể diễn đạt điều đó, ngôn ngữ buộc tôi phải rephrase nó như "iterate from 0 to size of object". Đối với không có gì tốt hơn so với lý do lịch sử, tôi thu thập. –

-1

subclassing là con đường để đi trong Python. Các lập trình viên đa ngôn ngữ học cách sử dụng đúng công cụ cho đúng tình huống - trong lý do. Một cái gì đó được xây dựng một cách nghệ thuật như Rails (một DSL sử dụng Ruby) rất khó thực hiện trong một ngôn ngữ với cú pháp cứng nhắc hơn như Python. Mọi người thường so sánh hai người nói họ giống nhau như thế nào. So sánh là hơi bất công. Python tỏa sáng theo những cách riêng của nó. totochto.

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