如何动态地向类添加属性?

问题:如何动态地向类添加属性?

目标是创建一个行为类似db结果集的模拟类。

因此,例如,如果数据库查询使用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返回一个属性对象。

用替换该setattrk = property(lambda x: vs[i])根本没有用。

那么在运行时创建实例属性的正确方法是什么?

PS我知道如何使用__getattribute__方法?

The goal is to create a mock class which behaves like a db resultset.

So for example, if a database query returns, using a dict expression, {'ab':100, 'cd':200}, then I would like to see:

>>> dummy.ab
100

At first I thought maybe I could do it this way:

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

but c.ab returns a property object instead.

Replacing the setattr line with k = property(lambda x: vs[i]) is of no use at all.

So what is the right way to create an instance property at runtime?

P.S. I am aware of an alternative presented in How is the __getattribute__ method used?


回答 0

我想我应该扩大这个答案,因为我年龄较大,比较聪明,并且知道发生了什么事。迟到总比不到好。

可以动态地向类添加属性。但这很重要:您必须将其添加到类中

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

property实际上,A 是称为描述符的事物的简单实现。该对象为给定类的给定属性提供自定义处理。Kinda就像一种从if树上拔出一棵大树的方法__getattribute__

当我要求foo.b在上面的例子中,Python看到的是,b在类实现限定的描述符协议哪位只是意味着它是一个对象__get____set____delete__方法。描述符声明负责处理该属性,因此Python调用Foo.b.__get__(foo, Foo),并将返回值作为属性值传递回给您。在的情况下property,每一种方法只是调用fgetfsetfdel你传递给property构造函数。

描述符实际上是Python公开其整个OO实现的基本方法。实际上,还有一种比更为常见的描述符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)

无论如何,我怀疑这就是为什么描述符仅在类上起作用的原因:它们是首先为类提供支持的东西的形式化形式。它们甚至是规则的exceptions:您显然可以为一个类分配描述符,而类本身就是type!的实例。实际上,试图读取Foo.b静态调用property.__get__;当描述符作为类属性访问时,返回它们自己只是惯用的。

我认为几乎所有Python的OO系统都可以用Python表示非常酷。:)

哦,如果您有兴趣的话,我写了一篇关于描述符冗长博客文章

I suppose I should expand this answer, now that I’m older and wiser and know what’s going on. Better late than never.

You can add a property to a class dynamically. But that’s the catch: you have to add it to the class.

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

A property is actually a simple implementation of a thing called a descriptor. It’s an object that provides custom handling for a given attribute, on a given class. Kinda like a way to factor a huge if tree out of __getattribute__.

When I ask for foo.b in the example above, Python sees that the b defined on the class implements the descriptor protocol—which just means it’s an object with a __get__, __set__, or __delete__ method. The descriptor claims responsibility for handling that attribute, so Python calls Foo.b.__get__(foo, Foo), and the return value is passed back to you as the value of the attribute. In the case of property, each of these methods just calls the fget, fset, or fdel you passed to the property constructor.

Descriptors are really Python’s way of exposing the plumbing of its entire OO implementation. In fact, there’s another type of descriptor even more common than 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>

The humble method is just another kind of descriptor. Its __get__ tacks on the calling instance as the first argument; in effect, it does this:

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

Anyway, I suspect this is why descriptors only work on classes: they’re a formalization of the stuff that powers classes in the first place. They’re even the exception to the rule: you can obviously assign descriptors to a class, and classes are themselves instances of type! In fact, trying to read Foo.b still calls property.__get__; it’s just idiomatic for descriptors to return themselves when accessed as class attributes.

I think it’s pretty cool that virtually all of Python’s OO system can be expressed in Python. :)

Oh, and I wrote a wordy blog post about descriptors a while back if you’re interested.


回答 1

目标是创建一个行为类似db结果集的模拟类。

因此,您需要一本可以将a [‘b’]拼写为ab的字典吗?

这很简单:

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

The goal is to create a mock class which behaves like a db resultset.

So what you want is a dictionary where you can spell a[‘b’] as a.b?

