Вопрос

Цель состоит в том, чтобы создать макет класса, который ведет себя как набор результатов БД.

Так, например, если запрос к базе данных возвращает результат с использованием выражения dict, {'ab':100, 'cd':200}, то я хотел бы увидеть:

>>> dummy.ab
100

Сначала я подумал, что, возможно, я мог бы сделать это следующим образом:

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

но c.ab Вместо этого возвращает объект свойства.

Замена setattr линия с k = property(lambda x: vs[i]) совершенно бесполезен.

Итак, как правильно создать свойство экземпляра во время выполнения?

P.S.Мне известна альтернатива, представленная в Как __getattribute__ используемый метод?

Это было полезно?

Решение

Полагаю, мне следует расширить этот ответ теперь, когда я стал старше, мудрее и знаю, что происходит.Лучше поздно, чем никогда.

Ты может динамически добавлять свойство в класс.Но в этом загвоздка:вам нужно добавить его в сорт.

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

А property на самом деле это простая реализация вещи, называемой дескриптор.Это объект, который обеспечивает индивидуальную обработку данного атрибута. по данному классу.Что-то вроде способа учесть огромное if дерево из __getattribute__.

Когда я прошу foo.b в приведенном выше примере Python видит, что b определенный в классе, реализует протокол дескриптора— что просто означает, что это объект с __get__, __set__, или __delete__ метод.Дескриптор берет на себя ответственность за обработку этого атрибута, поэтому Python вызывает Foo.b.__get__(foo, Foo), и возвращаемое значение передается вам как значение атрибута.В случае property, каждый из этих методов просто вызывает fget, fset, или fdel ты перешел в property конструктор.

Дескрипторы на самом деле являются способом Python раскрыть суть всей объектно-ориентированной реализации.На самом деле, есть еще один тип дескриптора, даже более распространенный, чем 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>

Скромный метод — это всего лишь еще один вид дескриптора.Его __get__ добавляет вызывающий экземпляр в качестве первого аргумента;по сути, он делает это:

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

В любом случае, я подозреваю, что именно поэтому дескрипторы работают только с классами:они представляют собой формализацию того, что в первую очередь обеспечивает работу классов.Они даже являются исключением из правил:вы, очевидно, можете назначить дескрипторы классу, а классы сами являются экземплярами type!На самом деле, пытаясь прочитать Foo.b все еще звонит property.__get__;это просто идиоматично, что дескрипторы возвращают себя при доступе к ним как к атрибутам класса.

Я думаю, это здорово, что практически вся объектно-ориентированная система Python может быть выражена на Python.:)

Ох, и я написал многословный пост в блоге об дескрипторах некоторое время назад, если вам интересно.

Другие советы

Цель состоит в том, чтобы создать макет класса, который ведет себя как набор результатов БД.

Итак, что вам нужно, это словарь, в котором вы можете написать a['b'] как a.b?

Это легко:

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

Кажется, вы могли бы решить эту проблему гораздо проще с помощью namedtuple, поскольку вы заранее знаете весь список полей.

from collections import namedtuple

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

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

foo2 = Foo()  # error

Если вам абсолютно необходимо написать свой собственный сеттер, вам придется выполнить метапрограммирование на уровне класса; property() не работает с экземплярами.

Для этого не обязательно использовать свойство.Просто переопределить __setattr__ чтобы они были доступны только для чтения.

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!")

Тада.

>>> 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!

Как динамически добавить свойство в класс Python?

Допустим, у вас есть объект, к которому вы хотите добавить свойство.Обычно я хочу использовать свойства, когда мне нужно начать управлять доступом к атрибуту в коде, который используется в дальнейшем, чтобы я мог поддерживать согласованный API.Сейчас я обычно добавляю их в исходный код, где определен объект, но давайте предположим, что у вас нет такого доступа или вам нужно по-настоящему динамически выбирать свои функции программно.

Создать класс

Используя пример, основанный на документация для property, давайте создадим класс объекта со «скрытым» атрибутом и создадим его экземпляр:

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

o = C()

Мы ожидаем, что в Python будет один очевидный способ выполнения задач.Однако в данном случае я собираюсь показать два способа:с обозначением декоратора и без.Во-первых, без обозначения декоратора.Это может быть более полезно для динамического назначения методов получения, установки или удаления.

Динамический (он жеПатч обезьяны)

Давайте создадим некоторые для нашего класса:

