像Python描述符这样的D元编程?
我正在尝试将我的框架的一部分从Python翻译成D,并且正在努力解决一个细节:但首先我必须扩展范围。该组件类似于ORM。我的用户定义类,这些类的实例将在数据库中持久化。用户API应该尽可能简单。比如说像Python描述符这样的D元编程?,python,d,python-descriptors,Python,D,Python Descriptors,我正在尝试将我的框架的一部分从Python翻译成D,并且正在努力解决一个细节:但首先我必须扩展范围。该组件类似于ORM。我的用户定义类,这些类的实例将在数据库中持久化。用户API应该尽可能简单。比如说 class Person: identity _id, string name, date birthdate, ... class Car: indentity _id, string ident, int power, Person owner ...
class Person:
identity _id,
string name,
date birthdate,
...
class Car:
indentity _id,
string ident,
int power,
Person owner
...
myCar = Car.load(ident="DEAD-BEAF")
print myCar.power
print myCar.owner.name
load函数从数据库加载实例数据。但是车主的加载应该推迟到实例被使用之后,因为大多数应用程序都在汽车上工作,车主很少被使用
在Python中,我可以使用。我有一组“字段”类,它们是描述符。比如说
class StringField(object):
def __get__(self,obj,objtype):
# get the value from obj
def __set__(self,obj,value):
# set value in obj
EntityClass有一个适当的元类,用于连接所需的连接。用户在Python中定义:
class Person(EntityClass):
name = StringField()
birthdate = DateField()
...
class Car(EntityClass):
ident = StringField()
power = IntField()
owner = RelationField(Person)
...
并使用以下类:
myCar = Car.load(ident="DEAD-BEAF")
print myCar.power (#1)
print myCar.owner.name (#2)
引擎盖下对myCar.power的调用扩展到
Car.power.__get__(myCar,Car)
如果我从数据库加载汽车,我只加载车主Id
所有者
我可以从数据库中加载Person实例
class RelationField(object):
def __get__(self,obj,objtype):
if not instance in obj.cache:
load instance
add instance to obj.cache
return instance from obj.cache
将ORM转换为D我尝试了不同的实现。对于简单的基类型,将用户定义属性(UDA)与模板和统一调用语法结合使用非常简单:
struct Persistent {};
save(T)(ref T obj)
{
...
}
T load(T)(...)
class Person
{
@Persistent string name;
@Persistent Date birthday;
...
}
class Car
{
@Persistent string ident;
@Persistent int power;
@Persistent Person owner; //???
...
}
auto myCar = load!Car(...);
writeln(myCar.power);
writeln(myCar.owner.name)
这个API和Python API一样简单,但我不知道如何实现所有者的延迟加载。我需要的是用属性函数替换所有者成员,但我不知道如何使用编译时元编程实现这一点。那么这是怎么做到的呢?或者有一种惯用的方法吗?您可以使用。属性名称在编译时可用,因此您可以使用通用代码处理它们,也可以像下面的代码一样,在模板
行之后使用if
,创建专门化
struct-Person{
int-id;
字符串名;
}
Person[int]Person\u by\u id;
结构车{
int-id;
整数幂;
int所有者id;
// https://dlang.org/spec/operatoroverloading.html#dispatch
模板opDispatch(字符串属性)
如果(属性=“所有者”)
{
@property ref Person opDispatch(){
按身份返回人员[所有者身份];
}
}
}
void main(){
自动p=人(1,“乔”);
个人身份证[p.id]=p;
汽车c=汽车(123900,1);
断言(c.owner.name==“Joe”);
c、 owner.name=“普通乔”;
断言(person_by_id[1]。name==“Average Joe”);
}
opDispatch
模板可以由mixin模板生成,因此用户应该编写如下内容:
struct-Car{
int-id;
整数幂;
int所有者id;
混合addMyHandlers!汽车;
}
这里,addMyHandler
mixin模板应该使用传入结构的内省生成上面的opDispatch
函数。如果希望保持结构整洁,可以在结构外部生成函数,并利用统一函数调用语法(UFCS):
struct-Car{
int-id;
整数幂;
int所有者id;
}
@财产参考人所有者(施工参考车){
按身份证返回人员[汽车车主身份证];
}
此
owner
函数也可以使用mixin模板生成,使用Car
上的内省来调查要生成的内容。(与您的python代码类似。)我想您可以创建一个Deferred
模板,用它包装Person
。在那里,您可以创建一个加载它的get
函数,并使用alias get this
,这样您就可以编写owner.xyz
,而不是owner.get.xyz
。我试过了,但我也想设置值,因此必须能够编写myCar.owner=new owner(…)代码>。因此,我需要为get和set使用别名this。如果模板实例化到一个结构中而不是类中,您应该能够重写opAssign,尽管我不知道别名this是否适用于结构。非常感谢,将结构模板与alias this
和opAssign
配合使用效果很好。
struct Persistent {};
save(T)(ref T obj)
{
...
}
T load(T)(...)
class Person
{
@Persistent string name;
@Persistent Date birthday;
...
}
class Car
{
@Persistent string ident;
@Persistent int power;
@Persistent Person owner; //???
...
}
auto myCar = load!Car(...);
writeln(myCar.power);
writeln(myCar.owner.name)