That’s easy:

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

回答 2

似乎您可以使用来更简单地解决此问题namedtuple,因为您提前知道了整个字段列表。

from collections import namedtuple

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

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

foo2 = Foo()  # error

如果您绝对需要编写自己的setter,则必须在类级别进行元编程。property()在实例上不起作用。

It seems you could solve this problem much more simply with a namedtuple, since you know the entire list of fields ahead of time.

from collections import namedtuple

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

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

foo2 = Foo()  # error

If you absolutely need to write your own setter, you’ll have to do the metaprogramming at the class level; property() doesn’t work on instances.


回答 3

您不需要为此使用属性。只需重写__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!

You don’t need to use a property for that. Just override __setattr__ to make them read only.

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!

回答 4

如何动态地向python类添加属性?

假设您有一个对象要添加属性。通常,当我需要开始管理对具有下游用法的代码中的属性的访问时,我想使用属性,以便可以维护一致的API。现在,我通常将它们添加到定义对象的源代码中,但是让我们假设您没有该访问权限,或者您需要以编程方式真正地动态选择函数。

建立类

使用基于的文档property的示例,让我们创建一个具有“隐藏”属性的对象类并创建一个实例:

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

o = C()

在Python中,我们期望有一种显而易见的处理方式。但是,在这种情况下,我将展示两种方式:使用装饰符表示法和不使用装饰符表示法。首先,没有装饰符号。这对于动态获取,设置或删除程序可能更为有用。

动态(又名Monkey修补)

让我们为我们的Class创建一些:

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

How to add property to a python class dynamically?

Say you have an object that you want to add a property to. Typically, I want to use properties when I need to begin managing access to an attribute in code that has downstream usage, so that I can maintain a consistent API. Now I will typically add them to the source code where the object is defined, but let’s assume you don’t have that access, or you need to truly dynamically choose your functions programmatically.

Create a class

Using an example based on the documentation for property, let’s create a class of object with a “hidden” attribute and create an instance of it:

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

o = C()

In Python, we expect there to be one obvious way of doing things. However, in this case, I’m going to show two ways: with decorator notation, and without. First, without decorator notation. This may be more useful for the dynamic assignment of getters, setters, or deleters.

Dynamic (a.k.a. Monkey Patching)

Let’s create some for our class:

def getx(self):
    return self._x

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

def delx(self):
    del self._x

And now we assign these to the property. Note that we could choose our functions programmatically here, answering the dynamic question:

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

And usage:

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

    I'm the 'x' property.

Decorators

We could do the same as we did above with decorator notation, but in this case, we must name the methods all the same name (and I’d recommend keeping it the same as the attribute), so programmatic assignment is not so trivial as it is using the above method:

@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

And assign the property object with its provisioned setters and deleters to the class:

C.x = x

And usage:

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

在这个Stack Overflow帖子上问了一个相似的问题以创建一个创建简单类型的类工厂。结果是这个答案具有Class工厂的工作版本。这是答案的片段:

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

您可以使用此方法的一些变体来创建默认值,这是您的目标(该问题中也有一个答案与此相关)。

I asked a similary question on this Stack Overflow post to create a class factory which created simple types. The outcome was this answer which had a working version of the class factory. Here is a snippet of the answer:

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

You could use some variation of this to create default values which is your goal (there is also an answer in that question which deals with this).


回答 6

不知道我是否完全理解这个问题,但是您可以在运行时使用类的内置实例属性进行修改__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

Not sure if I completely understand the question, but you can modify instance properties at runtime with the built-in __dict__ of your class:

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

回答 7

对于那些来自搜索引擎的人来说,这是我在谈论动态属性时正在寻找的两件事:

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__仅在需要该值时才做某事是很好的,例如查询数据库。设置/获取组合可以简化对类中存储的数据的访问(就像上面的示例一样)。

如果只需要一个动态属性,请查看property()内置函数。

For those coming from search engines, here are the two things I was looking for when talking about dynamic properties:

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__ is good if you want to put dynamically created properties. __getattr__ is good to only do something when the value is needed, like query a database. The set/get combo is good to simplify the access to data stored in the class (like in the example above).

