Làm thế nào để thêm thuộc tính vào một lớp động?


215

Mục tiêu là tạo ra một lớp giả hoạt động như một tập kết quả db.

Vì vậy, ví dụ, nếu một truy vấn cơ sở dữ liệu trả về, sử dụng biểu thức chính tả {'ab':100, 'cd':200}, thì tôi muốn xem:

>>> dummy.ab
100

Lúc đầu tôi nghĩ có lẽ tôi có thể làm theo cách này:

ks = ['ab', 'cd']
vs = [12, 34]
class C(dict):
    def __init__(self, ks, vs):
        for i, k in enumerate(ks):
            self[k] = vs[i]
            setattr(self, k, property(lambda x: vs[i], self.fn_readyonly))

    def fn_readonly(self, v)
        raise "It is ready only"

if __name__ == "__main__":
    c = C(ks, vs)
    print c.ab

nhưng c.abtrả về một đối tượng tài sản thay thế.

Thay thế setattrdòng k = property(lambda x: vs[i])là không sử dụng ở tất cả.

Vì vậy, cách đúng để tạo một thuộc tính cá thể trong thời gian chạy là gì?

PS tôi biết một sự thay thế trình bày trong Làm thế nào là __getattribute__phương pháp được sử dụng?


2
Có một vài lỗi chính tả trong mã của bạn: định nghĩa của fn_readonly cần một :và các __init__tham chiếu self.fn_readyonly.
mhawke

Bạn đúng rồi. Tôi đã thêm chức năng setter vào phút cuối để nhấn mạnh lý do tạo một thuộc tính trong thời gian chạy.
Anthony Kong

Vấn đề chính tôi gặp phải khi tạo các thuộc tính khi khởi tạo là, trong một số trường hợp nếu tôi gọi nhanh cho người trợ giúp sau đó, hoặc có một vấn đề, tôi sẽ gặp một lỗi mà họ không tồn tại mặc dù thực tế là họ đã làm. Trong giải pháp của tôi dưới đây, tôi tạo 2 lớp. Một là Cơ sở / Phụ huynh (mà tôi đang cố gắng tìm giải pháp để tránh) và đối tượng chính, mở rộng Cơ sở / Phụ huynh. Sau đó, trong đối tượng chính, không khởi tạo, tôi gọi trình tạo AccessorFunc của mình để tạo các thuộc tính, hàm trợ giúp và hơn thế nữa.
Acecool

tức là: class exampleBase: pass; lớp Ví dụ (exampleBase): __x = Accessor (exampleBase, 'x', 'X', 123); --- sẽ tạo một thuộc tính dưới x và các hàm được đặt tên bằng X, vì vậy GetX, SetX và hơn thế nữa ... và .x, ._x và .__ x cho thuộc tính. Vì vậy, .x là chính thuộc tính cho dữ liệu đi qua (nhận / cài đặt qua self.x = 123; hoặc self.x để xuất). Tôi đã sử dụng self._x cho dữ liệu RAW được lưu trữ để có thể dễ dàng truy cập vì tôi cũng cho phép các giá trị mặc định được gán, mà không đặt chúng trong dữ liệu được lưu trữ. vì vậy _x có thể là Không và .x có thể trả về 123. và .__ x được liên kết với Accessor
Acecool

Đây là một liên kết đến phiên bản cơ bản tạo ra các thuộc tính động và các hàm động - tệp có một loạt các liên kết đến các phiên bản khác. Một là hệ thống AccessorFunc sử dụng một hàm để tạo các trình trợ giúp (một cho các hàm, một cho các thuộc tính, một cho cả hai phần tử riêng lẻ - vì vậy nó không sử dụng rút ngắn mã trong bất kỳ thứ gì trong tệp đó) .. Nếu thiếu bất cứ thứ gì các tệp khác có nó: dropbox.com/s/phnnuavssmzeqrr/dynamic_properIES_simple Shikdl=0
Acecool

Câu trả lời:


333

Tôi cho rằng tôi nên mở rộng câu trả lời này, bây giờ tôi đã lớn tuổi và khôn ngoan hơn và biết chuyện gì đang xảy ra. Muộn còn hơn không.

Bạn có thể thêm một thuộc tính cho một lớp động. Nhưng đó là điểm thu hút: bạn phải thêm nó vào lớp .

>>> class Foo(object):
...     pass
... 
>>> foo = Foo()
>>> foo.a = 3
>>> Foo.b = property(lambda self: self.a + 1)
>>> foo.b
4

A propertythực sự là một triển khai đơn giản của một thứ gọi là mô tả . Đó là một đối tượng cung cấp xử lý tùy chỉnh cho một thuộc tính nhất định, trên một lớp nhất định . Kinda giống như một cách để nhân tố một ifcây lớn ra khỏi __getattribute__.

Khi tôi yêu cầu foo.btrong ví dụ trên, Python thấy rằng bđịnh nghĩa trên dụng cụ lớp giao thức mô tả -which chỉ có nghĩa là nó là một đối tượng với một __get__, __set__hoặc __delete__phương pháp. Bộ mô tả yêu cầu trách nhiệm xử lý thuộc tính đó, do đó, Python gọi Foo.b.__get__(foo, Foo)và giá trị trả về được trả lại cho bạn dưới dạng giá trị của thuộc tính. Trong trường hợp property, mỗi người trong số các phương pháp này chỉ gọi fget, fsethoặc fdelbạn truyền cho propertyconstructor.

Các mô tả thực sự là cách Python phơi bày hệ thống ống nước của toàn bộ triển khai OO của nó. Trong thực tế, có một loại mô tả khác thậm chí còn phổ biến hơn property.

>>> class Foo(object):
...     def bar(self):
...         pass
... 
>>> Foo().bar
<bound method Foo.bar of <__main__.Foo object at 0x7f2a439d5dd0>>
>>> Foo().bar.__get__
<method-wrapper '__get__' of instancemethod object at 0x7f2a43a8a5a0>

Phương pháp khiêm tốn chỉ là một loại mô tả khác. Nó __get__xử lý ví dụ gọi là đối số đầu tiên; thực tế, nó làm điều này:

def __get__(self, instance, owner):
    return functools.partial(self.function, instance)

Dù sao, tôi nghi ngờ đây là lý do tại sao các mô tả chỉ hoạt động trên các lớp: chúng là sự chính thức hóa các công cụ hỗ trợ các lớp học ở nơi đầu tiên. Chúng thậm chí là ngoại lệ cho quy tắc: rõ ràng bạn có thể gán mô tả cho một lớp và các lớp là chính các trường hợp của type! Trong thực tế, cố gắng đọc Foo.bcác cuộc gọi vẫn còn property.__get__; nó chỉ là thành ngữ để các mô tả tự trả về khi được truy cập dưới dạng các thuộc tính lớp.

Tôi nghĩ thật tuyệt vời khi hầu như tất cả hệ thống OO của Python đều có thể được thể hiện bằng Python. :)

Ồ, và tôi đã viết một bài đăng trên blog về người mô tả một thời gian trước nếu bạn quan tâm.


35
Không cần thêm phương thức add_property. setattr (Foo, 'name', property (func))
Courtney D

8
"Nhưng đó là câu bắt" của bạn chỉ giúp tôi tiết kiệm được vài giờ làm việc. Cảm ơn bạn.
Matt Howell

2
Nếu bạn muốn xác định một thuộc tính trên một cá thể, bạn có thể tạo một lớp trong thời gian chạy và sửa đổi __group__ .
Wilfred Hughes

1
Còn @ myproperty.setter thì sao? Làm thế nào để thêm nó một cách tự nhiên?
LRMAAX

