Sử dụng thuộc tính () trên classmethods


173

Tôi có một lớp với hai phương thức lớp (sử dụng hàm classmethod ()) để nhận và thiết lập những gì thực chất là một biến tĩnh. Tôi đã cố gắng sử dụng hàm property () với những cái này, nhưng nó dẫn đến một lỗi. Tôi đã có thể tái tạo lỗi với phần sau trong trình thông dịch:

class Foo(object):
    _var = 5
    @classmethod
    def getvar(cls):
        return cls._var
    @classmethod
    def setvar(cls, value):
        cls._var = value
    var = property(getvar, setvar)

Tôi có thể chứng minh các phương thức lớp, nhưng chúng không hoạt động như các thuộc tính:

>>> f = Foo()
>>> f.getvar()
5
>>> f.setvar(4)
>>> f.getvar()
4
>>> f.var
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
>>> f.var=5
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable

Có thể sử dụng hàm property () với các hàm trang trí classmethod không?

Câu trả lời:


90

Một thuộc tính được tạo trên một lớp nhưng ảnh hưởng đến một thể hiện. Vì vậy, nếu bạn muốn một thuộc tính classmethod, hãy tạo thuộc tính trên metaclass.

>>> class foo(object):
...     _var = 5
...     class __metaclass__(type):  # Python 2 syntax for metaclasses
...         pass
...     @classmethod
...     def getvar(cls):
...         return cls._var
...     @classmethod
...     def setvar(cls, value):
...         cls._var = value
...     
>>> foo.__metaclass__.var = property(foo.getvar.im_func, foo.setvar.im_func)
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

Nhưng vì dù sao bạn cũng đang sử dụng siêu dữ liệu, nó sẽ đọc tốt hơn nếu bạn chỉ di chuyển các lớp đối xứng trong đó.

>>> class foo(object):
...     _var = 5
...     class __metaclass__(type):  # Python 2 syntax for metaclasses
...         @property
...         def var(cls):
...             return cls._var
...         @var.setter
...         def var(cls, value):
...             cls._var = value
... 
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

hoặc, sử dụng metaclass=...cú pháp của Python 3 và siêu dữ liệu được xác định bên ngoài foothân lớp và siêu dữ liệu chịu trách nhiệm đặt giá trị ban đầu là _var:

>>> class foo_meta(type):
...     def __init__(cls, *args, **kwargs):
...         cls._var = 5
...     @property
...     def var(cls):
...         return cls._var
...     @var.setter
...     def var(cls, value):
...         cls._var = value
...
>>> class foo(metaclass=foo_meta):
...     pass
...
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

