2015-05-21 21 views
21

tôi đã thực hiện một chức năng máy phát điện nhỏ cho nhân vật dao động:Làm cách nào để mở rộng, bắt chước hoặc mô phỏng chức năng phạm vi?

>>> def crange(start, end): 
...  for i in range(ord(start), ord(end)+1): 
...    yield chr(i) 
... 

Và sau đó tôi có thể làm điều này:

>>> print(*crange('a','e')) 
a b c d e 

Yay! Nhưng điều này không làm việc:

>>> crange('a','e')[::2] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'generator' object is not subscriptable 

Và làm việc này, nhưng là O (n), không giống như range 's O (1):

>>> 'y' in crange('a','z') 
True 

Điều đó có nghĩa nó mất khoảng 0,35 giây để tìm kiếm cho số ký tự 109,999 trong số tối đa 110.000. 109999 in range(110000), tất nhiên là nhanh.

Tại thời điểm đó, suy nghĩ đầu tiên của tôi chỉ đơn giản là phạm vi phân lớp. Thật không may:

>>> class A(range): 
...  pass 
... 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: type 'range' is not an acceptable base type 

Vì vậy, tôi đoán tôi sẽ phải bắt chước nó trong một cách nào đó cho phép tôi để vượt qua nhân vật như các đối số, hoạt động giống như range nội bộ, và tạo ra các nhân vật. Thật không may, tôi không chắc chắn làm thế nào để tiến hành. Tôi đã thử một dir():

>>> print(*dir(range), sep='\n') 
__class__ 
__contains__ 
__delattr__ 
__dir__ 
__doc__ 
__eq__ 
__format__ 
__ge__ 
__getattribute__ 
__getitem__ 
__gt__ 
__hash__ 
__init__ 
__iter__ 
__le__ 
__len__ 
__lt__ 
__ne__ 
__new__ 
__reduce__ 
__reduce_ex__ 
__repr__ 
__reversed__ 
__setattr__ 
__sizeof__ 
__str__ 
__subclasshook__ 
count 
index 
start 
step 
stop 

cho phép tôi xem những gì các chức năng đang chờ ở đó, nhưng tôi không chắc chắn những gì họ đang làm, hoặc làm thế nào range sử dụng chúng. Tôi tìm kiếm nguồn cho range, nhưng nó trong C, và tôi không biết nơi để tìm wrapper Python của nó (nó có một, phải không?).

Tôi nên đi đâu từ đây và tôi có nên đến đó không?

+0

"nhưng trong C và tôi không biết phải tìm trình bao bọc Python của nó ở đâu (nó có một, đúng không?)" - không. Giống như 'list' hoặc' dict', không có phần nào của 'range' được viết bằng Python. – user2357112

+0

Về lớp học, có lẽ 'lớp A (đối tượng, phạm vi): ' – Zizouz212

+3

Mặc dù điều này có vẻ giống như một câu hỏi thú vị, tôi đang bỏ phiếu để đóng nó quá rộng. Không có cách nào tốt để làm điều này trừ khi đi qua toàn bộ 'phạm vi' của API và sao chép nó, vì vậy các câu trả lời sẽ phải mô tả mọi thứ' phạm vi', tất cả các móc được sử dụng để tùy chỉnh 'len' và cắt và mọi thứ, và chúng 'd mất 10 trang. Tôi khuyên bạn nên googling các tên phương thức và tìm kiếm thông qua [mô hình dữ liệu Python] (https://docs.python.org/3/reference/datamodel.html). – user2357112

Trả lời

9

Để thêm vào câu trả lời của Martin Konecny. Bạn có thể muốn sử dụng một phạm vi nội bộ cho tất cả mọi thứ và chuyển đổi giữa chr và ord.

class crange: 
    def __init__(self, *args, **kwargs): 
     args = [ord(arg) for arg in args] 
     kwargs = {key: ord(val) for key, val in kwargs.items()} 
     self.range = range(*args, **kwargs) 

    def __iter__(self): 
     for n in self.range: 
      yield chr(n) 

    def __contains__(self, c): 
     return ord(c) in self.range 

    def __getitem__(self, i): 
     if isinstance(i, slice): 
      ret = crange('\x00') 
      ret.range = self.range[i] 
      return ret 
     else: 
      return chr(self.range[i]) 

    def __repr__(self): 
     return "crange({}, {})".format(
      repr(chr(self.range.start)), repr(chr(self.range.stop))) 