Bạn không cần thêm thuộc tính vào một đối tượng được khởi tạo. Làm như vậy có thể có nghĩa là nó chỉ dính vào ví dụ nhưng tôi phải kiểm tra lại. Tôi biết tôi đã gặp phải một vấn đề tương tự trong đó các thuộc tính động của tôi chỉ là ví dụ, tôi cũng đã kết thúc với một thiết lập tĩnh và vấn đề tôi muốn là đối tượng để các Khởi tạo trong tương lai sẽ sử dụng chúng. Bài viết của tôi ở bên dưới và nó tạo ra các chức năng trợ giúp, và các cách dễ dàng để dễ dàng truy cập mọi thứ. .x cho thuộc tính, ._x cho dữ liệu thô mà getter / setter sử dụng (có thể là Không có) và .__ x cho đối tượng truy cập.
Acecool

57

Mục tiêu là tạo ra một lớp giả hoạt động như một tập kết quả db.

Vì vậy, những gì bạn muốn là một từ điển mà bạn có thể đánh vần một ['b'] là ab?

Điều đó thật dễ dàng:

class atdict(dict):
    __getattr__= dict.__getitem__
    __setattr__= dict.__setitem__
    __delattr__= dict.__delitem__

1
trong một thiết lập chung hơn, điều này phục vụ mục đích hạn chế. nếu dict có hệ thống phân cấp đa cấp, như d = {'a1': {'b': 'c'}, 'a2': ...}, thì trong khi bạn có thể làm d.a1 hoặc d.a2, bạn có thể ' t làm d.a1.b
Shreyas

1
Một điều cần lưu ý là điều này cho phép thiết lập các giá trị thuộc tính cho các thuộc tính có cùng tên với các phương thức hoặc thuộc tính dict, nhưng không cho phép truy xuất lại các giá trị theo cùng một cách : d.items = 1, d.itemstrả về <built-in method items of atdict object at ...>. Bạn vẫn có thể làm d["items"]hoặc sử dụng __getattribute__thay vì __getattr__, nhưng điều này ngăn việc sử dụng hầu hết các phương thức của dict.
Marcono1234

Chỉ cần sử dụng thư viện munch ! (ngã ba bó)
Brian Peterson

38

Dường như bạn có thể giải quyết vấn đề này đơn giản hơn nhiều với a namedtuple, vì bạn biết toàn bộ danh sách các trường trước thời hạn.

from collections import namedtuple

Foo = namedtuple('Foo', ['bar', 'quux'])

foo = Foo(bar=13, quux=74)
print foo.bar, foo.quux

foo2 = Foo()  # error

Nếu bạn thực sự cần phải viết trình thiết lập của riêng bạn, bạn sẽ phải thực hiện siêu lập trình ở cấp lớp; property()không hoạt động trên các trường hợp.


Ý tưởng tuyệt vời. Thật không may, tôi đang bị mắc kẹt với python 2.4 vào lúc này.
Anthony Kong


2
Anh chàng đã viết namedtuplexứng đáng nhận giải thưởng vì đã làm cho nó trở nên trơn tru và thanh lịch để trở thành những nguyên tắc hướng đối tượng trung thành.
Keith Pinson

4
Xin lỗi, tốt nhất, câu trả lời này chỉ áp dụng cho trường hợp đặc biệt trong đó một lớp Wanta chỉ bao gồm các thuộc tính chỉ đọc tất cả đều biết trước. Nói cách khác, tôi không nghĩ rằng nó giải quyết câu hỏi rộng hơn về cách thêm các thuộc tính chung - không chỉ các thuộc tính chỉ đọc - vào một lớp trong thời gian chạy (cũng không phải là phiên bản hiện tại của câu trả lời "bổ trợ" khác đăng bởi tác giả).
martineau

@martineau vậy ... truyền thêm đối số cho property()? không có gì trong cả hai câu trả lời cụ thể cho các thuộc tính chỉ đọc.
Eevee

32

Bạn không cần phải sử dụng một tài sản cho điều đó. Chỉ cần ghi đè __setattr__để làm cho họ đọc mà thôi.

class C(object):
    def __init__(self, keys, values):
        for (key, value) in zip(keys, values):
            self.__dict__[key] = value

    def __setattr__(self, name, value):
        raise Exception("It is read only!")

Tada.

>>> c = C('abc', [1,2,3])
>>> c.a
1
>>> c.b
2
>>> c.c
3
>>> c.d
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute 'd'
>>> c.d = 42
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __setattr__
Exception: It is read only!
>>> c.a = 'blah'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __setattr__
Exception: It is read only!

9

Làm thế nào để thêm thuộc tính vào một lớp python một cách linh hoạt?

Giả sử bạn có một đối tượng mà bạn muốn thêm thuộc tính. Thông thường, tôi muốn sử dụng các thuộc tính khi tôi cần bắt đầu quản lý quyền truy cập vào một thuộc tính trong mã có mức sử dụng xuôi dòng để tôi có thể duy trì API nhất quán. Bây giờ tôi thường sẽ thêm chúng vào mã nguồn nơi đối tượng được xác định, nhưng giả sử bạn không có quyền truy cập đó hoặc bạn cần thực sự linh hoạt chọn các chức năng của mình theo lập trình.

Tạo một lớp học

Sử dụng một ví dụ dựa trên tài liệu choproperty , hãy tạo một lớp đối tượng với thuộc tính "ẩn" và tạo một thể hiện của nó:

class C(object):
    '''basic class'''
    _x = None

o = C()

Trong Python, chúng tôi hy vọng sẽ có một cách rõ ràng để làm việc. Tuy nhiên, trong trường hợp này, tôi sẽ chỉ ra hai cách: với ký hiệu trang trí và không có. Đầu tiên, không có ký hiệu trang trí. Điều này có thể hữu ích hơn cho việc gán động của getters, setters hoặc delaries.

Năng động (còn gọi là Monkey Patching)

Hãy tạo một số cho lớp học của chúng tôi:

def getx(self):
    return self._x

def setx(self, value):
    self._x = value

def delx(self):
    del self._x

Và bây giờ chúng tôi gán những thứ này cho tài sản. Lưu ý rằng chúng ta có thể chọn các chức năng của mình theo chương trình tại đây, trả lời câu hỏi động:

C.x = property(getx, setx, delx, "I'm the 'x' property.")

Và cách sử dụng:

>>> o.x = 'foo'
>>> o.x
'foo'
>>> del o.x
>>> print(o.x)
None
>>> help(C.x)
Help on property:

    I'm the 'x' property.

Trang trí

Chúng ta có thể làm giống như chúng ta đã làm ở trên với ký hiệu trang trí, nhưng trong trường hợp này, chúng ta phải đặt tên cho các phương thức cùng tên (và tôi khuyên bạn nên giữ nó giống như thuộc tính), vì vậy việc gán chương trình không quá tầm thường như nó đang sử dụng phương pháp trên:

@property
def x(self):
    '''I'm the 'x' property.'''
    return self._x

@x.setter
def x(self, value):
    self._x = value

@x.deleter
def x(self):
    del self._x

Và gán đối tượng thuộc tính với setters và delference được cung cấp của nó cho lớp:

C.x = x

Và cách sử dụng:

>>> help(C.x)
Help on property:

    I'm the 'x' property.

>>> o.x
>>> o.x = 'foo'
>>> o.x
'foo'
>>> del o.x
>>> print(o.x)
None

5

Tôi đã hỏi một câu hỏi mô phỏng trên bài đăng Stack Overflow này để tạo ra một nhà máy lớp tạo ra các kiểu đơn giản. Kết quả là câu trả lời này có phiên bản làm việc của nhà máy lớp. Đây là một đoạn của câu trả lời:

def Struct(*args, **kwargs):
    def init(self, *iargs, **ikwargs):
        for k,v in kwargs.items():
            setattr(self, k, v)
        for i in range(len(iargs)):
            setattr(self, args[i], iargs[i])
        for k,v in ikwargs.items():
            setattr(self, k, v)

    name = kwargs.pop("name", "MyStruct")
    kwargs.update(dict((k, None) for k in args))
    return type(name, (object,), {'__init__': init, '__slots__': kwargs.keys()})