1
Điều này dường như không hoạt động với tôi trong Python 3.2. Nếu tôi thay đổi foo .__ metaclass __. Var = property (foo.getvar.im_func, foo.setvar.im_func) thành foo .__ metaclass __. Var = property (foo.getvar .__ func__, foo.setvar .__ func đối tượng 'foo' không có thuộc tính 'var' "khi thực hiện" foo.var ".
Michael Kelley

Hiệu chỉnh kép SIGH : điều này hoạt động trong Python 2.7, nhưng không phải Python 3.2.
Michael Kelley

@MichaelKelley - Đó là vì cú pháp của siêu dữ liệu đã thay đổi trong Python 3.x
mac

1
Tôi không chắc chắn để hiểu, cách Python 3.x để viết cái này là gì?
SylvainD

8
@Josay: Trước tiên, bạn cần xác định siêu dữ liệu, sau đó xác định lớp bằng class Foo(metaclass=...)cú pháp mới .
Kevin

69

Đọc ghi chú phát hành Python 2.2 , tôi thấy như sau.

Phương thức get [của một thuộc tính] sẽ không được gọi khi thuộc tính được truy cập dưới dạng một thuộc tính lớp (Cx) thay vì như một thuộc tính thể hiện (C (). X). Nếu bạn muốn ghi đè hoạt động __get__ cho các thuộc tính khi được sử dụng làm thuộc tính lớp, bạn có thể phân lớp thuộc tính - đó là kiểu kiểu mới - để mở rộng phương thức __get__ của nó hoặc bạn có thể xác định loại mô tả từ đầu bằng cách tạo mới lớp kiểu định nghĩa các phương thức __get__, __set__ và __delete__.

LƯU Ý: Phương pháp dưới đây không thực sự hoạt động đối với setters, chỉ getters.

Do đó, tôi tin rằng giải pháp được quy định là tạo ClassProperty dưới dạng một lớp con của thuộc tính.

class ClassProperty(property):
    def __get__(self, cls, owner):
        return self.fget.__get__(None, owner)()

class foo(object):
    _var=5
    def getvar(cls):
        return cls._var
    getvar=classmethod(getvar)
    def setvar(cls,value):
        cls._var=value
    setvar=classmethod(setvar)
    var=ClassProperty(getvar,setvar)

assert foo.getvar() == 5
foo.setvar(4)
assert foo.getvar() == 4
assert foo.var == 4
foo.var = 3
assert foo.var == 3

Tuy nhiên, các setters không thực sự hoạt động:

foo.var = 4
assert foo.var == foo._var # raises AssertionError

foo._var là không thay đổi, bạn chỉ đơn giản ghi đè lên tài sản với một giá trị mới.

Bạn cũng có thể sử dụng ClassPropertynhư một trang trí:

class foo(object):
    _var = 5

    @ClassProperty
    @classmethod
    def var(cls):
        return cls._var

    @var.setter
    @classmethod
    def var(cls, value):
        cls._var = value

assert foo.var == 5

20
Tôi không nghĩ phần setter của ClassProperty thực sự hoạt động như mô tả: trong khi các xác nhận của ví dụ đều vượt qua, ở cuối foo._var == 4 (không phải 3, như ngụ ý). Thiết lập tài sản ghi đè chính tài sản đó. Khi các thuộc tính lớp được thảo luận trên python-dev, nó đã chỉ ra rằng, trong khi các getters là tầm thường, thì setters rất khó (không thể?) Nếu không có siêu dữ liệu
Gabriel Grant

4
@Gabriel Hoàn toàn chính xác. Tôi không thể tin rằng không ai chỉ ra điều đó trong hai năm.
agf

Tôi cũng không chắc tại sao bạn không chỉ sử dụng self.fget(owner)và loại bỏ nhu cầu phải sử dụng @classmethodtất cả ở đây? (đó là những gì classmethod không , dịch .__get__(instance, owner)(*args, **kwargs)sang function(owner, *args, **kwargs)các cuộc gọi, thông qua một trung gian; các thuộc tính không cần trung gian).
Martijn Pieters

Trình diễn của bạn đang thiếu bất kỳ chuyển đổi thực tế nào trong getter hoặc setter sẽ chứng minh gọn gàng rằng foo.var = 3bài tập của bạn không thực sự đi qua thuộc tính , và thay vào đó chỉ đơn giản là thay thế đối tượng thuộc tính foobằng một số nguyên. Nếu bạn đã thêm assert isinstance(foo.__dict__['var'], ClassProperty)các cuộc gọi giữa các xác nhận của mình, bạn sẽ thấy thất bại sau khi foo.var = 3được thực thi.
Martijn Pieters

1
Lớp học Python không mô tả hỗ trợ ràng buộc về thiết trên lớp bản thân , chỉ có trên nhận được (do đó instance.attr, instance.attr = valuedel instance.attrtất cả các ràng buộc mô tả sẽ được tìm thấy trên type(instance), nhưng trong khi classobj.attrvới phím tắt, classobj.attr = valuedel classobj.attrlàm không và thay vào đó thay thế hoặc xóa các đối tượng mô tả chính nó). Bạn cần một siêu dữ liệu để hỗ trợ cài đặt và xóa (làm cho đối tượng lớp trở thành thể hiện và siêu dữ liệu là loại).
Martijn Pieters

56

Tôi hy vọng người @classpropertytrang trí chỉ đọc đơn giản đã chết này sẽ giúp ai đó tìm kiếm các sản phẩm đẳng cấp.

class classproperty(object):

    def __init__(self, fget):
        self.fget = fget

    def __get__(self, owner_self, owner_cls):
        return self.fget(owner_cls)

class C(object):

    @classproperty
    def x(cls):
        return 1

assert C.x == 1
assert C().x == 1

2
Điều này có làm việc với các lớp con? (một lớp con có thể ghi đè lên các lớp học không?)
zakdances

1
Ừ có class D(C): x = 2; assert D.x == 2
dtheodor

Tôi ước điều này hoạt động khi tôi sử dụng nó .formatnhư "{x}".format(**dict(self.__class__.__dict__, **self.__dict__)):(
2rs2ts

@Nathan Không chỉ ... khi bạn đặt nó, bạn còn ghi đè tất cả xquyền truy cập 10. Tôi thích cách tiếp cận này vì gọn gàng và đơn giản nhưng nghe giống như một antipotype
Michele Keyboardmico

Dễ dàng sửa chữa: thêm một __set__cái tăng lên ValueErrorđể ngăn chặn ghi đè.
Kiran Jonnalagadda

30

Có thể sử dụng hàm property () với các hàm trang trí classmethod không?

Không.

Tuy nhiên, một classmethod chỉ đơn giản là một phương thức ràng buộc (một hàm một phần) trên một lớp có thể truy cập được từ các thể hiện của lớp đó.

Vì cá thể là một chức năng của lớp và bạn có thể lấy được lớp từ cá thể đó, nên bạn có thể nhận bất kỳ hành vi mong muốn nào bạn có thể muốn từ một thuộc tính lớp với property:

class Example(object):
    _class_property = None
    @property
    def class_property(self):
        return self._class_property
    @class_property.setter
    def class_property(self, value):
        type(self)._class_property = value
    @class_property.deleter
    def class_property(self):
        del type(self)._class_property

Mã này có thể được sử dụng để kiểm tra - nó sẽ vượt qua mà không gây ra bất kỳ lỗi nào:

ex1 = Example()
ex2 = Example()
ex1.class_property = None
ex2.class_property = 'Example'
assert ex1.class_property is ex2.class_property
del ex2.class_property
assert not hasattr(ex1, 'class_property')

Và lưu ý rằng chúng tôi hoàn toàn không cần siêu dữ liệu - và bạn không truy cập trực tiếp vào siêu dữ liệu thông qua các trường hợp của lớp.

viết một @classpropertytrang trí

Bạn thực sự có thể tạo một trình classpropertytrang trí chỉ trong một vài dòng mã bằng cách phân lớp property(nó được triển khai trong C, nhưng bạn có thể thấy Python tương đương ở đây ):

class classproperty(property):
    def __get__(self, obj, objtype=None):
        return super(classproperty, self).__get__(objtype)
    def __set__(self, obj, value):
        super(classproperty, self).__set__(type(obj), value)
    def __delete__(self, obj):
        super(classproperty, self).__delete__(type(obj))

Sau đó đối xử với trình trang trí như thể nó là một phân loại kết hợp với thuộc tính:

class Foo(object):
    _bar = 5
    @classproperty
    def bar(cls):
        """this is the bar attribute - each subclass of Foo gets its own.
        Lookups should follow the method resolution order.
        """
        return cls._bar
    @bar.setter
    def bar(cls, value):
        cls._bar = value
    @bar.deleter
    def bar(cls):
        del cls._bar

Và mã này sẽ hoạt động mà không có lỗi:

def main():
    f = Foo()
    print(f.bar)
    f.bar = 4
    print(f.bar)
    del f.bar
    try:
        f.bar
    except AttributeError:
        pass
    else:
        raise RuntimeError('f.bar must have worked - inconceivable!')
    help(f)  # includes the Foo.bar help.
    f.bar = 5

    class Bar(Foo):
        "a subclass of Foo, nothing more"
    help(Bar) # includes the Foo.bar help!
    b = Bar()
    b.bar = 'baz'
    print(b.bar) # prints baz
    del b.bar
    print(b.bar) # prints 5 - looked up from Foo!

    
if __name__ == '__main__':
    main()

Nhưng tôi không chắc điều này sẽ được khuyên như thế nào. Một bài viết danh sách gửi thư cũ cho thấy nó không nên làm việc.

Bắt tài sản để làm việc trên lớp:

Nhược điểm ở trên là "thuộc tính lớp" không thể truy cập được từ lớp, bởi vì nó chỉ đơn giản sẽ ghi đè lên bộ mô tả dữ liệu từ lớp __dict__.

Tuy nhiên, chúng ta có thể ghi đè lên điều này bằng một thuộc tính được xác định trong siêu dữ liệu __dict__. Ví dụ:

class MetaWithFooClassProperty(type):
    @property
    def foo(cls):
        """The foo property is a function of the class -
        in this case, the trivial case of the identity function.
        """
        return cls

Và sau đó, một thể hiện của lớp siêu dữ liệu có thể có một thuộc tính truy cập vào thuộc tính của lớp bằng cách sử dụng nguyên tắc đã được trình bày trong các phần trước:

class FooClassProperty(metaclass=MetaWithFooClassProperty):
    @property
    def foo(self):
        """access the class's property"""
        return type(self).foo

Và bây giờ chúng ta thấy cả hai ví dụ

>>> FooClassProperty().foo
<class '__main__.FooClassProperty'>

và lớp học

>>> FooClassProperty.foo
<class '__main__.FooClassProperty'>

có quyền truy cập vào tài sản lớp.


3
Rõ ràng, súc tích, kỹ lưỡng: đây phải là câu trả lời được chấp nhận.
pfabri

25

Con trăn 3!

Câu hỏi cũ, rất nhiều lượt xem, rất cần một cách 3 Python đúng.

May mắn thay, thật dễ dàng với metaclasskwarg:

class FooProperties(type):

    @property
    def var(cls):
        return cls._var

class Foo(object, metaclass=FooProperties):
    _var = 'FOO!'

Sau đó, >>> Foo.var

'THỰC SỰ!'


1
điều đó có nghĩa là không có cách nào đơn giản để thoát khỏi hộp
mehmet

@mehmet Cái này có đơn giản không? Foolà một thể hiện của siêu dữ liệu của nó và @propertycó thể được sử dụng cho các phương thức của nó giống như các phương thức của nó Foo.
OJFord

2
bạn phải định nghĩa một lớp khác cho một lớp, đó là gấp đôi độ phức tạp giả sử siêu dữ liệu không thể sử dụng lại được.
mehmet

Một classmethod hoạt động từ cả lớp và thể hiện. Khách sạn này chỉ hoạt động từ các lớp. Tôi không nghĩ rằng đây là những gì đang được yêu cầu.
Aaron Hall

1
@AaronHall Nếu điều đó quan trọng, nó dễ dàng được thêm vào Foo.__new__. Mặc dù tại thời điểm đó, có thể đáng để sử dụng getattribution thay vào đó, hoặc đặt câu hỏi nếu giả vờ một tính năng ngôn ngữ có thực sự là cách tiếp cận bạn muốn thực hiện hay không.
OJFord

16

Không có cách hợp lý để làm cho hệ thống "thuộc tính lớp" này hoạt động trong Python.

Đây là một cách không hợp lý để làm cho nó hoạt động. Bạn chắc chắn có thể làm cho nó liền mạch hơn với số lượng ma thuật siêu dữ liệu ngày càng tăng.

class ClassProperty(object):
    def __init__(self, getter, setter):
        self.getter = getter
        self.setter = setter
    def __get__(self, cls, owner):
        return getattr(cls, self.getter)()
    def __set__(self, cls, value):
        getattr(cls, self.setter)(value)

class MetaFoo(type):
    var = ClassProperty('getvar', 'setvar')

class Foo(object):
    __metaclass__ = MetaFoo
    _var = 5
    @classmethod
    def getvar(cls):
        print "Getting var =", cls._var
        return cls._var
    @classmethod
    def setvar(cls, value):
        print "Setting var =", value
        cls._var = value

x = Foo.var
print "Foo.var = ", x
Foo.var = 42
x = Foo.var
print "Foo.var = ", x

Nút thắt của vấn đề là các thuộc tính là cái mà Python gọi là "mô tả". Không có cách nào ngắn gọn và dễ dàng để giải thích cách thức hoạt động của siêu lập trình này, vì vậy tôi phải chỉ cho bạn cách mô tả .

Bạn chỉ cần hiểu những thứ này nếu bạn đang thực hiện một khung khá tiên tiến. Giống như một hệ thống RPC hoặc hệ thống RPC trong suốt, hoặc một loại ngôn ngữ dành riêng cho miền.

Tuy nhiên, trong một bình luận cho câu trả lời trước đó, bạn nói rằng bạn

cần sửa đổi một thuộc tính theo cách mà tất cả các thể hiện của một lớp nhìn thấy và trong phạm vi mà các phương thức lớp này được gọi không có tham chiếu đến tất cả các thể hiện của lớp.

Dường như với tôi, những gì bạn thực sự muốn là một mẫu thiết kế Observer .


Tôi thích ý tưởng về ví dụ mã, nhưng có vẻ như nó sẽ hơi lộn xộn trong thực tế.
Mark Roddy

Những gì tôi đang cố gắng thực hiện là cài đặt khá đơn giản và nhận được một thuộc tính duy nhất được sử dụng làm cờ để sửa đổi hành vi của tất cả các trường hợp, vì vậy tôi nghĩ rằng Observer sẽ bị thổi phồng cho những gì tôi đang cố gắng thực hiện. Nếu có nhiều thuộc tính trong câu hỏi thì tôi sẽ nghiêng nhiều hơn.
Mark Roddy

Dường như chỉ cần làm cho các chức năng công khai và gọi chúng trực tiếp là giải pháp đơn giản. Tôi tò mò nếu tôi làm điều gì sai hoặc nếu tôi đang cố gắng làm là không thể. Xin lỗi về nhiều ý kiến ​​bằng cách này. Giới hạn hút 300 ký tự.
Mark Roddy

Điều tiện lợi về ví dụ mã là bạn có thể thực hiện tất cả các bit vụng về một lần và sau đó kế thừa chúng. Chỉ cần di chuyển _var vào lớp dẫn xuất. lớp D1 (Foo): _var = 21 lớp D2 (Foo) _var = "Xin chào" D1.var 21 D2.var Xin chào
Thomas L Holaday

6

Chỉ thiết lập nó trên lớp meta không giúp ích gì nếu bạn muốn truy cập thuộc tính lớp thông qua một đối tượng được khởi tạo, trong trường hợp này bạn cũng cần cài đặt một thuộc tính bình thường trên đối tượng (gửi đến thuộc tính lớp). Tôi nghĩ sau đây là một chút rõ ràng hơn:

#!/usr/bin/python

class classproperty(property):
    def __get__(self, obj, type_):
        return self.fget.__get__(None, type_)()

    def __set__(self, obj, value):
        cls = type(obj)
        return self.fset.__get__(None, cls)(value)

class A (object):

    _foo = 1

    @classproperty
    @classmethod
    def foo(cls):
        return cls._foo

    @foo.setter
    @classmethod
    def foo(cls, value):
        cls.foo = value

a = A()

print a.foo

b = A()

print b.foo

b.foo = 5

print a.foo

A.foo = 10

print b.foo

print A.foo

3

Một nửa giải pháp, __set__ trên lớp không hoạt động, vẫn còn. Giải pháp là một lớp thuộc tính tùy chỉnh thực hiện cả thuộc tính và tĩnh.

class ClassProperty(object):
    def __init__(self, fget, fset):
        self.fget = fget
        self.fset = fset

    def __get__(self, instance, owner):
        return self.fget()

    def __set__(self, instance, value):
        self.fset(value)

class Foo(object):
    _bar = 1
    def get_bar():
        print 'getting'
        return Foo._bar

    def set_bar(value):
        print 'setting'
        Foo._bar = value

    bar = ClassProperty(get_bar, set_bar)

f = Foo()
#__get__ works
f.bar
Foo.bar

f.bar = 2
Foo.bar = 3 #__set__ does not

3

Bởi vì tôi cần sửa đổi một thuộc tính theo cách mà tất cả các thể hiện của một lớp nhìn thấy và trong phạm vi mà các phương thức lớp này được gọi không có tham chiếu đến tất cả các thể hiện của lớp.

Bạn có quyền truy cập vào ít nhất một thể hiện của lớp không? Tôi có thể nghĩ ra một cách để làm điều đó sau đó:

class MyClass (object):
    __var = None

    def _set_var (self, value):
        type (self).__var = value

    def _get_var (self):
        return self.__var

    var = property (_get_var, _set_var)

a = MyClass ()
b = MyClass ()
a.var = "foo"
print b.var

2

Hãy thử xem, nó hoàn thành công việc mà không phải thay đổi / thêm nhiều mã hiện có.

>>> class foo(object):
...     _var = 5
...     def getvar(cls):
...         return cls._var
...     getvar = classmethod(getvar)
...     def setvar(cls, value):
...         cls._var = value
...     setvar = classmethod(setvar)
...     var = property(lambda self: self.getvar(), lambda self, val: self.setvar(val))
...
>>> f = foo()
>>> f.var
5
>>> f.var = 3
>>> f.var
3

Các propertychức năng cần hai callableđối số. cung cấp cho họ các hàm bao lambda (mà nó vượt qua thể hiện như là đối số đầu tiên của nó) và tất cả đều tốt.


Như Florian Bösch chỉ ra, cú pháp cần thiết (bởi các thư viện bên thứ ba hoặc mã kế thừa) là foo.var.
Thomas L Holaday

2

Đây là một giải pháp nên hoạt động cho cả truy cập thông qua lớp và truy cập thông qua một cá thể sử dụng siêu dữ liệu.

In [1]: class ClassPropertyMeta(type):
   ...:     @property
   ...:     def prop(cls):
   ...:         return cls._prop
   ...:     def __new__(cls, name, parents, dct):
   ...:         # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
   ...:         dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
   ...:         dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
   ...:         return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)
   ...:

In [2]: class ClassProperty(object):
   ...:     __metaclass__ = ClassPropertyMeta
   ...:     _prop = 42
   ...:     def __getattr__(self, attr):
   ...:         raise Exception('Never gets called')
   ...:

In [3]: ClassProperty.prop
Out[3]: 42

In [4]: ClassProperty.prop = 1
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-e2e8b423818a> in <module>()
----> 1 ClassProperty.prop = 1

AttributeError: can't set attribute

In [5]: cp = ClassProperty()

In [6]: cp.prop
Out[6]: 42

In [7]: cp.prop = 1
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-7-e8284a3ee950> in <module>()
----> 1 cp.prop = 1

<ipython-input-1-16b7c320d521> in <lambda>(cls, attr, val)
      6         # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
      7         dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
----> 8         dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
      9         return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)

