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
banxi1988
V2EX  ›  Python

目前不习惯Python不能重载构造函数的问题

  •  
  •   banxi1988 ·
    banxi1988 · 2013-07-08 15:51:23 +08:00 · 11046 次点击
    这是一个创建于 4162 天前的主题,其中的信息可能已经有所发展或是发生改变。
    一般来说这不是问题。
    Python有魔法的*args和**kwargs。
    我的问题来自于,
    我有一些Model类。
    有时候它需要使用dict来创建。如从request.form之类。
    有时候自己手动写参数创建。
    当从request.form创建的时候,
    我希望构造函数是这样的:
    (1)使用字典作为参数
    def __init__(self,form):
    if not isinstance(form,dict):
    continue
    pass

    但是当我自己手动传参数时,我希望它是这样的:
    (2)使用关键词参数。
    def __init__(self,**values):
    pass



    在我没有找到好的解决方法之前:
    我是使用第二种形式的。如果是处理form的话我就
    Model(**form.to_dict())

    这个**这种魔法看起来不是很好,折包又打包(指实参数的**kw和形参的**kw)
    而且像我一般都有一个ModelMixin来处理
    从dict到model对象赋值的通用方法:
    def _init_inner(self, **params):
    if not isinstance(params, dict):
    return
    for col in self.__table__.columns:
    name = col.name
    # 不设置键值,和密码(要做特别的处理)
    if name in ('id', 'password',) or '_id' in name:
    continue
    value = params.get(name)
    if value:
    if isinstance(col.type, db.Integer):
    value = int(value)
    elif isinstance(col.type, db.Boolean):
    value = bool(value)
    setattr(self, name, value)
    这样的话,
    __init__()
    里面还需要再一次的
    self._init_inner(**kw)

    这样经过多次的打包折包我觉得需要改改了。
    求指导。
    大家的model实例化是怎么做的呢?
    7 条回复    1970-01-01 08:00:00 +08:00
    timonwong
        1
    timonwong  
       2013-07-08 16:10:20 +08:00   ❤️ 1
    # 非要如此的话:

    class Model(object):
    def __init__(self, *args, **kwargs):
    if args:
    assert len(args) == 1
    assert isinstance(args[0], dict)
    self._init_models(args[0])
    else:
    self._init_models(kwargs)

    def _init_models(self, model_dict):
    # YOUR LOGIC
    pass
    banxi1988
        2
    banxi1988  
    OP
       2013-07-08 16:17:27 +08:00
    @timonwong 嗯,看起来不错。多谢
    binux
        3
    binux  
       2013-07-08 16:18:26 +08:00   ❤️ 1
    这是应该你自己判断的
    如果调用Model(form={a:1}),你的意思是调用__init__(self,form)呢,还是调用__init__(self,**values) ?
    banxi1988
        4
    banxi1988  
    OP
       2013-07-08 16:43:41 +08:00
    @binux 其实就是,
    手动的时候,Model(name='wowow',age=12)这样简单明了,
    但是从form中构造的话,
    使用Model(form)比较直接。
    Xe0n0
        5
    Xe0n0  
       2013-07-08 17:26:37 +08:00   ❤️ 1
    重新写个 dict_to_model 不就可以了,比如类方法。构造函数一般是为了处理构造时必须要初始化的东西,比如 C++ 中分配内存,子对象之类。这部分任务在 Python 中相对较少。

    C++ 中的那种重载后变成实际上调用不同函数的行为在 Python 是不存在的。一部分原因是没有静态类型,一部分用简单的默认参数和 args, kwargs 就可以解决。楼上说的也就是手动实现了一遍类型检查而已。

    完全不需要生硬寻找相同的实现方式。
    banxi1988
        6
    banxi1988  
    OP
       2013-07-08 17:36:58 +08:00
    @Xe0n0 有道理。
    Python中也可以使用这种工厂方法的模式。SQLAlchemy的字段是类级别的。。
    用类方法也不错。谢谢了。
    banxi1988
        7
    banxi1988  
    OP
       2013-07-08 18:39:24 +08:00
    @timonwong
    突然想起来,Python中的dict就有类似的构造器。
    dict() -> new empty dictionary
    dict(mapping) -> new dictionary initialized from a mapping object's
    (key, value) pairs
    dict(iterable) -> new dictionary initialized as if via:
    d = {}
    for k, v in iterable:
    d[k] = v
    dict(**kwargs) -> new dictionary initialized with the name=value pairs
    in the keyword argument list. For example: dict(one=1, two=2)



    @Xe0n0 感觉使用默认的构造方法如dict中使用的,感觉更自然点呢?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2858 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 06:38 · PVG 14:38 · LAX 22:38 · JFK 01:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.