質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

5754閲覧

エラーになる理由を知りたい

gori

総合スコア17

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2017/07/17 13:09

編集2017/07/17 13:52

###前提・実現したいこと
https://github.com/appdamacy/Grape

上記ソースコードで
return template('index', row=row)となっている箇所を
return template('index', row)とした場合にエラーになる理由を知りたいです。
row=rowとすることでどういった処理が行われているのでしょうか。

###発生している問題・エラーメッセージ

ValueError('dictionary update sequence element #0 has length 4; 2 is required',)

###該当のソースコード

import sqlite3 import feedparser from bottle import route, run, template, static_file, debug debug(True) @route('/static/<filepath:path>') def static(filepath): return static_file(filepath, root="./static") @route('/hello') def hello(): con = sqlite3.connect('grape.db') c = con.cursor() c.execute("create table if not exists item (title, link, summary, updated)") url = [ "https://lineblog.me/sakuraihinako/atom.xml", "https://lineblog.me/masuwakatsubasa/atom.xml", "https://lineblog.me/funayamakumiko/atom.xml" ] feed = [] for rss in url: feed.extend(feedparser.parse(rss).entries) for item in feed: title = item.title link = item.link summary = item.summary updated = item.updated c.execute('INSERT INTO item VALUES (?, ?, ?, ?)', (title, link, summary, updated)) c.execute(u"select * from item order by updated desc") row = [] for item in c: row.append({ "title": item[0], "link": item[1], "summary": item[2], "updated": item[3] }) c.close() return template('index', row) run(host='localhost', port=8080) ``` ###試したこと

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

quickquip

2017/07/17 13:44

pythonのコードはインデントがないと意味が取れないので、前後行を ``` で括って正しく表示されるようにした方がいいですよ。
guest

回答3

0

ベストアンサー

Python では関数に渡す引数として、位置引数 と キーワード引数 の2種類があります。参考:argument — Python 3.6.1 ドキュメント

row と値だけ渡すのが位置引数、 row=row とキーを指定するのがキーワード引数です。

キーワード引数は、デフォルト値を持った位置引数の一部を飛ばしたいときに使ったり、何を渡しているのか判りやすくするためにあえてキーを付けることがあります。

python

1def cube(x=1, y=1, z=1): 2 print('x:{}, y:{}, z:{}'.format(x, y, z)) 3 4cube(y=10, z=20) # x の定義を省略

python

1add_cart(1, 12345, 10) # なにを渡しているのかわからない 2 3add_cart(userid=1, itemid=12345, quantity=10) # わかりやすい 4

ところで関数の引数定義部分で *hoge でまだ格納されていないすべての位置引数を、**hoge でまだ格納されていないすべてのキーワード引数を格納させることができます。このようにして受け取る引数の数をその時々に応じて変えられる仕組みを可変長引数と言います。

ここで Bottleのソースコード をみると、def template(*args, **kwargs): とやって可変長位置引数と可変長キーワード引数で値を受け取って、return TEMPLATES[tplid].render(kwargs) とやって render に可変長キーワード引数を渡していることが判ります。

そもそも Bottle の bottle.template 関数に row なんて引数は存在しませんよね? それはあなたの考えた変数です。それを Bottle は可変長キーワード引数として受け取り、レンダラーに渡し、レンダラーは row というキーを使って値を取り出しテンプレートに埋め込んでHTMLを生成しています。


ここから蛇足。

bottle.template は第2位置引数以降に 辞書を渡すことによっても、レンダラーに値を渡すことができます。

python

1"""キーワード引数で値を渡す場合""" 2template('index', row=row, name=name) 3 4"""位置引数で辞書を渡す場合""" 5values = {'row': row, 'name': name} 6template('index', values) 7 8"""要はアンパック渡ししているのとと""" 9values = {'row': row, 'name': name} 10template('index', **values)

この仕様があるため、template('index', row) としたときに第2位置引数に辞書ではない row オブジェクトを渡してしまっているためにエラーが起きます。

まあ今回のキモは "キーワード引数"、"可変長引数" ですからエラーが出るメカニズムを追う必要はないと思います。ただ Bottle は設計やコードがきれいで手本として最適とよく言われています。より Python を深く理解したくなったら Bottle のソースコードを読んで学んでみるとよいかもしれません。