>>> Person = Struct('fname', 'age')
>>> person1 = Person('Kevin', 25)
>>> person2 = Person(age=42, fname='Terry')
>>> person1.age += 10
>>> person2.age -= 10
>>> person1.fname, person1.age, person2.fname, person2.age
('Kevin', 35, 'Terry', 32)
>>>

Bạn có thể sử dụng một số biến thể của điều này để tạo các giá trị mặc định là mục tiêu của bạn (cũng có câu trả lời trong câu hỏi liên quan đến vấn đề này).


4

Không chắc chắn nếu tôi hoàn toàn hiểu câu hỏi, nhưng bạn có thể sửa đổi các thuộc tính cá thể trong thời gian chạy với sự tích hợp __dict__của lớp của bạn:

class C(object):
    def __init__(self, ks, vs):
        self.__dict__ = dict(zip(ks, vs))


if __name__ == "__main__":
    ks = ['ab', 'cd']
    vs = [12, 34]
    c = C(ks, vs)
    print(c.ab) # 12

Về bản chất, câu hỏi của tôi là tìm hiểu xem có thể tạo một thuộc tính mới trong thời gian chạy hay không. Sự đồng thuận dường như là tiêu cực. Đề nghị của bạn chắc chắn là đơn giản và thiết thực. (Tương tự với các câu trả lời khác sử dụng dict )
Anthony Kong

Một câu trả lời đơn giản cũng sẽ là:self.__dict__[key] = value
Allan Karlson

4

Đối với những người đến từ các công cụ tìm kiếm, đây là hai điều tôi đang tìm kiếm khi nói về các thuộc tính động :

class Foo:
    def __init__(self):
        # we can dynamically have access to the properties dict using __dict__
        self.__dict__['foo'] = 'bar'

assert Foo().foo == 'bar'


# or we can use __getattr__ and __setattr__ to execute code on set/get
class Bar:
    def __init__(self):
        self._data = {}
    def __getattr__(self, key):
        return self._data[key]
    def __setattr__(self, key, value):
        self._data[key] = value

bar = Bar()
bar.foo = 'bar'
assert bar.foo == 'bar'

__dict__ là tốt nếu bạn muốn đặt các thuộc tính được tạo động. __getattr__chỉ tốt khi làm một cái gì đó khi giá trị là cần thiết, như truy vấn cơ sở dữ liệu. Combo set / get rất tốt để đơn giản hóa việc truy cập dữ liệu được lưu trữ trong lớp (như trong ví dụ trên).

Nếu bạn chỉ muốn một thuộc tính động, hãy xem hàm tích hợp thuộc tính () .


4

Bạn không thể thêm mới property()vào một cá thể trong thời gian chạy, vì các thuộc tính là các mô tả dữ liệu. Thay vào đó, bạn phải tự động tạo một lớp mới hoặc quá tải __getattribute__để xử lý các mô tả dữ liệu theo các trường hợp.


Cái này sai. Bạn có thể thêm thuộc tính vào lớp sau đó truy cập nó từ phương thức.
Ahmed

2

Cách tốt nhất để đạt được là bằng cách xác định __slots__. Bằng cách đó, cá thể của bạn không thể có thuộc tính mới.

ks = ['ab', 'cd']
vs = [12, 34]

class C(dict):
    __slots__ = []
    def __init__(self, ks, vs): self.update(zip(ks, vs))
    def __getattr__(self, key): return self[key]

if __name__ == "__main__":
    c = C(ks, vs)
    print c.ab

Đó là bản in 12

    c.ab = 33

Điều đó mang lại: AttributeError: 'C' object has no attribute 'ab'


2

Chỉ là một ví dụ khác làm thế nào để đạt được hiệu quả mong muốn

class Foo(object):

    _bar = None

    @property
    def bar(self):
        return self._bar

    @bar.setter
    def bar(self, value):
        self._bar = value

    def __init__(self, dyn_property_name):
        setattr(Foo, dyn_property_name, Foo.bar)

Vì vậy, bây giờ chúng ta có thể làm những thứ như:

>>> foo = Foo('baz')
>>> foo.baz = 5
>>> foo.bar
5
>>> foo.baz
5

2

Đây là một giải pháp:

  • Cho phép chỉ định tên thuộc tính dưới dạng chuỗi , vì vậy chúng có thể đến từ một số nguồn dữ liệu bên ngoài thay vì tất cả được liệt kê trong chương trình của bạn.
  • Thêm các thuộc tính khi lớp được định nghĩa , thay vì mỗi khi một đối tượng được tạo.

Sau khi lớp đã được xác định, bạn chỉ cần làm điều này để thêm một thuộc tính vào nó một cách linh hoạt:

setattr(SomeClass, 'propertyName', property(getter, setter))

Đây là một ví dụ hoàn chỉnh, được thử nghiệm trong Python 3:

#!/usr/bin/env python3

class Foo():
  pass

def get_x(self):
  return 3

def set_x(self, value):
  print("set x on %s to %d" % (self, value))

setattr(Foo, 'x', property(get_x, set_x))

foo1 = Foo()
foo1.x = 12
print(foo1.x)

1

Bạn có thể sử dụng đoạn mã sau để cập nhật các thuộc tính lớp bằng cách sử dụng một đối tượng từ điển:

class ExampleClass():
    def __init__(self, argv):
        for key, val in argv.items():
            self.__dict__[key] = val

if __name__ == '__main__':
    argv = {'intro': 'Hello World!'}
    instance = ExampleClass(argv)
    print instance.intro

1

Điều này khác một chút so với những gì OP muốn, nhưng tôi đã làm rối trí não cho đến khi tôi có một giải pháp làm việc, vì vậy tôi sẽ đặt ở đây cho anh chàng / cô gái tiếp theo

Tôi cần một cách để xác định setters và getters động.

class X:
    def __init__(self, a=0, b=0, c=0):
        self.a = a
        self.b = b
        self.c = c

    @classmethod
    def _make_properties(cls, field_name, inc):
        _inc = inc

        def _get_properties(self):
            if not hasattr(self, '_%s_inc' % field_name):
                setattr(self, '_%s_inc' % field_name, _inc)
                inc = _inc
            else:
                inc = getattr(self, '_%s_inc' % field_name)

            return getattr(self, field_name) + inc

        def _set_properties(self, value):
            setattr(self, '_%s_inc' % field_name, value)

        return property(_get_properties, _set_properties)

Tôi biết các lĩnh vực của tôi trước thời hạn vì vậy tôi sẽ tạo tài sản của mình. LƯU Ý: bạn không thể thực hiện PER này, các thuộc tính này sẽ tồn tại trên lớp !!!

for inc, field in enumerate(['a', 'b', 'c']):
    setattr(X, '%s_summed' % field, X._make_properties(field, inc))

Hãy kiểm tra tất cả ngay bây giờ ..

x = X()
assert x.a == 0
assert x.b == 0
assert x.c == 0

assert x.a_summed == 0  # enumerate() set inc to 0 + 0 = 0
assert x.b_summed == 1  # enumerate() set inc to 1 + 0 = 1
assert x.c_summed == 2  # enumerate() set inc to 2 + 0 = 2

# we set the variables to something
x.a = 1
x.b = 2
x.c = 3

assert x.a_summed == 1  # enumerate() set inc to 0 + 1 = 1
assert x.b_summed == 3  # enumerate() set inc to 1 + 2 = 3
assert x.c_summed == 5  # enumerate() set inc to 2 + 3 = 5

# we're changing the inc now
x.a_summed = 1 
x.b_summed = 3 
x.c_summed = 5

assert x.a_summed == 2  # we set inc to 1 + the property was 1 = 2
assert x.b_summed == 5  # we set inc to 3 + the property was 2 = 5
assert x.c_summed == 8  # we set inc to 5 + the property was 3 = 8

Có khó hiểu không? Vâng, xin lỗi tôi không thể đưa ra bất kỳ ví dụ thực tế có ý nghĩa. Ngoài ra, điều này không dành cho những người nhẹ dạ.


