__str__() 实现的正确自动生成也适用于 sqlalchemy 类? [英] Proper autogenerate of __str__() implementation also for sqlalchemy classes?

查看:15
本文介绍了__str__() 实现的正确自动生成也适用于 sqlalchemy 类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想显示/打印干净整洁的 sqlalchemy 类.

是否有一种在 python 中自动生成 __str__() 实现的方法? 答案 您可以使用 vars、dir、...:... 来迭代实例属性简单类的情况.

当我尝试将其应用于 Sqlalchemy 类时(例如 Python 的 SQLAlchemy 的介绍性教程 - 见下文),我得到 - 除了成员变量之外,还有以下条目作为成员变量:

_sa_instance_state=

如何避免此条目出现在 __str__ 表示中?

为了完整起见,我也将链接的stackoverflow问题的解决方案放在下面.

导入操作系统导入系统从 sqlalchemy 导入列、外键、整数、字符串从 sqlalchemy.ext.declarative 导入 declarative_base来自 sqlalchemy.orm 的导入关系从 sqlalchemy 导入 create_engineBase = declarative_base()类人(基础):__表名__ = '人'# 这里我们定义了表person的列# 注意每一列也是一个普通的 Python 实例属性.id = 列(整数,primary_key=True)名称 = 列(字符串(250),可为空=假)

如前所述,这是 有没有办法在 python 中自动生成 __str__() 实现?:

def auto_str(cls):def __str__(self):返回 '​​%s(%s)' % (type(self).__name__,', '.join('%s=%s' % item for item in vars(self).items()))cls.__str__ = __str__返回 cls@auto_str类 Foo(对象):def __init__(self, value_1, value_2):self.attribute_1 = value_1self.attribute_2 = value_2

已应用:

<预><代码>>>>str(Foo('bar', 'ping'))'Foo(attribute_2=ping,attribute_1=bar)'

解决方案

这是我使用的:

def todict(obj):""" 返回对象的字典,不包括私有属性,sqlalchemy 状态和关系属性."""排除 = ('_sa_adapter', '_sa_instance_state')返回 {k: v for k, v in vars(obj).items() 如果不是 k.startswith('_') 和不是任何(hasattr(v, a) for a in excl)}班级基础:def __repr__(self):params = ', '.join(f'{k}={v}' for k, v in todict(self).items())返回 f"{self.__class__.__name__}({params})"Base = declarative_base(cls=Base)

任何从 Base 继承的模型都将定义默认的 __repr__() 方法,如果我需要做一些不同的事情,我可以覆盖该特定类上的方法.

它不包括任何用前导下划线表示的私有属性的值、SQLAlchemy 实例状态对象以及字符串中的任何关系属性.我排除了关系属性,因为我通常不希望 repr 导致延迟加载的关系,并且关系是双向的,包括关系属性会导致无限递归.

结果如下:ClassName(attr=val, ...).

--编辑--

我上面提到的 todict() func 是一个帮助程序,我经常调用它从 SQLA 对象中构造一个 dict,主要用于序列化.我在这种情况下懒惰地使用它,但它不是很有效,因为它正在构建一个 dict(在 todict() 中)来构建一个 dict (在 __repr__() 中).我已经修改了模式以调用生成器:

def keyvalgen(obj):"""生成属性名/值对,过滤掉SQLA属性."""排除 = ('_sa_adapter', '_sa_instance_state')对于 vars(obj).items() 中的 k, v:如果不是 k.startswith('_') 并且不是 any(hasattr(v, a) for a in excl):产量 k, v

然后基础 Base 看起来像这样:

类基础:def __repr__(self):params = ', '.join(f'{k}={v}' for k, v in keyvalgen(self))返回 f"{self.__class__.__name__}({params})"

todict() func 也利用了 keyvalgen() 生成器,但不再需要构建 repr.

I would like to display / print my sqlalchemy classes nice and clean.

In Is there a way to auto generate a __str__() implementation in python? the answer You can iterate instance attributes using vars, dir, ...:... helps in the case of simple classes.

When I try to apply it to a Sqlalchemy class (like the one from Introductory Tutorial of Python’s SQLAlchemy - see below), I get - apart from the member variables also the following entry as a member variable:

_sa_instance_state=<sqlalchemy.orm.state.InstanceState object at 0x000000004CEBCC0>

How can I avoid that this entry appears in the __str__ representation?

For the sake of completeness, I put the solution of the linked stackoverflow question below, too.

import os
import sys
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy import create_engine

Base = declarative_base()

class Person(Base):
    __tablename__ = 'person'
    # Here we define columns for the table person
    # Notice that each column is also a normal Python instance attribute.
    id = Column(Integer, primary_key=True)
    name = Column(String(250), nullable=False)

As mentioned, this is the solution from Is there a way to auto generate a __str__() implementation in python?:

def auto_str(cls):
    def __str__(self):
        return '%s(%s)' % (
            type(self).__name__,
            ', '.join('%s=%s' % item for item in vars(self).items())
        )
    cls.__str__ = __str__
    return cls

@auto_str
class Foo(object):
    def __init__(self, value_1, value_2):
        self.attribute_1 = value_1
         self.attribute_2 = value_2

Applied:

>>> str(Foo('bar', 'ping'))
'Foo(attribute_2=ping, attribute_1=bar)'

解决方案

This is what I use:

def todict(obj):
    """ Return the object's dict excluding private attributes, 
    sqlalchemy state and relationship attributes.
    """
    excl = ('_sa_adapter', '_sa_instance_state')
    return {k: v for k, v in vars(obj).items() if not k.startswith('_') and
            not any(hasattr(v, a) for a in excl)}

class Base:

    def __repr__(self):
        params = ', '.join(f'{k}={v}' for k, v in todict(self).items())
        return f"{self.__class__.__name__}({params})"

Base = declarative_base(cls=Base)

Any models that inherit from Base will have the default __repr__() method defined and if I need to do something different I can just override the method on that particular class.

It excludes the value of any private attributes denoted with a leading underscore, the SQLAlchemy instance state object, and any relationship attributes from the string. I exclude the relationship attributes as I most often don't want the repr to cause a relationship to lazy load, and where the relationship is bi-directional, including relationship attribs can cause infinite recursion.

The result looks like: ClassName(attr=val, ...).

--EDIT--

The todict() func that I mention above is a helper that I often call upon to construct a dict out of a SQLA object, mostly for serialisation. I was lazily using it in this context but it isn't very efficient as it's constructing a dict (in todict()) to construct a dict (in __repr__()). I've since modified the pattern to call upon a generator:

def keyvalgen(obj):
    """ Generate attr name/val pairs, filtering out SQLA attrs."""
    excl = ('_sa_adapter', '_sa_instance_state')
    for k, v in vars(obj).items():
        if not k.startswith('_') and not any(hasattr(v, a) for a in excl):
            yield k, v

Then the base Base looks like this:

class Base:

    def __repr__(self):
        params = ', '.join(f'{k}={v}' for k, v in keyvalgen(self))
        return f"{self.__class__.__name__}({params})"

The todict() func leverages off of the keyvalgen() generator as well but isn't needed to construct the repr anymore.

这篇关于__str__() 实现的正确自动生成也适用于 sqlalchemy 类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