2014-09-26 14 views
7

Tôi đã nhìn vào câu trả lời cho câu hỏi này: Is it possible to define a class constant inside an Enum?Python: Constant Lớp

gì quan tâm đến tôi là hầu hết các lớp liên tục trong câu trả lời Ethan Furman của.

class Constant: 
    def __init__(self, value): 
     self.value = value 
    def __get__(self, *args): 
     return self.value 
    def __repr__(self): 
     return '%s(%r)' % (self.__class__.__name__, self.value) 

Câu hỏi là về Python 3.4 nhưng tôi đang sử dụng 2.7. Trong câu trả lời Ethan đặt hằng số hấp dẫn như là một biến thể hiện của Planet lớp như vậy:

G = Constant(6.67300E-11) 

thử nghiệm của tôi về lớp này trong 2,7 cho thấy cách gõ chỉ G mang lại cho tôi điều này:

Out[49]: Constant(3) 

(Tôi đặt nó thành 3 để dễ sử dụng trong khi thử nghiệm.Điều này trông giống như đầu ra __repr__ với tôi, xin vui lòng sửa tôi nếu tôi "sai".

Giá trị có sẵn thông qua G.value. Tuy nhiên, trong câu trả lời của Ethan sử dụng

return self.G * self.mass/(self.radius * self.radius) 

Điều này rõ ràng chỉ hoạt động nếu giá trị được trả về so với đầu ra __repr__. Bây giờ, nếu tôi thay đổi class Constant: thành class Constant(int): thì nhập G Tôi vẫn nhận được kết quả __repr__ nhưng nếu tôi nhập G * 4 Tôi nhận được 12 không phải là lỗi tôi đã nhận được. (TypeError: loại toán hạng không được hỗ trợ (s) cho *: 'instance' và 'int' )

Vì vậy, rõ ràng một cái gì đó giống như đối tượng int có thể xuất ra một số khi được gọi. Có một phương pháp phép thuật nào mà tôi bỏ lỡ, cho phép tôi làm điều này cho lớp Constant không? Vì hằng số có thể là chuỗi, số nguyên hoặc float Tôi muốn có 1 lớp xử lý tất cả chúng so với 3 lớp riêng biệt để mở rộng các đối tượng đó.

Giá trị cũng có thể đặt qua G.value. Tôi có thể khóa cái này xuống để lớp Constant hoạt động như một hằng số thực tế? (Tôi nghi ngờ câu trả lời là không.)

+0

Tại sao bạn muốn nó không đổi? – Veedrac

+0

@Veedrac Tại sao tôi không muốn các hằng số? Hoặc chỉ đọc các giá trị trong một lớp học? Từ việc đọc của tôi trên Python, tôi hiểu rằng nó phản đối triết lý "Chúng ta đều là người lớn đồng ý" của Python. Tôi thực sự thích Python cho đến nay nhưng tôi nghĩ rằng triết lý là một sự giám sát. Tôi lập trình cho tôi, bản thân mình và tôi - không ai khác đọc nó hoặc sử dụng nó. Sau khi viết bằng nhiều ngôn ngữ trong 15 năm qua, tôi đã học được một vài điều. Một trong những điều đó là tôi có thể ngăn chặn những ngày đáng để gỡ lỗi bằng cách đơn giản thiết kế một lớp mà ở đó những thứ nhất định không thể thay đổi bên ngoài nội bộ của lớp đó. –

+0

Tôi đã tự hỏi ở cấp độ nào bạn yêu cầu nó là hằng số; quan điểm của tôi là kiểm tra xem bạn có OK với "liên tục thông qua giao diện công cộng" hay không, đó là cách làm đúng, hoặc bạn thực sự muốn nó là * hoàn toàn * liên tục, điều đó là không thể. – Veedrac

Trả lời

2

Lớp của bạn Hằng số phải kế thừa từ đối tượng, là lớp kiểu Python mới.

Bằng cách đó, Hằng số sẽ được gọi là mô tả. Nói một cách đơn giản, bộ mô tả là một cấu trúc Python để tùy chỉnh hành vi nhận và thiết lập một thuộc tính lớp. Chúng hữu ích khi một cá thể của một bộ mô tả được thiết lập như một thuộc tính của một lớp khác.

Trong ví dụ của bạn Hằng số là bộ mô tả và Hành tinh có thuộc tính là một thể hiện của Hằng số. Khi bạn nhận được thuộc tính G của lớp Planet (self.G trong ví dụ), những gì bạn thực sự nhận được là cái được trả về bởi phương thức __get__ của bộ mô tả, đó là giá trị.

Lưu ý rằng __get__ chỉ được gọi khi cá thể mô tả được truy cập bởi thuộc tính lớp khác.

Vì vậy, xác định các lớp như thế này:

class Constant(object): 
    def __init__(self, value): 
     self.value = value 
    def __get__(self, *args): 
     return self.value 
    def __repr__(self): 
     return '%s(%r)' % (self.__class__.__name__, self.value) 

Sau đó, ví dụ này chút:

c = Constant(3.14) 
print c 

class Test: 
    c = Constant(3.14) 

t = Test() 
print t.c 

Sẽ in:

Constant(3.14) 
3.14 

Thấy rằng khi thể hiện liên tục được in trực tiếp , phương thức __repr__ sẽ được gọi, nhưng khi được in dưới dạng thuộc tính lớp khác, __get__ sẽ được sử dụng.

Bạn có thể đọc thêm về mô tả trên this great article.

+0

Từ những gì tôi đã thử nghiệm nó chỉ hoạt động nếu nó là một biến Class và không phải là một biến Instance. Nếu tôi di chuyển 'c = Hằng số' thành' __init__' qua 'self.c = Hằng số (...)' thì tôi nhận được kết quả '__repr__'. Và nó vẫn có thể ghi được, điều này tốt cho một hằng số vì tôi có thể đặt tên với tất cả các CAPS. Lý tưởng nhất, tôi hy vọng sẽ tìm một cách để tạo một biến thể hiện có thể ghi từ bên trong lớp nhưng không phải là bên ngoài kịch bản '__main__'. Tôi đã có một cái gì đó trong PHP đã làm điều này khá tốt nhưng từ những gì tôi đã đọc cho đến nay nó không phải là có thể bằng Python. Thuộc tính lớp dường như luôn có sẵn để ghi đè. Cám ơn –

0

Vâng, value là người ghi nhớ số class Constant của bạn; vì vậy bạn có thể thử making it private:

class Constant: 
    def __init__(self, value): 
    # This actually transforms the variable to _Constant__value, 
    # but also hides it from outer scope 
    self.__value = value 
    def __get__(self, *args): 
    # Altough the member is theorically renamed as _Constant__value, 
    # it is completely accesible from inside the class as __value 
    reurn self.__value 
    def __repr__(self): 
    return '%s(%r)' % (self.__class__.__name__, self.__value) 

cách tiếp cận khác có thể được sau this recipe.

Hãy thử và cho tôi ngay bây giờ. Hy vọng tôi đã giúp bạn!

+0

Tôi chưa thử công thức nhưng mã bạn đã cung cấp không hoạt động với tôi vì đó là ví dụ riêng của nó. Tôi không thể lấy giá trị trực tiếp được nữa. Tôi nghi ngờ đó là vì những gì @ baxeico nói nơi nó phải trở thành một bộ mô tả trong một lớp học. Thx –

+0

Công thức dường như hoạt động. Tuy nhiên, nó phải nằm trong một tệp và được nhập. Nó cũng có vẻ là một singleton. Việc nhập nó trong một lớp (ngay dưới định nghĩa lớp) không giới hạn nó vào không gian tên của lớp đó. Cũng không đặt dòng nhập trong '__init__'. Công thức làm việc khá độc đáo nếu bạn có thể sống với những hạn chế này. –

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