Nếu tôi nhớ lại một cách chính xác, tôi đã tìm ra cách trong tất cả các thử nghiệm của mình để tạo một thuộc tính loại STATIC / g / setter được thêm động. Tôi phải trải qua tất cả những điều trước đây của mình - nhưng có thể thêm một cái gì đó được chia sẻ giữa tất cả các trường hợp là điều hoàn toàn có thể. Đối với việc tạo trên một quy trình theo từng trường hợp ... Tôi khá chắc chắn rằng bạn có thể để một phiên bản khác không có gì khác. Tôi phải xác minh, nhưng tôi cũng gặp phải một vấn đề như thế này (trong những lần thử đầu tiên tôi đã mắc một lỗi khiến các chức năng được tạo ra, nhưng không phải tất cả các trường hợp đều có chúng vì một lỗ hổng)
Acecool

Ngoài ra, mọi giải pháp có thể đều được chào đón vì đây là một kho kiến ​​thức. Thật thú vị khi thấy những cách khác nhau mà những người khác nhau tạo ra giải pháp cho một vấn đề. Giải pháp của tôi làm RẤT NHIỀU, bạn đã đưa nó xuống một cái gì đó đơn giản hơn để chia sẻ. Tôi cũng đã thực hiện một biến thể nhỏ hơn của mình - nó phải ở đâu đó trong chủ đề này - và tôi chỉ nhận ra đó không phải là biến thể tôi đã đăng: -) ...
Acecool

0

Điều này dường như hoạt động (nhưng xem bên dưới):

class data(dict,object):
    def __init__(self,*args,**argd):
        dict.__init__(self,*args,**argd)
        self.__dict__.update(self)
    def __setattr__(self,name,value):
        raise AttributeError,"Attribute '%s' of '%s' object cannot be set"%(name,self.__class__.__name__)
    def __delattr__(self,name):
        raise AttributeError,"Attribute '%s' of '%s' object cannot be deleted"%(name,self.__class__.__name__)

Nếu bạn cần hành vi phức tạp hơn, hãy thoải mái chỉnh sửa câu trả lời của bạn.

biên tập

Những điều sau đây có thể sẽ hiệu quả hơn về bộ nhớ cho các bộ dữ liệu lớn:

class data(dict,object):
    def __init__(self,*args,**argd):
        dict.__init__(self,*args,**argd)
    def __getattr__(self,name):
        return self[name]
    def __setattr__(self,name,value):
        raise AttributeError,"Attribute '%s' of '%s' object cannot be set"%(name,self.__class__.__name__)
    def __delattr__(self,name):
        raise AttributeError,"Attribute '%s' of '%s' object cannot be deleted"%(name,self.__class__.__name__)

0

Để trả lời lực đẩy chính của câu hỏi của bạn, bạn muốn một thuộc tính chỉ đọc từ một dict như một nguồn dữ liệu bất biến:

Mục tiêu là tạo ra một lớp giả hoạt động như một tập kết quả db.

Vì vậy, ví dụ, nếu một truy vấn cơ sở dữ liệu trả về, sử dụng biểu thức chính tả {'ab':100, 'cd':200}, thì tôi sẽ thấy

>>> dummy.ab
100

Tôi sẽ trình bày cách sử dụng một namedtupletừ collectionsmô-đun để thực hiện điều này:

import collections

data = {'ab':100, 'cd':200}

def maketuple(d):
    '''given a dict, return a namedtuple'''
    Tup = collections.namedtuple('TupName', d.keys()) # iterkeys in Python2
    return Tup(**d)

dummy = maketuple(data)
dummy.ab

trả lại 100


0
class atdict(dict):
  def __init__(self, value, **kwargs):
    super().__init__(**kwargs)
    self.__dict = value

  def __getattr__(self, name):
    for key in self.__dict:
      if type(self.__dict[key]) is list:
        for idx, item in enumerate(self.__dict[key]):
          if type(item) is dict:
            self.__dict[key][idx] = atdict(item)
      if type(self.__dict[key]) is dict:
        self.__dict[key] = atdict(self.__dict[key])
    return self.__dict[name]



d1 = atdict({'a' : {'b': [{'c': 1}, 2]}})

print(d1.a.b[0].c)

Và đầu ra là:

>> 1

0

Mở rộng ý tưởng từ kjfletch

# This is my humble contribution, extending the idea to serialize
# data from and to tuples, comparison operations and allowing functions
# as default values.

def Struct(*args, **kwargs):
    FUNCTIONS = (types.BuiltinFunctionType, types.BuiltinMethodType, \
                 types.FunctionType, types.MethodType)
    def init(self, *iargs, **ikwargs):
        """Asume that unamed args are placed in the same order than
        astuple() yields (currently alphabetic order)
        """
        kw = list(self.__slots__)

        # set the unnamed args
        for i in range(len(iargs)):
            k = kw.pop(0)
            setattr(self, k, iargs[i])

        # set the named args
        for k, v in ikwargs.items():
            setattr(self, k, v)
            kw.remove(k)

        # set default values
        for k in kw:
            v = kwargs[k]
            if isinstance(v, FUNCTIONS):
                v = v()
            setattr(self, k, v)

    def astuple(self):
        return tuple([getattr(self, k) for k in self.__slots__])

    def __str__(self):
        data = ['{}={}'.format(k, getattr(self, k)) for k in self.__slots__]
        return '<{}: {}>'.format(self.__class__.__name__, ', '.join(data))

    def __repr__(self):
        return str(self)

    def __eq__(self, other):
        return self.astuple() == other.astuple()

    name = kwargs.pop("__name__", "MyStruct")
    slots = list(args)
    slots.extend(kwargs.keys())
    # set non-specific default values to None
    kwargs.update(dict((k, None) for k in args))

    return type(name, (object,), {
        '__init__': init,
        '__slots__': tuple(slots),
        'astuple': astuple,
        '__str__': __str__,
        '__repr__': __repr__,
        '__eq__': __eq__,
    })


Event = Struct('user', 'cmd', \
               'arg1', 'arg2',  \
               date=time.time, \
               __name__='Event')

aa = Event('pepe', 77)
print(aa)
raw = aa.astuple()

bb = Event(*raw)
print(bb)

if aa == bb:
    print('Are equals')

cc = Event(cmd='foo')
print(cc)

Đầu ra:

<Event: user=pepe, cmd=77, arg1=None, arg2=None, date=1550051398.3651814>
<Event: user=pepe, cmd=77, arg1=None, arg2=None, date=1550051398.3651814>
Are equals
<Event: user=None, cmd=foo, arg1=None, arg2=None, date=1550051403.7938335>

0

Mặc dù nhiều câu trả lời được đưa ra, tôi không thể tìm thấy câu trả lời mà tôi hài lòng. Tôi đã tìm ra giải pháp của riêng mình để làm propertyviệc cho trường hợp động. Nguồn để trả lời câu hỏi ban đầu:

#!/usr/local/bin/python3

INITS = { 'ab': 100, 'cd': 200 }

class DP(dict):
  def __init__(self):
    super().__init__()
    for k,v in INITS.items():
        self[k] = v 

def _dict_set(dp, key, value):
  dp[key] = value

for item in INITS.keys():
  setattr(
    DP,
    item,
    lambda key: property(
      lambda self: self[key], lambda self, value: _dict_set(self, key, value)
    )(item)
  )

a = DP()
print(a)  # {'ab': 100, 'cd': 200}
a.ab = 'ab100'
a.cd = False
print(a.ab, a.cd) # ab100 False

0

Một cái gì đó phù hợp với tôi là thế này:

class C:
    def __init__(self):
        self._x=None

    def g(self):
        return self._x

    def s(self, x):
        self._x = x

    def d(self):
        del self._x

    def s2(self,x):
        self._x=x+x

    x=property(g,s,d)


c = C()
c.x="a"
print(c.x)

C.x=property(C.g, C.s2)
C.x=C.x.deleter(C.d)
c2 = C()
c2.x="a"
print(c2.x)