If you only want one dynamic property, have a look at the property() built-in function.


回答 8

您不能property()在运行时向实例添加新实例,因为属性是数据描述符。相反,您必须动态创建一个新类或重载__getattribute__以处理实例上的数据描述符。

You cannot add a new property() to an instance at runtime, because properties are data descriptors. Instead you must dynamically create a new class, or overload __getattribute__ in order to process data descriptors on instances.


回答 9

最好的方法是通过定义__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'

The best way to achieve is by defining __slots__. That way your instances can’t have new attributes.

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

That prints 12

    c.ab = 33

That gives: AttributeError: 'C' object has no attribute 'ab'


回答 10

另一个例子,如何达到预期的效果

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

Just another example how to achieve desired effect

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)

So now we can do stuff like:

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

回答 11

这是一个解决方案:

  • 允许将属性名称指定为string,因此它们可以来自某些外部数据源,而不是在程序中列出的所有名称。
  • 在定义类时添加属性,而不是在每次创建对象时添加属性

定义了类之后,只需执行以下操作即可向其动态添加属性:

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

这是一个经过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)

Here is a solution that:

  • Allows specifying property names as strings, so they can come from some outside data source instead of all being listed in your program.
  • Adds the properties when the class is defined, instead of every time an object is created.

After the class has been defined, you just do this to add a property to it dynamically:

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

Here is a complete example, tested in 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)

回答 12

您可以使用以下代码通过字典对象更新类属性:

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

You can use the following code to update class attributes using a dictionary object:

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

回答 13

这与OP想要的有所不同,但是我动了动脑筋,直到找到可行的解决方案为止,所以我在这里为下一个家伙/女友

我需要一种方法来指定动态的setter和getter。

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

令人困惑吗?是的,很抱歉,我无法提出任何有意义的现实示例。同样,这也不适合那些轻松的人。

This is a little different than what OP wanted, but I rattled my brain until I got a working solution, so I’m putting here for the next guy/gal

I needed a way to specify dynamic setters and getters.

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)

I know my fields ahead of time so im going to create my properties. NOTE: you cannot do this PER instance, these properties will exist on the class!!!

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

Let’s test it all now..

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

Is it confusing? Yes, sorry I couldn’t come up with any meaningful real world examples. Also, this is not for the light hearted.


回答 14

这似乎可行(但请参见下文):

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

This seems to work(but see below):

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

If you need more complex behavior, feel free to edit your answer.

edit

The following would probably be more memory-efficient for large datasets:

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

回答 15

为了回答问题的主旨,您希望将字典中的只读属性作为不可变数据源:

目标是创建一个行为类似db结果集的模拟类。

因此,例如,如果数据库查询使用dict表达式返回 {'ab':100, 'cd':200},那么我将看到

>>> dummy.ab
100

我将演示如何使用namedtuple来自collections模块的a来完成此任务:

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

To answer the main thrust of your question, you want a read-only attribute from a dict as an immutable datasource:

The goal is to create a mock class which behaves like a db resultset.

So for example, if a database query returns, using a dict expression, {'ab':100, 'cd':200}, then I would to see

>>> dummy.ab
100

I’ll demonstrate how to use a namedtuple from the collections module to accomplish just this:

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

returns 100


回答 16

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

And the output is:

>> 1

回答 17

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)

输出:

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

Extending the idea from 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)

Output:

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

回答 18

尽管给出了很多答案,但我找不到我满意的答案。我想出了自己的解决方案,该解决方案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

Although many answers are given, I couldn’t find one I am happy with. I figured out my own solution which makes property work for the dynamic case. The source to answer the original question:

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

回答 19

对我有用的是这样的:

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

Something that works for me is this:

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)

Output

a
aa

回答 20

最近,我遇到了一个类似的问题,即我想出的解决方案使用了它,__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

I recently ran into a similar problem, the solution that I came up with uses __getattr__ and __setattr__ for the properties that I want it to handle, everything else gets passed on to the originals.

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

