V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
woshicai
V2EX  ›  Python

新人求助, 为什么实例属性没有覆盖类属性

  •  
  •   woshicai · 2016-10-31 20:58:17 +08:00 · 2634 次点击
    这是一个创建于 2977 天前的主题,其中的信息可能已经有所发展或是发生改变。
    # lz 最近看廖雪峰的 python3 教程实战, 写代码时遇到一个问题, 此为背景
    暂时只贴部分代码,其余部分代码放在 github 上:
    https://github.com/hfutcbl/python-liaoxuefeng_practice/tree/master/aiohttpPractice

    python 版本:
    python3 --version
    Python 3.5.2

    代码:
    类的代码
    class User(Model):
    __table__ = 'users'

    id = StringField(primary_key=True, default=next_id, ddl='varchar(50)')
    email = StringField(ddl='varchar(50)')
    passwd = StringField(ddl='varchar(50)')
    admin = BooleanField()
    name = StringField(ddl='varchar(50)')
    image = StringField(ddl='varchar(500)')
    created_at = FloatField(default=time.time)
    调用代码
    u = User(name='Test1', email='[email protected]', passwd='1234567890', image='about:blank')
    ......
    def getValueOrDefault(self, key):
    print('email:%s, passwd:%s, name:%s, image:%s' % (self['email'], self['passwd'], self['name'], self['image']))
    print(self.email, self.passwd, self.name, self.image, '\n','self:', self)

    结果:
    email:[email protected], passwd:1234567890, name:Test1, image:about:blank
    [email protected] <StringField, varchar(50):None> <StringField, varchar(50):None> <StringField, varchar(500):None>
    self: {'email': '[email protected]', 'name': 'Test1', 'image': 'about:blank', 'passwd': '1234567890'}

    用 self[key] 访问可以正常获取数据,但用 self.key 只能获得传入的 4 个参数中的其中一个正确数据,比如这次是 email ,每次运行能够获取正确数据的 key 值不一样,运行多次亲测:
    email:[email protected], passwd:1234567890, name:Test1, image:about:blank
    <StringField, varchar(50):None> 1234567890 <StringField, varchar(50):None> <StringField, varchar(500):None>
    self: {'passwd': '1234567890', 'email': '[email protected]', 'image': 'about:blank', 'name': 'Test1'}

    有知道的大神能解答下吗?
    10 条回复    2016-11-01 17:39:52 +08:00
    woshicai
        1
    woshicai  
    OP
       2016-10-31 23:23:50 +08:00
    自顶一记
    没人不开心
    GreatMartial
        2
    GreatMartial  
       2016-11-01 00:28:48 +08:00 via Android
    不看你的代码,就看你的标题。
    实例属性的查询方式是:先查询实例的属性,如果没有查询到,才会向类里查询相应的属性。
    我是小白,可能说的不严谨。
    这个知识点我是在博客园里,有一篇专门讲类与实例属性继承的文章里学习到的
    cheetah
        3
    cheetah  
       2016-11-01 00:43:48 +08:00
    这代码格式没法看啊
    Trim21
        4
    Trim21  
       2016-11-01 00:52:04 +08:00 via Android
    问题抽象了,同时把代码也抽象一下吧。。。
    woshicai
        5
    woshicai  
    OP
       2016-11-01 08:25:55 +08:00
    @GreatMartial 是啊 print(self)可以看到实例的属性是我初始化实例的数据 但是用 self.key 访问到的确实类的属性
    @cheetah v 站貌似不支持 markdown
    @Trim21

    好吧,把问题抽象一下。
    简单的说就是我想获取 self 的属性, 用 self[key]能够正常获取我传入的数据, self.key 会出现异常(会返回类的 key 属性 default 值), print(self)显示实例的 key 值对应的是我传入的数据, 所以有疑惑。 想知道 self[key]和 self.key 的区别,为什么返回的结果不一样。
    slideclick
        6
    slideclick  
       2016-11-01 09:06:14 +08:00
    self.key 是标准获得实例属性的 python 语法。除非实例里面没有,才会去读类级别变量。至于 self[key]为什么可以,那个是 Django 框架设计的,不是 python 语法
    woshicai
        7
    woshicai  
    OP
       2016-11-01 09:36:35 +08:00
    @slideclick 感谢解答。
    尴尬的是我用的不是 Django 框架, 前面没说清楚, 我是让类 User 是继承 dict 类, 所以 self[key]的方式是可以的。
    而且 print(self)打印出来的就是一个 dict :
    self: {'email': '[email protected]', 'name': 'Test1', 'image': 'about:blank', 'passwd': '1234567890'}
    focusheart
        8
    focusheart  
       2016-11-01 10:24:49 +08:00
    https://github.com/hfutcbl/python-liaoxuefeng_practice/blob/master/aiohttpPractice/orm.py
    检查一下 orm.py 里对于 Model 类的构造:

    class Model(dict, metaclass=ModelMetaclass):

    def __init__(self, **kw):
    super(Model, self).__init__(**kw)

    相当于调用的 dict 的构造, dict 的构造里没有将 key 直接转为 instance property 的默认行为吧?不过 ModelMetaclass 的__new__ 里可以处理吧。
    另外,一般习惯上,对于这样使用 orm 的,用 instance[key] 的方式比较普遍吧。
    woshicai
        9
    woshicai  
    OP
       2016-11-01 11:41:04 +08:00
    @focusheart
    非常感谢回答, 终于明白 self.key 为什么不行了。在 ModelMetaclass 的 __new__函数里没有确实没有将 key 处理为 instance property 。
    但是还是有个问题:并不是所有 self.key 打印出来的值都是类中定义的 default 值,见输出:

    [email protected] <StringField, varchar(50):None> <StringField, varchar(50):None> <StringField, varchar(500):None>

    还有个问题:
    最初我是用 getattr(self, key, None) 来获取属性,
    class Model:
    ......
    def __getattr__(self, key):
    try:
    return self[key]
    print('-------\n getattr() called \n-------------')
    ......
    发现 getattr 每次运行只被调用一次(我期待调用次数和 key 的个数一样),想知道 getattr 的调用顺序。
    谢谢各位大神。
    slideclick
        10
    slideclick  
       2016-11-01 17:39:52 +08:00
    __getattr__(self, name)
    Called only when an attempt to retrieve the named attribute fails, after the obj,
    Class and its superclasses are searched. The expressions obj.no_such_attr, get
    attr(obj, 'no_such_attr') and hasattr(obj, 'no_such_attr') may trigger
    Class.__getattr__(obj, 'no_such_attr'), but only if an attribute by that name
    cannot be found in obj or in Class and its superclasses.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2508 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 15:53 · PVG 23:53 · LAX 07:53 · JFK 10:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.