Đầu ra

a
aa

-1

Gần đây tôi gặp phải một vấn đề tương tự, giải pháp mà tôi đã đưa ra sử dụng __getattr____setattr__đối với các thuộc tính mà tôi muốn nó xử lý, mọi thứ khác sẽ được chuyển cho bản gốc.

class C(object):
    def __init__(self, properties):
        self.existing = "Still Here"
        self.properties = properties

    def __getattr__(self, name):
        if "properties" in self.__dict__ and name in self.properties:
            return self.properties[name] # Or call a function, etc
        return self.__dict__[name]

    def __setattr__(self, name, value):
        if "properties" in self.__dict__ and name in self.properties:
            self.properties[name] = value
        else:
            self.__dict__[name] = value

if __name__ == "__main__":
    my_properties = {'a':1, 'b':2, 'c':3}
    c = C(my_properties)
    assert c.a == 1
    assert c.existing == "Still Here"
    c.b = 10
    assert c.properties['b'] == 10

Tôi đã xem xét điều này, tuy nhiên về mặt kỹ thuật bạn đang xem qua một danh sách trong trình trợ giúp getter và setter của bạn. Bởi vì điều này, mỗi cuộc gọi sẽ chậm hơn vì trước tiên bạn đang tìm kiếm nó từ một danh sách, thay vì truy cập trực tiếp vào nó. Trừ khi Python tự động ánh xạ nó cho bạn; có thể, nhưng tôi chưa biết điểm chuẩn này để biết chắc chắn, nhưng nó là một mối quan tâm đối với tôi trước khi tôi thử nó. Thứ hai, bằng cách này, bạn phải xác định người trợ giúp theo cách khác. Bạn cũng không thể khóa các kiểu dữ liệu và / hoặc giá trị mà không kết thúc bằng một từ điển lớn hoặc nhiều dòng bổ sung.
Acecool

tức là: Tôi sẽ phải tạo một lớp cơ sở mà tôi mở rộng tất cả các con tôi sử dụng hệ thống từ đó, HOẶC tôi phải thêm các hàm ma thuật s / getattr vào mọi thứ và nhân đôi hệ thống mỗi lần. Khai báo các thuộc tính cũng có nghĩa là bạn phải thiết lập chúng theo một cách và nếu bạn muốn bất kỳ hỗ trợ bổ sung nào, như tôi đã liệt kê như bảo vệ loại dữ liệu và hoặc bảo vệ giá trị để cho phép hoặc ngăn dữ liệu được chỉ định và các trợ giúp khác , sau đó bạn phải mã hóa chúng. Được cấp, bạn có thể làm cho hệ thống hoạt động tương tự nhưng kết thúc là nơi bạn khai báo hơi khác và cồng kềnh hơn.
Acecool

-1

Dưới đây là ví dụ đơn giản để tạo đối tượng thuộc tính theo chương trình.

#!/usr/bin/python3

class Counter:
    def __init__(self):
        cls = self.__class__
        self._count = 0
        cls.count = self.count_ref()

    def count_get(self):
        print(f'count_get: {self._count}')
        return self._count

    def count_set(self, value):
        self._count = value
        print(f'count_set: {self._count}')

    def count_del(self):
        print(f'count_del: {self._count}')

    def count_ref(self):
        cls = self.__class__
        return property(fget=cls.count_get, fset=cls.count_set, fdel=cls.count_del)

counter = Counter()

counter.count
for i in range(5):
    counter.count = i
del counter.count

'''
output
======
count_get: 0
count_set: 0
count_set: 1
count_set: 2
count_set: 3
count_set: 4
count_del: 4
'''

-2

Cách duy nhất để tự động đính kèm một thuộc tính là tạo một lớp mới và thể hiện của nó với thuộc tính mới của bạn.

class Holder: p = property(lambda x: vs[i], self.fn_readonly)
setattr(self, k, Holder().p)

1
Điều này dường như không hoạt động. nó sẽ chỉ định kết quả của tài sản, không phải chính tài sản đó.
mjallday

Điều này là không đúng. Tôi gắn các thuộc tính động với hệ thống của mình mà không cần phải khởi tạo lớp. Khởi tạo là x = Ví dụ (), sau đó thêm thuộc tính vào x.
Acecool

Nếu bạn nhìn vào mã của tôi, bạn sẽ thấy rằng tôi sử dụng lớp exampleBase: pass, sau đó là lớp Ví dụ (exampleBase): ... sau đó tôi đính kèm các thuộc tính vào exampleBase, vì tên đó tồn tại và vì Ví dụ mở rộng từ nó, nó có quyền truy cập vào tất cả mọi thứ. Tôi sử dụng __ var cho trình trợ giúp của trình truy cập để có thể truy cập trực tiếp vào các đối tượng của trình truy cập, tôi sử dụng _ cho dữ liệu được lưu trữ (thô) có thể là Không và không có dấu gạch dưới cho thuộc tính thực tế đi qua getter. Tôi có thể gọi hàm getter bằng hàm được thêm động hoặc sử dụng thuộc tính. Tất cả mà không có init'd đầu tiên.
Acecool

Lưu ý: Tôi đã đề cập đến nó - nhưng định nghĩa của tôi cho định nghĩa có nghĩa là tham chiếu tồn tại trong không gian tên - tức là: Ví dụ lớp (Đối tượng): vượt qua ... Nó tồn tại, nhưng chưa được khởi tạo. Khởi tạo có nghĩa là blah = Ví dụ (); bây giờ đối tượng đã được 'sao chép' và được xây dựng, sau đó được lưu trữ dưới dạng tham chiếu trong blah. --- Nếu bạn làm điều này, thì các hàm / thuộc tính được thêm động chỉ nên có trong trường hợp - vấn đề tôi gặp phải là ngay cả khi các hàm tồn tại, có những trường hợp tôi gặp lỗi nói rằng chúng không có. Hoặc chặn lỗi dừng tạo, hoặc thực thi không đồng bộ.
Acecool

Một vài lưu ý khác: Có thể tạo các thuộc tính một cách linh hoạt và các hàm theo cách chỉ tồn tại trên mỗi phiên bản. Bạn cũng có thể làm cho chúng tồn tại cho đối tượng (đó là những gì bạn muốn trong hầu hết các trường hợp). Và có những trường hợp các phần tử được thêm vào là 'tĩnh', nghĩa là cùng một tham chiếu và các giá trị được trả về được chia sẻ trên tất cả các trường hợp - nếu bạn cập nhật trong một khu vực, tất cả đều giống nhau ..
Acecool

-6

Rất nhiều câu trả lời được cung cấp yêu cầu rất nhiều dòng trên mỗi thuộc tính, tức là / và / hoặc - những gì tôi cho là việc triển khai xấu xí hoặc tẻ nhạt vì tính lặp đi lặp lại cần thiết cho nhiều thuộc tính, v.v. Tôi thích tiếp tục đun sôi / đơn giản hóa chúng cho đến khi chúng không thể được đơn giản hóa nữa hoặc cho đến khi nó không phục vụ nhiều mục đích để làm như vậy.

Tóm lại: trong các tác phẩm đã hoàn thành, nếu tôi lặp lại 2 dòng mã, tôi thường chuyển đổi nó thành một hàm trợ giúp dòng đơn, v.v ... Tôi đơn giản hóa toán học hoặc các đối số lẻ như (start_x, start_y, end_x, end_y) thành (x, y, w, h) tức là x, y, x + w, y + h (đôi khi yêu cầu min / max hoặc nếu w / h là âm và việc triển khai không giống như vậy, tôi sẽ trừ đi x / y và abs w / h. vv ..).

Ghi đè các getters / setters nội bộ là một cách tốt để đi, nhưng vấn đề là bạn cần phải làm điều đó cho mọi lớp, hoặc cha mẹ lớp đến cơ sở đó ... Điều này không phù hợp với tôi vì tôi thích tự do lựa chọn con cái / cha mẹ để thừa kế, nút con, v.v.

