【Python】getattr和setattr的源码分析及使用

前言

鄙人有次在使用SQLALchemy的时候,对查询出来的对象,进行获取/重新赋值产生了点小问题

下面来一起看看这个小问题:

from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.dialects.mysql import TINYINT, INTEGER, VARCHAR, TEXT, DATE, DATETIME
from sqlalchemy import create_engine, Column

uri = "mysql+pymysql://root:@127.0.0.1:3306/test?charset=utf8mb4"
Base = declarative_base()
engine = create_engine(uri, pool_pre_ping=True, echo=True)
Session = sessionmaker(bind=engine)
Base = declarative_base()
session = Session()


class Student(Base):
    __tablename__ = "tStudent"
    id = Column(INTEGER, autoincrement=True, primary_key=True)
    nValid = Column(INTEGER, comment="1-有效;2- 无效", nullable=False, default=1)
    sName = Column(VARCHAR(100), comment="学生姓名", nullable=False)
    nAge = Column(INTEGER, comment="年龄")
    sCnDesc = Column(TEXT)
    sEnDesc = Column(TEXT)
    
student_a = Student()
student_a.id = 23
student_a.nValid = 1
student_a.sName = "James"
student_a.nAge = 35
student_a.sCnDesc = "大家好,我叫詹姆斯!"
student_a.sEnDesc = "Hello everyone, My name is James!"

session.add(student)
session.commit()

鄙人开发中遇到一个这样的使用:
当我通过sqlalchemy查询数据,而且是使用.all()来查询的时候,
返回的是一个list,且里面的每一个元素都是一个Object;

而此时我想要预先设置好一个list/set来存这些字段,
然后获取的时候通过遍历来获取,心里想:这样不就是解决我的问题了吗,这能有多难?

然后操作就是这样写:

res = session.query(Student).all()
# 比如,要获取属性id、sName、nAge:
keys = ["id", "sName", "nAge"]
for one in res:
    for k in keys:
        print(f"属性:{k} 对应的值为:{one.k}")

现在请你们来猜测一下这个使用对不对?或者输出结果是什么?你们先想一下结果再往下看…

此时运行将会得到下面的错误,是不是很惊喜?嗯哼?啥玩意啊?

Traceback (most recent call last):
  File "E:/projects/python/daily/temp.py", line 208, in <module>
    print(f"属性:{k} 对应的值为:{one.k}")
AttributeError: 'Student' object has no attribute 'k'

看了一下,没有属性 k,这student对象的确没有属性 k啊,我的天,那我得怎么用?

然后这时候如果你使用 getattr的话,这就很容易解决你这种需求,下面来分析一下源码:
这两个作为Python的内置属性,下面来分析一下源码:

def getattr(object, name, default=None): # known special case of getattr
    """
    getattr(object, name[, default]) -> value
    
    Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
    When a default argument is given, it is returned when the attribute doesn't
    exist; without it, an exception is raised in that case.
    """
    pass

    
def setattr(x, y, v): # real signature unknown; restored from __doc__
    """
    Sets the named attribute on the given object to the specified value.
    
    setattr(x, 'y', v) is equivalent to ``x.y = v''
    """
    pass

从上面的源码可以分析出来 getattr就是从一个对象从获取你想要的属性,使用格式是:

  • getattr(对象, 你要获取的属性)

那么我这个例子里面的用法就是:

res = session.query(Student).all()
# 比如,要获取属性id、sName、nAge:
keys = ["id", "sName", "nAge"]
for one in res:
    for k in keys:
        # one.k 改为 getattr(one, k) 即可获取对应的属性
        print(f"属性:{k} 对应的值为:{getattr(one, k)}")

>>>
	属性:id 对应的值为:23
	属性:sName 对应的值为:James
	属性:nAge 对应的值为:35
  • setattr的使用格式是:setattr(对象, 需要设置的属性, 设置的内容)
    请看下面栗子:
res = session.query(Student).all()
# 比如,要获取属性id、sName、nAge:
keys = ["id", "sName", "nAge"]
for one in res:
    print("修改前:id:{} sName:{} nAge:{}".format(one.id, one.sName, one.nAge))
    setattr(one, "id", 24)
    setattr(one, "sName", "Kobe Bean Bryant")
    setattr(one, "nAge", 42)
    session.commit()
    print("修改后:id:{} sName:{} nAge:{}".format(one.id, one.sName, one.nAge))
    break

>>>
	修改前:id:23 sName:James nAge:35
	修改后:id:24 sName:Kobe Bean Bryant nAge:42

可以再次通过上面的getattr使用来查询一遍数据库,即可验证刚刚的用法对不对

同时,官方还指出:setattr(x, 'y', v)是等价于x.y = v,笔者通过分析,这个用法其实也可以对这个x对象进行添加另外一个新的属性y

下面这个例子是给对象增加一个school属性:

setattr(student_a, "school", "Beijing University")
print(student_a.schole)

>>> 
	Beijing University

小教程有用的话,点个赞吧
谢谢大家,我系渣渣辉

EOF

猜你喜欢

转载自blog.csdn.net/weixin_41173374/article/details/105788989