回答 21

这是通过编程创建属性对象的简单示例。

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

Here is the simple example to create property object programmatically.

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

回答 22

动态附加属性的唯一方法是使用新属性创建一个新类及其实例。

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

Only way to dynamically attach a property is to create a new class and its instance with your new property.

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

回答 23

提供的很多答案每个属性需要这么多行,即/和/或-由于多个属性需要重复性,我认为这是丑陋或乏味的实现。不能再简化了,或者直到它没有太大用处为止。

简而言之:在完成的作品中,如果我重复两行代码,通常会将其转换为单行辅助函数,以此类推…将数学或奇数参数(例如(start_x,start_y,end_x,end_y)简化为(x,y,w,h)即x,y,x + w,y + h(有时需要min / max或如果w / h为负且实现不喜欢它,我将从x /中减去y和ab w / h等。)。

重写内部getter / setter方法是可行的方法,但是问题是您需要为每个类都这样做,或者将该类作为该基础的父类…这对我不起作用,因为我更希望成为自由选择子代/父代进行继承,子节点等。

我创建了一个解决方案,无需使用Dict数据类型来提供数据即可回答问题,因为我发现输入数据等操作很繁琐,等等。

我的解决方案要求您在类上方添加2行,以为要向其添加属性的类创建基类,然后为每个类添加1行,并且您可以选择添加回调以控制数据,并在数据更改时通知您,限制可以根据值和/或数据类型等进行设置的数据。

您还可以选择使用_object.x,_object.x =值,_object.GetX(),_object.SetX(值),并且它们被等效地处理。

此外,值是分配给类实例的唯一非静态数据,但是实际属性却分配给了类,这意味着您不想重复的事情,不需要重复…可以分配一个默认值,因此每次都有一个不需要的getter,尽管有一个选项可以覆盖默认的默认值,还有另一个选项可以使getter通过覆盖默认的返回值来返回原始存储值(注意:此方法表示仅在分配值时才分配原始值,否则为None-当值重置时,它分配None等。)

辅助函数也有很多-添加的第一个属性将2个左右的辅助函数添加到类中以引用实例值…它们是ResetAccessors(_key,..)varargs重复(所有操作都可以使用第一个命名的args重复进行) )和SetAccessors(_key,_value),还可以选择将更多选项添加到主类中以提高效率-计划的方法是:一种将访问器组合在一起的方式,因此,如果您倾向于每次都重置一些访问器,您可以将它们分配给一个组并重置该组,而不必每次都重复命名的密钥,甚至更多。

实例/原始存储值存储在类中。, 班上。引用访问器类,该类保存该属性的静态vars / values / functions。_类。是属性本身,在设置/获取等过程中通过实例类访问时会调用该属性。

访问器_class .__指向该类,但是由于它是内部的,因此需要在该类中进行分配,这就是为什么我选择使用__Name = AccessorFunc(…)对其进行分配的原因,每个属性一行包含多个可选项要使用的参数(使用键控varargs,是因为它们更容易,更有效地标识和维护)…

如前所述,我还创建了许多函数,其中一些函数使用访问器函数信息,因此不需要调用(因为目前有点不方便-现在您需要使用 _class。.FunctionName(_class_instance ,args)-通过添加运行此马拉松马拉松函数或将访问器添加到对象并使用self(命名为指出它们的方法),我可以使用堆栈/跟踪来获取实例引用以获取值是针对实例的,并保留对自身,AccessorFunc类引用以及函数定义内的其他信息的访问)。

尚未完成,但这是一个了不起的立足点。注意:如果不使用__Name = AccessorFunc(…)创建属性,则即使我在init函数中定义了__键,也无法访问__键。如果这样做,则没有问题。

另外:请注意,名称和键是不同的…名称是“正式的”,在函数名称创建中使用,并且键用于数据存储和访问。即_class.x,其中小写的x是键,名称将是大写的X,因此GetX()是函数,而不是看起来有些奇怪的Getx()。这可以使self.x正常工作并看起来合适,但也可以使GetX()看起来合适。