投稿2017/07/17 15:31

miyahan

総合スコア3095

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

miyahan

2017/07/17 15:50

ほかの方とだだかぶりしてしまいました。。。すみません。
gori

2017/07/18 10:41

回答ありがとうございます。 可変長引数を理解できていませんでした。引数を正しく設定できていなかったんですね。 やっと理解できました。
guest

0

気になって少し調べてみました。まず、templateの実装

Python

1def template(*args, **kwargs): 2tpl = args[0] if args else None 3 for dictarg in args[1:]: 4 kwargs.update(dictarg) # ←ここ!

エラーが発生しているのはupdateですね。


次に、(*args, **kwargs)の意味についての解説

Python

1>>> def hoge(*args, **kwargs): 2... print args 3... print kwargs 4... 5>>> hoge(1, 2, 3, ['a', 'b', 'c'], name='my_name', data='100') 6(1, 2, 3, ['a', 'b', 'c']) 7{'data': '100', 'name': 'my_name'}

キーワードを指定しないとargsに、指定するとkwargsに渡されるのですね。


さらに、updateメソッドの使い方

dict['氏名'].update({'追加科目名1' : '点数', '追加科目名2' : '新点数'})

updateメソッドの引数は辞書型なのですね。


結局なんでエラーが生じているのか
さっきのコードをもっかい見てみます。

Python

1def template(*args, **kwargs): 2tpl = args[0] if args else None 3 for dictarg in args[1:]: 4 kwargs.update(dictarg) # ←ここ!

argsで取得した値を、kwargsにマージしているようです。
updateメソッドの引数が辞書型でないので、エラーが生じているのでしょう。

試しに、次のようにしたら動きませんか?

Python

1return template('index', {'row': row})

実験してみました

Python

1def func(*args, **kwargs): 2 for dictarg in args: 3 kwargs.update(dictarg) 4 5 print(kwargs) 6 7tmplist = list(range(4)) 8func(a=tmplist) 9func({'b': tmplist}) 10func(tmplist) 11""" 実行結果 12{'a': [0, 1, 2, 3]} 13{'b': [0, 1, 2, 3]} 14Traceback (most recent call last): 15 File "tmptest.py", line 10, in <module> 16 func(tmplist) 17 File "tmptest.py", line 3, in func 18 kwargs.update(dictarg) 19TypeError: cannot convert dictionary update sequence element #0 to a sequence 20"""

うん、予想通り。


色んな引数の与え方があるんですね。

投稿2017/07/17 13:59

編集2017/07/17 15:03
LouiS0616

総合スコア35658

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gori

2017/07/17 14:33

回答ありがとうございます。なんとか理解できたと思います。 rowの型がリストとなっていたのでエラーとなったところまでは理解できました。 row=rowとすることで型がリストから辞書型に変換されたのはなぜでしょうか? 回答の際に例として記載していた下記のように記載する必要があると思うのですが・・ 回答いただけないでしょうか。 return template('index', {'row': row})
LouiS0616

2017/07/17 14:46

キーワードを指定 ・しない -> args ・する  -> wkargs
LouiS0616

2017/07/17 14:46

wkargsに渡されたときは、自動的に辞書として扱われるようですね。
gori

2017/07/18 10:43

よくやく理解できました。引数にも色んな種類があるんですね。 ライブラリの中身まで含めて解説いただきありがとうございました。
guest

0

対象のコードは読めてませんが、エラーでいえばここが参考になると思います。
https://stackoverflow.com/questions/14302248/dictionary-update-sequence-element-0-has-length-3-2-is-required

投稿2017/07/17 13:19

_Victorique__

総合スコア1392

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gori

2017/07/17 13:34

エラーコードで検索して似たようなページにいくつかたどり着きましたが、理解できませんでした。
_Victorique__

2017/07/17 13:38

具体的に何が理解できなかったのかを記述すると回答が得られやすくなりますよ。
gori

2017/07/17 13:41

rowをrow=rowとすることでどう変化するのかが分かりませんでした。
gori

2017/07/17 13:42

質問に追記します。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問