r = crange('a', 'f') 
print(list(r)) 
print('b' in r) 
print('f' in r) 
print(r[:2]) 

Nói cách khác: nếu chúng tôi không thể phân lớp, chúng tôi có thể sử dụng object composition.

+0

Tôi sắp hỏi xem có nên sử dụng đối tượng 'dải ô' bên trong không ... :) – TigerhawkT3

+1

' self.range .__ chứa __ (ord (c)) '→' ord (c) trong self.range '; 'self.range .__ getitem __ (i)' → 'self.range [i]', '('crange (' + repr (chr (self.range.start)) + ',' + repr (chr (self.range) .stop)) + ')') '→' "crange ({}, {})" định dạng (self.range.start, self.range.stop) '. – Veedrac

+0

Thay đổi được đề xuất được thực hiện, cảm ơn. Bản thân tôi bị mắc kẹt khi sử dụng tên phương thức để đối xứng. repr là một mớ hỗn độn, không có lý do :(. – Ariakenom

17

Tại thời điểm đó, suy nghĩ đầu tiên của tôi chỉ đơn giản là phạm vi phân lớp.

range là một chức năng trong python2 và một lớp "cuối cùng" trong Python3 (more info here) - trong cả hai trường hợp không phải là điều bạn có thể sub-class. Bạn sẽ cần phải tạo một lớp học crange kéo dài từ object làm loại cơ sở.

class crange(object): 

Và làm việc này, nhưng là O (n), không giống như O phạm vi của (1)

Trong Python 3, có một phương pháp __contains__ rằng bạn sẽ xác định cho đối tượng của bạn.

Đối với các đối tượng không xác định __contains__(), kiểm tra thành viên đầu tiên cố gắng lặp qua __iter__(), sau đó giao thức chuỗi lặp cũ qua __getitem__(), xem phần này trong tài liệu tham khảo ngôn ngữ.

Điều này cho phép Python xác định xem giá trị có nằm trong phạm vi của bạn mà không thực sự liệt kê phạm vi.

Ví dụ đơn giản, nếu phạm vi của bạn là 1 đến 1.000.000, thì không đáng kể để xác định xem 23546 có nằm trong phạm vi đó (1 < 23546 < 1000000) hay không.Tất nhiên việc thực hiện thực tế là một chút phức tạp hơn và bổ sung thêm khả năng xử lý từng bước bước, vv

Về:

Yay! Nhưng điều này không hoạt động: >>> crange('a','e')[::2]

Trong trường hợp này, bạn cần xác định __getitem__ trên đối tượng của mình. Dưới đây là ví dụ về một số phương pháp được yêu cầu:

class crange(object): 
    def __init__(self, start, end, step=1): 
     # initialize your range object 
     self.start = start 
     self.end = end 
     self.step = step 

    def __iter__(self): 
     # enable iteration over your object 
     # (assume step size is 1) 
     for i in range(ord(self.start), ord(self.end)+1): 
      yield chr(i) 

    def __getitem__(self, i): 
     # enable accessing items in your range by index 
     # also enable crange('a','e')[::2] 
     # (assuming step size of 1) 
     if isinstance(i, slice): 
      # implement slicing 
     else: 
      return chr(ord(self.start) + i) 

    def __contains__(self, char): 
     # enable O(1) determination of whether a value is in your range 
     # (assume step size is 1) 
     return ord(self.start) <= ord(char) < ord(self.end) 

    def __len__(self): 
     # return length (assuming step size of 1) 
     return ord(self.end) - ord(self.start) 
+0

Nếu tôi nhớ chính xác '__contains __()' được thực hiện trong 'range()' như: 'if step == 1: return start <= num

+1

@ DougR.thx Tôi đã điền vào một số phương pháp và sử dụng phương thức '__contains __()' –

+0

Rất vui được trợ giúp. Xin lỗi, tôi đã mất ba lần để có được toàn bộ điều đúng. Đây là loại vấn đề tôi muốn thấy ở đây trên SO. –

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