我有一个示例类,其键/名称相同,但显示不同。为了输出数据而创建了许多辅助函数(注意:并非所有这些都是完整的),因此您可以看到发生了什么。

使用键:x,名称: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属性(名称除外)按相同顺序分配以下值之后:’string’,1.0,True,9,10,False

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帮助器)函数以及被更改为Instance函数,可能放在一个函数中并重命名-查找它。

下一步:运行它并不需要所有内容-底部的很多注释内容是用于调试的更多信息-下载时可能不存在。如果是这样,您应该可以取消注释并重新编译以获得更多信息。

我正在寻找一种解决方案,需要MyClassBase:通过,MyClass(MyClassBase):…-如果您知道解决方案,请发布它。

该类中唯一需要的是__行-strinit一样都是用于调试的-可以将它们从Demo类中删除,但是您需要注释掉或删除下面的一些行(_foo / 2/3 )..

顶部的String,Dict和Util类是我的Python库的一部分-它们不完整。我从库中复制了一些我需要的东西,然后创建了一些新东西。完整的代码将链接到完整的库,并将包括完整的库以及提供更新的调用和删除代码(实际上,剩下的唯一代码将是Demo类和print语句-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/(首先在软件包管理器中添加Repo,然后再安装插件-在1.0.0版本准备就绪时,我将添加它到主插件列表…)

我希望这个解决方案能对您有所帮助……并且一如既往:

仅仅因为它有效,就不能使它正确-Josh’Acecool’Moser

A lot of the supplied answers require so many lines per property, ie / and / or – what I’d consider an ugly or tedious implementation because of repetitiveness required for multiple properties, etc. I prefer keeping boiling things down / simplifying them until they can’t be simplified anymore or until it doesn’t serve much purpose to do so.

In short: in completed works, if I repeat 2 lines of code, I typically convert it into a single line helper function, and so on… I simplify math or odd arguments such as ( start_x, start_y, end_x, end_y ) to ( x, y, w, h ) ie x, y, x + w, y + h ( sometimes requiring min / max or if w / h are negative and the implementation doesn’t like it, I’ll subtract from x / y and abs w / h. etc.. ).

Overriding the internal getters / setters is an ok way to go, but the problem is you need to do that for every class, or parent the class to that base… This doesn’t work for me as I’d prefer to be free to choose the children / parents for inheritance, child nodes, etc.

I have created a solution which answers the question without using a Dict data-type to supply the data as I find that to be tedious to enter the data, etc…

My solution requires you to add 2 extra lines above your class to create a base class for the class you want to add the properties to, then 1 line per and you have the option to add callbacks to control the data, inform you when data changes, restrict the data which can be set based on value and / or data-type, and much more.

You also have the option to use _object.x, _object.x = value, _object.GetX( ), _object.SetX( value ) and they are handled equivalently.

Additionally, the values are the only non-static data which are assigned to the class instance, but the actual property is assigned to the class meaning the things you don’t want to repeat, don’t need to be repeated… You can assign a default value so the getter doesn’t need it each time, although there is an option to override the default default value, and there is another option so the getter returns the raw stored value by overriding default returns ( note: this method means the raw value is only assigned when a value is assigned, otherwise it is None – when the value is Reset, then it assigns None, etc.. )

There are many helper functions too – the first property which gets added adds 2 or so helpers to the class for referencing the instance values… They are ResetAccessors( _key, .. ) varargs repeated ( all can be repeated using the first named args ) and SetAccessors( _key, _value ) with the option of more being added to the main class to aide in efficiency – the ones planned are: a way to group accessors together, so if you tend to reset a few at a time, every time, you can assign them to a group and reset the group instead of repeating the named keys each time, and more.

The instance / raw stored value is stored at class., the __class. references the Accessor Class which holds static vars / values / functions for the property. _class. is the property itself which is called when accessed via the instance class during setting / getting, etc.

The Accessor _class.__ points to the class, but because it is internal it needs to be assigned in the class which is why I opted to use __Name = AccessorFunc( … ) to assign it, a single line per property with many optional arguments to use ( using keyed varargs because they’re easier and more efficient to identify and maintain )…

I also create a lot of functions, as mentioned, some of which use accessor function information so it doesn’t need to be called ( as it is a bit inconvenient at the moment – right now you need to use _class..FunctionName( _class_instance, args ) – I got around using the stack / trace to grab the instance reference to grab the value by adding the functions which either run this bit marathon, or by adding the accessors to the object and using self ( named this to point out they’re for the instance and to retain access to self, the AccessorFunc class reference, and other information from within the function definitions ).

It isn’t quite done, but it is a fantastic foot-hold. Note: If you do not use __Name = AccessorFunc( … ) to create the properties, you won’t have access to the __ key even though I define it within the init function. If you do, then there are no issues.

Also: Note that Name and Key are different… Name is ‘formal’, used in Function Name Creation, and the key is for data storage and access. ie _class.x where lowercase x is key, the name would be uppercase X so that GetX( ) is the function instead of Getx( ) which looks a little odd. this allows self.x to work and look appropriate, but also allow GetX( ) and look appropriate.

I have an example class set up with key / name identical, and different to show. a lot of helper functions created in order to output the data ( Note: Not all of this is complete ) so you can see what is going on.

The current list of functions using key: x, name: X outputs as:

This is by no means a comprehensive list – there are a few which haven’t made it on this at the time of posting…

_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

Some of the data being output is:

This is for a brand new class created using the Demo class without any data assigned other than the name ( so it can be output ) which is _foo, the variable name I used…

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

And this is after assigning all of _foo properties ( except the name ) the following values in the same order: ‘string ‘, 1.0, True, 9, 10, False

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

Note that because of restricted data-types or value restrictions, some data wasn’t assigned – this is by design. The setter prohibits bad data-types or values from being assigned, even from being assigned as a default value ( unless you override the default value protection behavior )

The code hasn’t been posted here because I didn’t have room after the examples and explanations… Also because it will change.

Please Note: at the time of this posting, the file is messy – this will change. But, if you run it in Sublime Text and compile it, or run it from Python, it will compile and spit out a ton of information – the AccessorDB portion isn’t done ( which will be used to update the Print Getters and GetKeyOutput helper functions along with being changed to an Instance function, probably put into a single function and renamed – look for it.. )

Next: Not everything is required for it to run – a lot of the commented stuff at the bottom is for more information used for debugging – it may not be there when you download it. If it is, you should be able to uncomment and recompile to get more information.

I am looking for a work-around to needing MyClassBase: pass, MyClass( MyClassBase ): … – if you know of a solution – post it.

The only thing necessary in the class are the __ lines – the str is for debugging as is the init – they can be removed from the Demo Class but you will need to comment out or remove some of the lines below ( _foo / 2 / 3 )..

The String, Dict, and Util classes at the top are a part of my Python library – they are not complete. I copied over a few things I needed from the library, and I created a few new ones. The full code will link to the complete library and will include it along with providing updated calls and removing the code ( actually, the only code left will be the Demo Class and the print statements – the AccessorFunc system will be moved to the library )…

Part of file:

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

This beauty makes it incredibly easy to create new classes with dynamically added properties with AccessorFuncs / callbacks / data-type / value enforcement, etc.

For now, the link is at ( This link should reflect changes to the document. ): https://www.dropbox.com/s/6gzi44i7dh58v61/dynamic_properties_accessorfuncs_and_more.py?dl=0

Also: If you don’t use Sublime Text, I recommend it over Notepad++, Atom, Visual Code, and others because of proper threading implementations making it much, much faster to use… I am also working on an IDE-like code mapping system for it – take a look at: https://bitbucket.org/Acecool/acecoolcodemappingsystem/src/master/ ( Add Repo in Package Manager first, then Install Plugin – when version 1.0.0 is ready, I’ll add it to the main plugin list… )

I hope this solution helps… and, as always:

Just because it works, doesn’t make it right – Josh ‘Acecool’ Moser