可以在属性上使用描述符来提供一些声明性信息吗?



我是Python的新手,所以如果我甚至没有使用正确的术语请原谅我…我正在使用Python 3.2,我正试图弄清楚我是否可以用一些声明式信息装饰类属性。

在我看来,它应该是这样的:

class MyTestClass:
    def __init__(self, foo):
        self.foo = foo
    @property
    @somedeclarativeInfo("ABC",123)
    def radius(self):
        return self.__foo
    @radius.setter
    def radius(self, foo):
        self.__foo = foo

然后我想用这个类做两件不同的事情:

A -能够与foo属性交互,就像任何其他属性(简单的get和sets)

B -能够动态地找到用这个描述符装饰的特定类的属性,并能够取出"ABC"和123值等。

我想也许我应该创建一个描述符来完成我想要的,但我不确定我是否在正确的轨道上,或者这是否可以完成。

因为我的背景是。net,所以我用了下面的例子来展示我想要做的事情,以防有助于任何人理解我的目标:

using System;
using System.Reflection;
namespace SampleWithProperties
{
    public class MyCustomAttribute : Attribute
    {
        public string Val1;
        public string Val2;
        public MyCustomAttribute(string val1,string val2)
        {
            Val2 = val2;
            Val1 = val1;
        }
    }
    public class Foo
    {
        [MyCustomAttribute("abc","def")]
        public string PropertyA { get; set; }
        [MyCustomAttribute("xyz","X")]
        public int PropertyB { get; set; }
        public string PropertyC { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            // Show that we can figure out which properties have the custom attribute,
            // and that we can get the values for Val1 and Val2
            foreach(PropertyInfo propertyInfo in typeof(Foo).GetProperties())
            {
                Console.WriteLine("Found a property named "+propertyInfo.Name);
                foreach(Attribute attribute in propertyInfo.GetCustomAttributes(
                    attributeType:typeof(MyCustomAttribute),inherit:true))
                {
                    Console.WriteLine("Found a MyCustomAttribute on the property.");
                    MyCustomAttribute myCustomAttribute = attribute as MyCustomAttribute;
                    Console.WriteLine("Val1 = " + myCustomAttribute.Val1);
                    Console.WriteLine("Val2 = " + myCustomAttribute.Val2);
                }
                Console.WriteLine();
            }
            // Show that the properties can be used like normal
            Foo foo = new Foo {PropertyA = "X", PropertyB = 2, PropertyC = "Z"};
            Console.WriteLine("Created an instance of Foo just for fun.  Its property values are "+
                foo.PropertyA+","+foo.PropertyB+","+foo.PropertyC);
        }
    }
}

这能做到吗?

没有一种简单的方法可以实现您想要的属性。你不能简单地设置属性或从受属性保护的项中获取属性。

def declarativeInfo(*args, **kwargs):
    def wrapper(obj):
        for arg in args:
            setattr(obj, arg, arg)
        for k, v in kwargs:
            setattr(obj, k, v)
        return obj
    return wrapper
class MyTestClass:
    def __init__(self, foo):
        print MyTestClass.__dict__
        self.radius = self.Radius('foo')
    @declarativeInfo(bar="ABC",baz=123)
    class Radius(object):
        def __init__(self, foo):
            self.value = foo
a = MyTestClass('foo')
print a.radius.value
print a.radius.a

是最简单的方法。当然,你总是可以使value成为一个属性。

如果你真的希望radius是一个正常的属性,你可以将信息存储在字典的其他地方,并从self.propdict或其他地方检索它

好吧,这个问题是我第一次开始使用Python时写的。我现在知道如何在Python中做我发布的。net示例代码所做的事情。当然,当我最初发布这个问题时,我没有意识到的最大的事情是描述符改变了你的属性/属性(无论你怎么称呼它们)的行为。尽管如此,我们仍然可以允许这些属性像属性一样发挥作用(而不改变它们的行为),同时用装饰器在它们上面添加一些元数据。我目前正在实现一些协议序列化/反序列化的东西,这将派上用场。

class MyCustomDescriptor:
    def __init__(self,val1,val2):d
        self._val1 = val1
        self._val2 = val2
    @property
    def val1(self): return self._val1
    @property
    def val2(self): return self._val2
    def __call__(self,decorated_method_reference):
        self._decorated_method_reference = decorated_method_reference
        return self
    def __get__(self,instance,type=None):
        if not instance:
            return self
        return self._decorated_method_reference(instance)
class Foo:
    def __init__(self,attribute_a_value,attribute_b_value,attribute_c_value):
        self._attribute_a_value = attribute_a_value
        self._attribute_b_value = attribute_b_value
        self._attribute_c_value = attribute_c_value
    @MyCustomDescriptor(val1="abc",val2="def")
    def attribute_a(self): return self._attribute_a_value
    @MyCustomDescriptor(val1="xyz",val2="X")
    def attribute_b(self): return self._attribute_b_value
    @property
    def attribute_c(self): return self._attribute_c_value
# Show that by inspecting class Foo we can figure out which attribute are marked with MyCustomDescriptor and that
# we can get the values for val1 and val2.  We don't even need an instance of Foo to do this.  The class itself is sufficient.
print("Inspecting class Foo.  Looking for attributes marked with MyCustomDescriptor...")
for attribute_name in dir(Foo):
    attribute_as_object = getattr(Foo,attribute_name)
    if type(attribute_as_object) == MyCustomDescriptor:
        print("attribute "+attribute_name+" is decorated with MyCustomDescriptor.  val1="+attribute_as_object.val1+" val2="+attribute_as_object.val2)
# Show that the properties on Foo work like normal properties.  Note that I skipped implementing setters but could have done so.
foo_instance = Foo(attribute_a_value="X",attribute_b_value=2,attribute_c_value="Z")
print("Created an instance of Foo just for fun.  It's property values are "+str(foo_instance.attribute_a)+", "+str(foo_instance.attribute_b)+", "+str(foo_instance.attribute_c))

输出为:

<>之前检查类Foo。寻找带有MyCustomDescriptor标记的属性…属性attribute_a用MyCustomDescriptor装饰。abc val2 val1 = = def属性attribute_b用MyCustomDescriptor装饰。val1 = xyz val2 = X创建Foo的一个实例只是为了好玩。它的属性值是X 2 Z

相关内容

最新更新