描述符可以用于属性以提供一些声明性信息吗?

2024-09-29 23:23:33 发布

您现在位置:Python中文网/ 问答频道 /正文

我是Python新手,所以请原谅我没有使用正确的术语。。。我使用的是python3.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和set)

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

这能做到吗?你知道吗


Tags: selfgetstring属性foodefpropertypublic
2条回答

没有简单的方法来处理属性。不能简单地对受属性保护的项设置属性或从中获取属性。你知道吗

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成为一个普通属性,您可以将信息存储在dict的其他地方,并从self.propdict或其他地方检索它。你知道吗

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

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

输出为:

Inspecting class Foo.  
Looking for attributes marked with MyCustomDescriptor...
attribute attribute_a is decorated with MyCustomDescriptor.  
val1=abc val2=def
attribute attribute_b is decorated with MyCustomDescriptor.  
val1=xyz val2=X
Created an instance of Foo just for fun.  
It's property values are X, 2, Z

相关问题 更多 >

    热门问题