Tôi đã tạo ra một giải pháp trả lời câu hỏi mà không cần sử dụng kiểu dữ liệu Dict để cung cấp dữ liệu vì tôi thấy việc đó là tẻ nhạt để nhập dữ liệu, v.v ...

Giải pháp của tôi yêu cầu bạn thêm 2 dòng bên trên lớp để tạo lớp cơ sở cho lớp bạn muốn thêm thuộc tính, sau đó 1 dòng trên mỗi và bạn có tùy chọn thêm cuộc gọi lại để kiểm soát dữ liệu, thông báo cho bạn khi dữ liệu thay đổi , hạn chế dữ liệu có thể được đặt dựa trên giá trị và / hoặc loại dữ liệu và hơn thế nữa.

Bạn cũng có tùy chọn sử dụng _object.x, _object.x = value, _object.GetX (), _object.SetX (value) và chúng được xử lý tương đương.

Ngoài ra, các giá trị là dữ liệu không tĩnh duy nhất được gán cho thể hiện của lớp, nhưng thuộc tính thực tế được gán cho lớp có nghĩa là những điều bạn không muốn lặp lại, không cần phải lặp lại ... Bạn có thể gán một giá trị mặc định để getter không cần nó mỗi lần, mặc dù có một tùy chọn để ghi đè giá trị mặc định và có một tùy chọn khác để getter trả về giá trị được lưu trữ thô bằng cách ghi đè trả về mặc định (lưu ý: phương thức này có nghĩa là giá trị thô chỉ được gán khi giá trị được gán, nếu không thì là Không - khi giá trị được đặt lại, sau đó nó sẽ gán Không, v.v.)

Cũng có nhiều hàm trợ giúp - thuộc tính đầu tiên được thêm 2 hoặc nhiều trình trợ giúp vào lớp để tham chiếu các giá trị cá thể ... Chúng là các varargs ResetAccessors (_key, ..) ) và SetAccessors (_key, _value) với tùy chọn được thêm vào lớp chính để hỗ trợ hiệu quả - những cách được lên kế hoạch là: một cách để nhóm người truy cập cùng nhau, vì vậy, nếu bạn có xu hướng thiết lập lại một vài lần , bạn có thể gán chúng cho một nhóm và đặt lại nhóm thay vì lặp lại các khóa được đặt tên mỗi lần và hơn thế nữa.

Giá trị lưu trữ thể hiện / thô được lưu trữ tại lớp., lớp. tham chiếu Lớp Accessor chứa vars / value / hàm tĩnh cho thuộc tính. _lớp học. là chính thuộc tính được gọi khi được truy cập thông qua lớp cá thể trong khi thiết lập / nhận, v.v.

Accessor _ class .__ trỏ đến lớp, nhưng vì nó là nội bộ nên nó cần được gán trong lớp, đó là lý do tại sao tôi chọn sử dụng __Name = AccessorFunc (...) để gán nó, một dòng cho mỗi thuộc tính có nhiều tùy chọn sử dụng các đối số (sử dụng các vararg có khóa vì chúng dễ dàng và hiệu quả hơn để xác định và duy trì) ...

Tôi cũng tạo ra rất nhiều chức năng, như đã đề cập, một số trong số đó sử dụng thông tin chức năng của trình truy cập để không cần phải gọi (vì hiện tại nó hơi bất tiện - ngay bây giờ bạn cần sử dụng _ class. class .. , args) - Tôi đã sử dụng stack / dấu vết để lấy tham chiếu thể hiện để lấy giá trị bằng cách thêm các hàm chạy marathon bit này hoặc bằng cách thêm các hàm truy cập vào đối tượng và sử dụng chính nó (đặt tên này để chỉ ra chúng ví dụ và để giữ quyền truy cập vào bản thân, tham chiếu lớp AccessorFunc và các thông tin khác từ bên trong các định nghĩa hàm).

Nó không hoàn thành, nhưng nó là một chân giữ tuyệt vời. Lưu ý: Nếu bạn không sử dụng __Name = AccessorFunc (...) để tạo các thuộc tính, bạn sẽ không có quyền truy cập vào phím __ ngay cả khi tôi xác định nó trong hàm init. Nếu bạn làm, sau đó không có vấn đề.

Ngoài ra: Lưu ý rằng Tên và Khóa khác nhau ... Tên là 'chính thức', được sử dụng trong Tạo tên hàm và khóa dành cho lưu trữ và truy cập dữ liệu. tức là _group.x trong đó chữ thường x là khóa, tên sẽ là chữ hoa X sao cho GetX () là hàm thay vì Getx () trông hơi kỳ lạ. điều này cho phép self.x hoạt động và trông phù hợp, nhưng cũng cho phép GetX () và trông phù hợp.

Tôi có một lớp ví dụ được thiết lập với khóa / tên giống hệt nhau và khác nhau để hiển thị. rất nhiều hàm trợ giúp được tạo để xuất dữ liệu (Lưu ý: Không phải tất cả các chức năng này đã hoàn tất) để bạn có thể thấy những gì đang diễn ra.

Danh sách các hàm hiện tại sử dụng khóa: x, name: X xuất ra dưới dạng:

Đây không phải là một danh sách toàn diện - có một vài cái chưa được đưa vào danh sách này tại thời điểm đăng ...

_instance.SetAccessors( _key, _value [ , _key, _value ] .. )                   Instance Class Helper Function: Allows assigning many keys / values on a single line - useful for initial setup, or to minimize lines.    In short: Calls this.Set<Name>( _value ) for each _key / _value pairing.
_instance.ResetAccessors( _key [ , _key ] .. )                                 Instance Class Helper Function: Allows resetting many key stored values to None on a single line.                                           In short: Calls this.Reset<Name>() for each name provided.


Note: Functions below may list self.Get / Set / Name( _args ) - self is meant as the class instance reference in the cases below - coded as this in AccessorFuncBase Class.

this.GetX( _default_override = None, _ignore_defaults = False )                 GET:            Returns    IF ISSET: STORED_VALUE .. IF IGNORE_DEFAULTS: None  .. IF PROVIDED: DEFAULT_OVERRIDE ELSE: DEFAULT_VALUE       100
this.GetXRaw( )                                                                 RAW:            Returns    STORED_VALUE                                                                                                     100
this.IsXSet( )                                                                  ISSET:          Returns    ( STORED_VALUE != None )                                                                                         True

this.GetXToString( )                                                            GETSTR:         Returns    str( GET )                                                                                                       100
this.GetXLen( _default_override = None, _ignore_defaults = False )              LEN:            Returns    len( GET )                                                                                                       3
this.GetXLenToString( _default_override = None, _ignore_defaults = False )      LENSTR:         Returns    str( len( GET ) )                                                                                                3
this.GetXDefaultValue( )                                                        DEFAULT:        Returns    DEFAULT_VALUE                                                                                                    1111

this.GetXAccessor( )                                                            ACCESSOR:       Returns    ACCESSOR_REF ( self.__<key> )                                                                                    [ AccessorFuncBase ] Key: x : Class ID: 2231452344344 : self ID: 2231448283848        Default: 1111       Allowed Types: {"<class 'int'>": "<class 'type'>", "<class 'float'>": "<class 'type'>"}     Allowed Values: None
this.GetXAllowedTypes( )                                                        ALLOWED_TYPES:  Returns    Allowed Data-Types                                                                                               {"<class 'int'>": "<class 'type'>", "<class 'float'>": "<class 'type'>"}
this.GetXAllowedValues( )                                                       ALLOWED_VALUES: Returns    Allowed Values                                                                                                   None

this.GetXHelpers( )                                                             HELPERS:        Returns    Helper Functions String List - ie what you're reading now...                                                     THESE ROWS OF TEXT
this.GetXKeyOutput( )                                                           Returns information about this Name / Key                                                                                                   ROWS OF TEXT
this.GetXGetterOutput( )                                                        Returns information about this Name / Key                                                                                                   ROWS OF TEXT

