这个
@callable
decorator语法确实是
def
功能和
class
类语句。然而,这只是
语法甜头
.
语法
@name(arguments)
def functionname(...):
# ...
转换为:
def functionname(...):
# ...
functionname = name(arguments)(functionname)
也就是说,由
@[decorator]
调用并将结果分配回函数名(或类名,如果应用于
班
声明)。
始终可以直接调用decorator,并分配返回值:
id = persisted_property(id=true)(Column(Integer, primaryKey=True, nullable=False))
但是,装饰器不能访问在其中构建对象的名称空间!一具尸体
班
语句的执行就像它是一个函数(尽管具有不同的作用域规则),并使用生成的本地命名空间生成类属性。decorator只是这个上下文中的另一个函数调用,而类主体的本地命名空间并不意味着可用。
接下来,我甚至没有开始建立你的
建造者模式
. 这是一种Java模式,其中强制执行类隐私和不可更改性,从而破坏动态语言模式。Python不是Java,不要试图把它变成Java。例如,您不能真正使Python类的实例不可变,这不是动态语言所允许的。此外,Builder模式是一个在Python中不存在的问题的解决方案,在那里你可以建立你的参数来构造一个前面的类,例如,字典,然后动态地应用到类调用,而Java没有这样的动态调用支持。
您不需要使用decorator模式来标记模式属性
无论如何
. 你应该依靠sqlacalchemy自己的
introspection support
:
from sqlalchemy.inspection import inspect
class Builder:
def __init__(self, cls, existing=None, **attrs):
self.cls = cls
if existing is not None:
assert isinstance(existing, cls)
existing_attrs = {n: s.value for n, s in inspect(existing).attrs.items()}
# keyword arguments override existing attribute values
attrs = {**existing_attrs, **attrs}
self.attrs = attrs
def _create_attr_setter(self, attrname):
# create a bound attribute setter for the given attribute name
def attr_setter(self, value):
if attrname in self.attrs:
raise ValueError(f"{attrname} already has a value set")
return type(self)(self.cls, **self.attrs, **{attrname: value})
attr_setter.__name__ = f'set_{attrname}'
return attr_setter.__get__(self, type(self))
def __getattr__(self, name):
if name.startswith('set_'):
attrname = name[4:]
mapper = inspect(self.cls)
# valid SQLAlchemy descriptor name on the class?
if attrname in mapper.attrs:
return self._create_attr_setter(attrname)
raise AttributeError(name)
def build(self):
return self.cls(**self.attrs)
class BuilderMixin:
@classmethod
def builder(cls, existing=None):
return Builder(cls, existing)
然后就用
BuilderMixin
作为混合类:
>>> from sqlalchemy.ext.declarative import declarative_base
>>> from sqlalchemy import Column, Integer, String
>>> Base = declarative_base()
>>> class Foo(Base, BuilderMixin):
... __tablename__ = 'foo'
... id = Column(Integer, primary_key=True, nullable=False)
... text = Column(String(100))
... created_by = Column(Integer)
...
>>> Foo.builder().set_text('Demonstration text').set_created_by(1).build()
<__main__.Foo object at 0x10f8314a8>
>>> _.text, _.created_by
('Demonstration text', 1)
您可以将其他信息附加到
info
词典:
text = Column(String(100), info={'mutable': True})
然后您的构建器代码可以通过映射器(例如
mapper.attrs['text'].info.get('mutable', False)
)
但是,不要重新创建Java Builder模式,只需构造
attrs
直接使用字典,最多使用
hybrid property
或与
ORM events
.