def getx(self):
    return self._x

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

def delx(self):
    del self._x

И теперь мы присваиваем их свойству.Обратите внимание, что здесь мы могли бы выбирать наши функции программно, отвечая на динамический вопрос:

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

И использование:

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

    I'm the 'x' property.

Декораторы

Мы могли бы сделать то же самое, что и выше, с нотацией декоратора, но в этом случае мы должен назовите методы одинаковыми именами (и я бы рекомендовал оставить их такими же, как и атрибут), поэтому программное назначение не так тривиально, как при использовании вышеуказанного метода:

@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

И назначьте объект свойства с его предоставленными средствами установки и удаления классу:

C.x = x

И использование:

>>> 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

Я задал аналогичный вопрос в этом сообщении о переполнении стека создать фабрику классов, которая создавала простые типы.Результатом было этот ответ у которого была рабочая версия фабрики классов.Вот фрагмент ответа:

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)
>>>

Вы можете использовать некоторые варианты этого, чтобы создать значения по умолчанию, что и является вашей целью (в этом вопросе также есть ответ).

Вы не можете добавить новый property() к экземпляру во время выполнения, поскольку свойства являются дескрипторами данных.Вместо этого вы должны динамически создавать новый класс или перегружать его. __getattribute__ для обработки дескрипторов данных в экземплярах.

Не уверен, что я полностью понимаю вопрос, но вы можете изменять свойства экземпляра во время выполнения с помощью встроенного __dict__ вашего класса:

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

Для тех, кто пришел из поисковых систем, вот две вещи, которые я искал, когда говорил: динамичный характеристики:

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__ это хорошо, если вы хотите разместить динамически создаваемые свойства. __getattr__ Хорошо делать что-то только тогда, когда значение необходимо, например, запрашивать базу данных.Комбинация set/get удобна для упрощения доступа к данным, хранящимся в классе (как в примере выше).

Если вам нужно только одно динамическое свойство, взгляните на свойство() встроенная функция.

Лучший способ добиться этого – определить __slots__.Таким образом, ваши экземпляры не могут иметь новые атрибуты.

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

Это печатает 12

    c.ab = 33

Это дает: AttributeError: 'C' object has no attribute 'ab'

Еще один пример того, как добиться желаемого эффекта

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)

Итак, теперь мы можем делать такие вещи, как:

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

Вы можете использовать следующий код для обновления атрибутов класса с помощью объекта словаря:

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

Кажется, это работает (но см. ниже):

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__)

Если вам нужно более сложное поведение, не стесняйтесь редактировать свой ответ.

редактировать

Для больших наборов данных, вероятно, будет более эффективно использовать память:

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__)

Чтобы ответить на основную суть вашего вопроса, вам нужен атрибут только для чтения из dict в качестве неизменяемого источника данных:

Цель состоит в том, чтобы создать макет класса, который ведет себя как набор результатов БД.

Так, например, если запрос к базе данных возвращает результат с использованием выражения dict, {'ab':100, 'cd':200}, тогда бы я посмотрел

>>> dummy.ab
100

Я покажу, как использовать namedtuple из collections модуль для выполнения именно этого:

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

возвращает 100

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)

И результат:

>> 1

Расширяя идею от Кейфлетч

# 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)

Выход:

<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>

Хотя дано много ответов, я не смог найти тот, который меня бы устроил.Я нашел свое собственное решение, которое делает property работать для динамического случая.Источник ответа на исходный вопрос:

#!/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

Что-то, что работает для меня, это:

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)

Выход

a
aa

Это немного отличается от того, что хотел ОП, но я ломал голову, пока не нашел работающее решение, поэтому помещаю сюда для следующего парня/девчонки.

Мне нужен был способ указать динамические сеттеры и геттеры.

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)

Я заранее знаю свои поля, поэтому собираюсь создать свои свойства.ПРИМЕЧАНИЕ:вы не можете сделать этот экземпляр PER, эти свойства будут существовать в классе!!!

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

Давайте теперь все это проверим..

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

Это сбивает с толку?Да, извините, я не смог привести каких-либо содержательных примеров из реальной жизни.Кроме того, это не для легкомысленных.

Единственный способ динамически прикрепить свойство — создать новый класс и его экземпляр с вашим новым свойством.

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

Недавно я столкнулся с аналогичной проблемой, решение, которое я нашел, использует __getattr__ и __setattr__ для свойств, которые я хочу, чтобы он обрабатывал, все остальное передается оригиналам.

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