this.SetX( _value )                                                             SET:            STORED_VALUE Setter - ie Redirect to __<Key>.Set                                                                            N / A
this.ResetX( )                                                                  RESET:          Resets STORED_VALUE to None                                                                                                 N / A

this.HasXGetterPrefix( )                                                        Returns Whether or Not this key has a Getter Prefix...                                                                                      True
this.GetXGetterPrefix( )                                                        Returns Getter Prefix...                                                                                                                    Get

this.GetXName( )                                                                Returns Accessor Name - Typically Formal / Title-Case                                                                                       X
this.GetXKey( )                                                                 Returns Accessor Property Key - Typically Lower-Case                                                                                        x
this.GetXAccessorKey( )                                                         Returns Accessor Key - This is to access internal functions, and static data...                                                             __x
this.GetXDataKey( )                                                             Returns Accessor Data-Storage Key - This is the location where the class instance value is stored..                                         _x

Một số dữ liệu được xuất ra là:

Đây là một lớp hoàn toàn mới được tạo bằng lớp Demo mà không có bất kỳ dữ liệu nào được gán ngoài tên (vì vậy nó có thể là đầu ra) là _foo, tên biến tôi đã sử dụng ...

_foo         --- MyClass: ---- id( this.__class__ ): 2231452349064 :::: id( this ): 2231448475016

    Key       Getter Value        | Raw Key   Raw / Stored Value       | Get Default Value             Default Value            | Get Allowed Types             Allowed Types                                                              | Get Allowed Values            Allowed Values                                                                                                                                                                                                                   |

    Name:     _foo                | _Name:    _foo                     | __Name.DefaultValue( ):       AccessorFuncDemoClass    | __Name.GetAllowedTypes( )     <class 'str'>                                                              | __Name.GetAllowedValues( )    Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    x:        1111                | _x:       None                     | __x.DefaultValue( ):          1111                     | __x.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __x.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    y:        2222                | _y:       None                     | __y.DefaultValue( ):          2222                     | __y.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __y.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    z:        3333                | _z:       None                     | __z.DefaultValue( ):          3333                     | __z.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __z.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Blah:     <class 'int'>       | _Blah:    None                     | __Blah.DefaultValue( ):       <class 'int'>            | __Blah.GetAllowedTypes( )     <class 'str'>                                                              | __Blah.GetAllowedValues( )    Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Width:    1                   | _Width:   None                     | __Width.DefaultValue( ):      1                        | __Width.GetAllowedTypes( )    (<class 'int'>, <class 'bool'>)                                            | __Width.GetAllowedValues( )   Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Height:   0                   | _Height:  None                     | __Height.DefaultValue( ):     0                        | __Height.GetAllowedTypes( )   <class 'int'>                                                              | __Height.GetAllowedValues( )  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)                                                                                                                                                                                                   |
    Depth:    2                   | _Depth:   None                     | __Depth.DefaultValue( ):      2                        | __Depth.GetAllowedTypes( )    Saved Value Restricted to Authorized Values ONLY                           | __Depth.GetAllowedValues( )   (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)                                                                                                                                                                                                   |