AttributeError: can't set attribute

Điều này cũng hoạt động với một setter được xác định trong siêu dữ liệu.


1

Sau khi tìm kiếm các địa điểm khác nhau, tôi đã tìm thấy một phương thức để xác định một classproperty hợp lệ với Python 2 và 3.

from future.utils import with_metaclass

class BuilderMetaClass(type):
    @property
    def load_namespaces(self):
        return (self.__sourcepath__)

class BuilderMixin(with_metaclass(BuilderMetaClass, object)):
    __sourcepath__ = 'sp'        

print(BuilderMixin.load_namespaces)

Hy vọng điều này có thể giúp ai đó :)


1
Nếu phương pháp này là một cái gì đó bạn tìm thấy ở đâu đó, sẽ tốt hơn nếu đưa ra một liên kết (xem Cách tham khảo tài liệu được viết bởi người khác )
Andrew Myers

-27

Đây là gợi ý của tôi. Đừng sử dụng các phương thức lớp.

Nghiêm túc.

Lý do của việc sử dụng các phương thức lớp trong trường hợp này là gì? Tại sao không có một đối tượng bình thường của một lớp bình thường?


Nếu bạn chỉ đơn giản muốn thay đổi giá trị, một tài sản không thực sự rất hữu ích phải không? Chỉ cần đặt giá trị thuộc tính và được thực hiện với nó.