Многие из предоставленных ответов требуют такого количества строк для каждого свойства, т. е. / и / или - что я бы посчитал уродливой или утомительной реализацией из-за повторяемости, необходимой для нескольких свойств и т. д.Я предпочитаю упрощать/упрощать вещи до тех пор, пока их уже нельзя будет упростить или пока это не перестанет приносить пользу.

Суммируя:в завершенных работах, если я повторяю две строки кода, я обычно конвертирую их в однострочную вспомогательную функцию и так далее...Я упрощаю математические вычисления или нечетные аргументы, такие как (start_x, start_y, end_x, end_y) до (x, y, w, h), т.е. x, y, x + w, y + h (иногда требуется min/max или if w/h отрицательны и реализация не нравится, вычитаю из x/y и abs w/h.и т. д..).

Переопределение внутренних геттеров/сеттеров — это хороший способ, но проблема в том, что вам нужно сделать это для каждого класса или создать родительский класс для этой базы...У меня это не работает, так как я бы предпочел иметь возможность свободно выбирать детей/родителей для наследования, дочерние узлы и т. д.

Я создал решение, которое отвечает на вопрос, не используя тип данных Dict для предоставления данных, поскольку я считаю, что вводить данные утомительно и т. д.

Мое решение требует, чтобы вы добавили 2 дополнительные строки над вашим классом, чтобы создать базовый класс для класса, к которому вы хотите добавить свойства, затем по 1 строке на каждую, и у вас есть возможность добавить обратные вызовы для управления данными, сообщать вам об изменении данных. , ограничить данные, которые могут быть установлены на основе значения и/или типа данных, и многое другое.

У вас также есть возможность использовать _object.x, _object.x = value, _object.GetX(), _object.SetX(value), и они обрабатываются одинаково.

Кроме того, значения являются единственными нестатическими данными, которые присваиваются экземпляру класса, но фактическое свойство присваивается классу, что означает, что то, что вы не хотите повторять, не нужно повторять...Вы можете назначить значение по умолчанию, чтобы геттеру оно не требовалось каждый раз, хотя есть возможность переопределить значение по умолчанию, а также есть другой вариант, чтобы геттер возвращал необработанное сохраненное значение, переопределяя возвращаемые значения по умолчанию (примечание:этот метод означает, что необработанное значение назначается только тогда, когда присвоено значение, в противном случае оно равно «Нет» - когда значение равно «Сброс», тогда присваивается «Нет» и т. д.)

Также существует множество вспомогательных функций: первое добавляемое свойство добавляет в класс около двух вспомогательных функций для ссылки на значения экземпляра...Это ResetAccessors( _key, ..) повторенные varargs (все можно повторить, используя первые названные args) и SetAccessors( _key, _value ) с возможностью добавления большего количества в основной класс для повышения эффективности - запланированы следующие:способ группировать средства доступа вместе, поэтому, если вы склонны сбрасывать несколько одновременно, каждый раз, вы можете назначить их группе и сбросить группу вместо повторения именованных ключей каждый раз и многое другое.

Экземпляр/необработанное сохраненное значение хранится по адресу сорт., класс.ссылается на класс доступа, который содержит статические переменные/значения/функции для свойства._сорт.— это само свойство, которое вызывается при доступе через класс экземпляра во время установки/получения и т. д.

Аксессор _class.__ указывает на класс, но поскольку он является внутренним, его необходимо назначить в классе, поэтому я решил использовать __Name = AccessorFunc( ...), чтобы назначить его, одну строку для каждого свойства со множеством дополнительных аргументов (используя переменные аргументы с ключами, потому что их легче и эффективнее идентифицировать и поддерживать)...

Как уже упоминалось, я также создаю множество функций, некоторые из которых используют информацию о функции доступа, поэтому ее не нужно вызывать (поскольку в данный момент это немного неудобно — прямо сейчас вам нужно использовать _class..FunctionName( _class_instance, args) — я использовал стек/трассировку, чтобы получить ссылку на экземпляр и получить значение, добавив функции, которые либо запускают этот битовый марафон, либо добавив методы доступа к объекту и используя self (с именем this). чтобы указать, что они предназначены для экземпляра, и сохранить доступ к себе, ссылке на класс AccessorFunc и другой информации из определений функций).