this.IsNameSet( ):    True      this.GetName( ):     _foo                     this.GetNameRaw( ):    _foo                     this.GetNameDefaultValue( ):    AccessorFuncDemoClass    this.GetNameLen( ):    4    this.HasNameGetterPrefix( ):    <class 'str'>                                this.GetNameGetterPrefix( ):    None
this.IsXSet( ):       False     this.GetX( ):        1111                     this.GetXRaw( ):       None                     this.GetXDefaultValue( ):       1111                     this.GetXLen( ):       4    this.HasXGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetXGetterPrefix( ):       None
this.IsYSet( ):       False     this.GetY( ):        2222                     this.GetYRaw( ):       None                     this.GetYDefaultValue( ):       2222                     this.GetYLen( ):       4    this.HasYGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetYGetterPrefix( ):       None
this.IsZSet( ):       False     this.GetZ( ):        3333                     this.GetZRaw( ):       None                     this.GetZDefaultValue( ):       3333                     this.GetZLen( ):       4    this.HasZGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetZGetterPrefix( ):       None
this.IsBlahSet( ):    False     this.GetBlah( ):     <class 'int'>            this.GetBlahRaw( ):    None                     this.GetBlahDefaultValue( ):    <class 'int'>            this.GetBlahLen( ):    13   this.HasBlahGetterPrefix( ):    <class 'str'>                                this.GetBlahGetterPrefix( ):    None
this.IsWidthSet( ):   False     this.GetWidth( ):    1                        this.GetWidthRaw( ):   None                     this.GetWidthDefaultValue( ):   1                        this.GetWidthLen( ):   1    this.HasWidthGetterPrefix( ):   (<class 'int'>, <class 'bool'>)              this.GetWidthGetterPrefix( ):   None
this.IsDepthSet( ):   False     this.GetDepth( ):    2                        this.GetDepthRaw( ):   None                     this.GetDepthDefaultValue( ):   2                        this.GetDepthLen( ):   1    this.HasDepthGetterPrefix( ):   None                                         this.GetDepthGetterPrefix( ):   (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
this.IsHeightSet( ):  False     this.GetHeight( ):   0                        this.GetHeightRaw( ):  None                     this.GetHeightDefaultValue( ):  0                        this.GetHeightLen( ):  1    this.HasHeightGetterPrefix( ):  <class 'int'>                                this.GetHeightGetterPrefix( ):  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

Và đây là sau khi gán tất cả các thuộc tính _foo (trừ tên) các giá trị sau theo cùng một thứ tự: 'chuỗi', 1.0, True, 9, 10, Sai

this.IsNameSet( ):    True      this.GetName( ):     _foo                     this.GetNameRaw( ):    _foo                     this.GetNameDefaultValue( ):    AccessorFuncDemoClass    this.GetNameLen( ):    4    this.HasNameGetterPrefix( ):    <class 'str'>                                this.GetNameGetterPrefix( ):    None
this.IsXSet( ):       True      this.GetX( ):        10                       this.GetXRaw( ):       10                       this.GetXDefaultValue( ):       1111                     this.GetXLen( ):       2    this.HasXGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetXGetterPrefix( ):       None
this.IsYSet( ):       True      this.GetY( ):        10                       this.GetYRaw( ):       10                       this.GetYDefaultValue( ):       2222                     this.GetYLen( ):       2    this.HasYGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetYGetterPrefix( ):       None
this.IsZSet( ):       True      this.GetZ( ):        10                       this.GetZRaw( ):       10                       this.GetZDefaultValue( ):       3333                     this.GetZLen( ):       2    this.HasZGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetZGetterPrefix( ):       None
this.IsBlahSet( ):    True      this.GetBlah( ):     string Blah              this.GetBlahRaw( ):    string Blah              this.GetBlahDefaultValue( ):    <class 'int'>            this.GetBlahLen( ):    11   this.HasBlahGetterPrefix( ):    <class 'str'>                                this.GetBlahGetterPrefix( ):    None
this.IsWidthSet( ):   True      this.GetWidth( ):    False                    this.GetWidthRaw( ):   False                    this.GetWidthDefaultValue( ):   1                        this.GetWidthLen( ):   5    this.HasWidthGetterPrefix( ):   (<class 'int'>, <class 'bool'>)              this.GetWidthGetterPrefix( ):   None
this.IsDepthSet( ):   True      this.GetDepth( ):    9                        this.GetDepthRaw( ):   9                        this.GetDepthDefaultValue( ):   2                        this.GetDepthLen( ):   1    this.HasDepthGetterPrefix( ):   None                                         this.GetDepthGetterPrefix( ):   (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
this.IsHeightSet( ):  True      this.GetHeight( ):   9                        this.GetHeightRaw( ):  9                        this.GetHeightDefaultValue( ):  0                        this.GetHeightLen( ):  1    this.HasHeightGetterPrefix( ):  <class 'int'>                                this.GetHeightGetterPrefix( ):  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

_foo         --- MyClass: ---- id( this.__class__ ): 2231452349064 :::: id( this ): 2231448475016

    Key       Getter Value        | Raw Key   Raw / Stored Value       | Get Default Value             Default Value            | Get Allowed Types             Allowed Types                                                              | Get Allowed Values            Allowed Values                                                                                                                                                                                                                   |

    Name:     _foo                | _Name:    _foo                     | __Name.DefaultValue( ):       AccessorFuncDemoClass    | __Name.GetAllowedTypes( )     <class 'str'>                                                              | __Name.GetAllowedValues( )    Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    x:        10                  | _x:       10                       | __x.DefaultValue( ):          1111                     | __x.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __x.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    y:        10                  | _y:       10                       | __y.DefaultValue( ):          2222                     | __y.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __y.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    z:        10                  | _z:       10                       | __z.DefaultValue( ):          3333                     | __z.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __z.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Blah:     string Blah         | _Blah:    string Blah              | __Blah.DefaultValue( ):       <class 'int'>            | __Blah.GetAllowedTypes( )     <class 'str'>                                                              | __Blah.GetAllowedValues( )    Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Width:    False               | _Width:   False                    | __Width.DefaultValue( ):      1                        | __Width.GetAllowedTypes( )    (<class 'int'>, <class 'bool'>)                                            | __Width.GetAllowedValues( )   Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Height:   9                   | _Height:  9                        | __Height.DefaultValue( ):     0                        | __Height.GetAllowedTypes( )   <class 'int'>                                                              | __Height.GetAllowedValues( )  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)                                                                                                                                                                                                   |
    Depth:    9                   | _Depth:   9                        | __Depth.DefaultValue( ):      2                        | __Depth.GetAllowedTypes( )    Saved Value Restricted to Authorized Values ONLY                           | __Depth.GetAllowedValues( )   (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)                                                                                                                                                                                                   |

Lưu ý rằng do các loại dữ liệu bị hạn chế hoặc hạn chế giá trị, một số dữ liệu không được chỉ định - đây là do thiết kế. Trình thiết lập cấm các kiểu dữ liệu hoặc giá trị xấu được gán, thậm chí không được gán làm giá trị mặc định (trừ khi bạn ghi đè hành vi bảo vệ giá trị mặc định)

Mã chưa được đăng ở đây vì tôi không có chỗ sau các ví dụ và giải thích ... Cũng bởi vì nó sẽ thay đổi.

Xin lưu ý: tại thời điểm đăng bài này, tệp bị lộn xộn - điều này sẽ thay đổi. Nhưng, nếu bạn chạy nó trong Sublime Text và biên dịch nó, hoặc chạy nó từ Python, nó sẽ biên dịch và phun ra một tấn thông tin - phần AccessorDB không được thực hiện (sẽ được sử dụng để cập nhật Trình trợ giúp Print Getters và GetKeyOutput các chức năng cùng với việc được thay đổi thành một chức năng Instance, có thể được đưa vào một chức năng duy nhất và được đổi tên - hãy tìm nó ..)

Tiếp theo: Không phải mọi thứ đều cần thiết để nó chạy - rất nhiều nội dung được nhận xét ở phía dưới là để biết thêm thông tin được sử dụng để gỡ lỗi - nó có thể không ở đó khi bạn tải xuống. Nếu có, bạn sẽ có thể bỏ ghi chú và biên dịch lại để có thêm thông tin.

Tôi đang tìm kiếm một giải pháp cần MyClassBase: pass, MyClass (MyClassBase): ... - nếu bạn biết về một giải pháp - hãy đăng nó.

Điều duy nhất cần thiết trong lớp là các dòng __ - str là để gỡ lỗi như là init - chúng có thể bị xóa khỏi Lớp Demo nhưng bạn sẽ cần nhận xét hoặc xóa một số dòng bên dưới (_foo / 2/3 ) ..

Các lớp String, Dict và Util ở trên cùng là một phần của thư viện Python của tôi - chúng chưa hoàn thành. Tôi đã sao chép một vài thứ tôi cần từ thư viện và tôi đã tạo ra một vài thứ mới. Mã đầy đủ sẽ liên kết đến thư viện hoàn chỉnh và sẽ bao gồm nó cùng với việc cung cấp các cuộc gọi được cập nhật và xóa mã (thực tế, mã duy nhất còn lại sẽ là Lớp Demo và các câu lệnh in - hệ thống AccessorFunc sẽ được chuyển đến thư viện). ..

Một phần của tập tin:

##
## MyClass Test AccessorFunc Implementation for Dynamic 1-line Parameters
##
class AccessorFuncDemoClassBase( ):
    pass
class AccessorFuncDemoClass( AccessorFuncDemoClassBase ):
    __Name      = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'Name',      default = 'AccessorFuncDemoClass',  allowed_types = ( TYPE_STRING ),                    allowed_values = VALUE_ANY,                 documentation = 'Name Docs',        getter_prefix = 'Get',  key = 'Name',       allow_erroneous_default = False,    options = { } )
    __x         = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'X',         default = 1111,                     allowed_types = ( TYPE_INTEGER, TYPE_FLOAT ),       allowed_values = VALUE_ANY,                 documentation = 'X Docs',           getter_prefix = 'Get',  key = 'x',          allow_erroneous_default = False,    options = { } )
    __Height    = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'Height',    default = 0,                        allowed_types = TYPE_INTEGER,                       allowed_values = VALUE_SINGLE_DIGITS,       documentation = 'Height Docs',      getter_prefix = 'Get',  key = 'Height',     allow_erroneous_default = False,    options = { } )

Vẻ đẹp này giúp dễ dàng tạo các lớp mới với các thuộc tính được thêm động với AccessorFuncs / callbacks / data-type / value, v.v.

Hiện tại, liên kết đang ở (Liên kết này sẽ phản ánh các thay đổi đối với tài liệu.): Https://www.dropbox.com/s/6gzi44i7dh58v61/dynamic_properies_accessorfuncs_and_more Hebdl=0

Ngoài ra: Nếu bạn không sử dụng Sublime Text, tôi khuyên dùng nó trên Notepad ++, Atom, Visual Code và các loại khác vì việc triển khai luồng phù hợp làm cho nó sử dụng nhanh hơn nhiều, nhanh hơn ... Tôi cũng đang làm việc trên một mã giống như IDE hệ thống ánh xạ cho nó - hãy xem: https://bitbucket.org/Acecool/acecoolcodemappingsystem/src/master/ (Trước tiên hãy thêm Repo trong Trình quản lý gói, sau đó Cài đặt Plugin - khi phiên bản 1.0.0 đã sẵn sàng, tôi sẽ thêm nó vào danh sách plugin chính ...)

Tôi hy vọng giải pháp này sẽ giúp ... và, như mọi khi:

Chỉ vì nó hoạt động, không làm cho nó đúng - Josh 'Acecool' Moser


Tôi muốn thêm một màn hình nhanh về lớp trông như thế nào để bạn không cần mở tệp mã nhưng các bình luận không xuất hiện để hỗ trợ nó ..
Acecool

Rõ ràng điều này đang nhận được rất nhiều sự ghét bỏ, đó là khó hiểu. Nó thực hiện chính xác những gì OP đang yêu cầu - tự động thêm các thuộc tính vào một đối tượng. Nó cũng thêm các chức năng của trình trợ giúp, không cần phải đưa vào - có thể đó là lý do khiến nó bị ghét - và nó cũng đảm bảo nhà phát triển có một cách dễ dàng để truy cập vào tài sản (.x) được xử lý thông qua getter, giá trị thô được lưu trữ (._x) có thể là Không khi .x trả về mặc định hoặc thứ gì khác và cách truy cập trình truy cập để sử dụng trình trợ giúp, thay đổi mọi thứ, v.v. (.__ x) ....
Acecool
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.