はじめに
flask_sqlalchemyのチュートリアルをやっていたらコンストラクタの記述でちょっと気になったので調べてみた。
コード
これが今回テストに使うコード。これを実行すると、pythonファイルと同階層に"TestPerson.db"というsqliteデータベースができる。
from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///TestPerson.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['SQLALCHEMY_ECHO'] = False db = SQLAlchemy(app) class Person(db.Model): __tablename__ = 'person' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.Text) age = db.Column(db.Integer) def __init__(self, name, age): self.name = name self.age = age if __name__ == '__main__': db.create_all() man1 = Person('john', 29) man2 = Person('adam', 19) man3 = Person('David', 55) db.session.add(man1) db.session.add(man2) db.session.add(man3) db.session.commit()
データベースの中身を確認すると
id | name | age |
---|---|---|
1 | john | 29 |
2 | adam | 19 |
3 | David | 55 |
こうなってる。
気になった個所
Personクラスのコンストラクタ(init)の部分ってどう解釈すればいい?
class Person(db.Model): __tablename__ = 'person' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.Text) age = db.Column(db.Integer) def __init__(self, name, age): # ここが凄い気になる self.name = name self.age = age
ほかのチュートリアル見るとコンストラクタを書かないパターンもあった。
name = db.Column(db.Text), age = db.Column(db.Integer)
はクラス変数として定義されている。よってコンストラクタを書かなければ、
man1 = Person(name='john', age = 29)
でクラス変数に値が入るはず。ところがコンストラクタでインスタンス変数self.name, self.age
を定義しているため、man1 = Person(name='john', age = 29)
でインスタンス変数に値が入ってしまう。これはSQLAlchemyの処理的に問題ないのか?
このへんに関してはSQLAlchemy公式サイトにちらっと記載があった。
公式サイトの説明
以下公式サイトから抜粋
from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db' db = SQLAlchemy(app) class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) def __repr__(self): return '<User %r>' % self.username
Note how we never defined a __init__ method on the User class? That’s because SQLAlchemy adds an implicit constructor to all model classes which accepts keyword arguments for all its columns and relationships. If you decide to override the constructor for any reason, make sure to keep accepting **kwargs and call the super constructor with those **kwargs to preserve this behavior:
class Foo(db.Model): # ... def __init__(self, **kwargs): super(Foo, self).__init__(**kwargs) # do custom stuff