Это еще не совсем сделано, но это фантастическая точка опоры.Примечание:Если вы не используете __Name = AccessorFunc(...) для создания свойств у вас не будет доступа к клавише __, хотя я определяю ее в функции init.Если да, то проблем нет.

Также:Обратите внимание, что имя и ключ разные...Имя является «формальным», используется при создании имени функции, а ключ предназначен для хранения данных и доступа к ним.т.е. _class.x, где строчная x является ключом, имя будет X в верхнем регистре, так что GetX( ) является функцией вместо Getx( ), что выглядит немного странно.это позволяет self.x работать и выглядеть соответствующим образом, а также позволяет GetX() выглядеть соответствующим образом.

У меня есть пример класса с идентичным ключом/именем и разными значениями для отображения.множество вспомогательных функций, созданных для вывода данных (Примечание:Не все это полно) так что вы можете видеть, что происходит.

Текущий список функций с использованием клавиши:х, имя:X выводит как:

Это ни в коем случае не полный список — есть некоторые, которые не попали в него на момент публикации…

_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

Некоторые из выводимых данных:

Это совершенно новый класс, созданный с использованием класса Demo, без каких-либо данных, кроме имени (чтобы его можно было вывести), то есть _foo, имя переменной, которую я использовал...

_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)

И это после присвоения всем свойствам _foo (кроме имени) следующих значений в том же порядке:'строка', 1.0, Истина, 9, 10, Ложь

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)                                                                                                                                                                                                   |

Обратите внимание, что из-за ограничений типов данных или значений некоторые данные не были назначены — это сделано намеренно.Установщик запрещает назначение неверных типов данных или значений, даже в качестве значения по умолчанию (если вы не переопределите поведение защиты значений по умолчанию).

Код не был размещен здесь, потому что после примеров и пояснений мне не хватило места...А еще потому, что оно изменится.

Пожалуйста, обрати внимание:на момент публикации в файле был беспорядок - это изменится.Но если вы запустите его в Sublime Text и скомпилируете его или запустите из Python, он скомпилирует и выдаст массу информации — часть AccessorDB еще не завершена (которая будет использоваться для обновления вспомогательных методов Print Getters и GetKeyOutput). функции, а также изменены на функцию экземпляра, возможно, помещены в одну функцию и переименованы - ищите ее.)

Следующий:Для его запуска требуется не все - многие комментарии внизу предназначены для получения дополнительной информации, используемой для отладки - ее может не быть при загрузке.Если это так, вы сможете раскомментировать и перекомпилировать, чтобы получить дополнительную информацию.

Я ищу обходной путь для MyClassBase:пройти, MyClass(MyClassBase):...- если знаете решение - напишите.

Единственное, что необходимо в классе — это строки __ — ул. предназначен для отладки, как и в этом — их можно удалить из демонстрационного класса, но вам нужно будет закомментировать или удалить некоторые строки ниже ( _foo / 2 / 3 )..

Классы String, Dict и Util вверху являются частью моей библиотеки Python — они неполные.Я скопировал несколько нужных мне вещей из библиотеки и создал несколько новых.Полный код будет связан с полной библиотекой и будет включать ее вместе с предоставлением обновленных вызовов и удалением кода (фактически, единственным оставшимся кодом будет демонстрационный класс и операторы печати — система AccessorFunc будет перенесена в библиотеку). ..

Часть файла:

##
## 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 = { } )

Эта красота позволяет невероятно легко создавать новые классы с динамически добавляемыми свойствами с помощью AccessorFuncs/обратных вызовов/типа данных/значений и т. д.

На данный момент ссылка находится по адресу (Эта ссылка должна отражать изменения в документе.): https://www.dropbox.com/s/6gzi44i7dh58v61/dynamic_properties_accessorfuncs_and_more.py?dl=0

Также:Если вы не используете Sublime Text, я рекомендую его вместо Notepad++, Atom, Visual Code и других, поскольку правильная реализация потоков делает его использование намного быстрее...Я также работаю над системой сопоставления кода, подобной IDE, — взгляните на: https://bitbucket.org/Acecool/acecoolcodemappingsystem/src/master/ (Сначала добавьте репо в диспетчере пакетов, затем установите плагин — когда версия 1.0.0 будет готова, я добавлю ее в основной список плагинов...)

Я надеюсь, что это решение поможет...и как всегда:

То, что это работает, не делает это правильным - Джош «Acecool» Мозер

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top