Một tài sản chỉ nên được sử dụng nếu có thứ gì đó để che giấu - thứ gì đó có thể thay đổi trong quá trình thực hiện trong tương lai.

Có thể ví dụ của bạn bị tước bỏ, và có một số tính toán quái quỷ mà bạn đã bỏ qua. Nhưng nó không giống như tài sản thêm giá trị đáng kể.

Các kỹ thuật "quyền riêng tư" chịu ảnh hưởng của Java (trong Python, tên thuộc tính bắt đầu bằng _) thực sự không hữu ích lắm. Riêng tư từ ai? Điểm riêng tư là hơi mơ hồ khi bạn có nguồn (như bạn làm trong Python.)

Các getters và setters kiểu EJB chịu ảnh hưởng của Java (thường được thực hiện như các thuộc tính trong Python) có mặt để tạo điều kiện cho sự hướng nội nguyên thủy của Java cũng như để vượt qua trình biên dịch với trình biên dịch ngôn ngữ tĩnh. Tất cả các getters và setters không hữu ích trong Python.


14
Bởi vì tôi cần sửa đổi một thuộc tính theo cách mà tất cả các thể hiện của một lớp nhìn thấy và trong phạm vi mà các phương thức lớp này được gọi không có tham chiếu đến tất cả các thể hiện của lớp.
Mark Roddy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.