我是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属性进行交互
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);
}
}
}
可以这样做吗?
答案 0 :(得分:1)
没有简单的方法可以用属性做你想做的事。您不能简单地设置属性或从属性保护的项中获取属性。
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
或其他内容中检索。
答案 1 :(得分:0)
好的,我在第一次使用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))
输出结果为:
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