ChatGPTに関心した話
お久しぶりです。
猫も杓子もGPTですね。
自分も例に漏れず使っているわけですが関心したことがあったのでまとめてみようかなと思いました
動機
pythonを最近よく書くのである程度詳しい認識はあるのですが、
dictを加算しつつ結合するようなメソッドが欲しいと思いました。
dictを結合する場合 |
演算子や update()
メソッドを用いることがよく知られていますが、それらはこのように動作します
In [2]: _d1 = {1:2, 2:3} In [3]: _d1.update({3:4}) In [4]: _d1 Out[4]: {1: 2, 2: 3, 3: 4} In [5]: {1:2, 2:3} | {3:4} Out[5]: {1: 2, 2: 3, 3: 4}
これらはキーが重複していない状態では想定通りの挙動をしますが、キーがかぶっているときには安全側に倒すような挙動となります(エラーなどでずに後ろの値で上書き)
キーが重複していたときに加算してほしいなあと思ったのですがそういった実装はないのでChatGPTに聞いてみることにしました
聞いてみた
解説
だいたいコメントを読んでもらうと想定内のことが書いてありますね
なんで copy()
が入っているのかというと、primitive typeを除いてpythonでは引数に参照渡しでくるのでそのまま copy()
せずに代入すると引数で渡したp1の値が関数の外で想定外の値になってしまうからです
だいたいのケースでcopyせずに問題なく動くと思いますがあるとなしでは安全さが違う
これらを受けてこういうコードになった
T = TypeVar("T") def merge_dict(src: dict[T, int], *args: Any) -> dict[T, int]: dest = src.copy() for arg in args: for k, v in arg.items(): if k in dest: dest[k] += v else: dest[k] = v return dest
こういう感じにすることで
merge_dict({1: 2, 3:4}, {3:5}, {1: 8})
みたいな書き方でもちゃんと結合させることが可能
感想
multi memcached in upstart
やりたいこと
check
$ ps -ax | grep memcached 8501 ? Ssl 0:00 /usr/bin/memcached -m 64 -p 11211 -u memcache -l 127.0.0.1
これを21211でも起動したい
やり方をぐるる
/etc/init.d/memcached
にヒントがあるとのこと
# Usage: # cp /etc/memcached.conf /etc/memcached_server1.conf # cp /etc/memcached.conf /etc/memcached_server2.conf # start all instances: # /etc/init.d/memcached start # start one instance: # /etc/init.d/memcached start server1 # stop all instances: # /etc/init.d/memcached stop # stop one instance: # /etc/init.d/memcached stop server1 # There is no "status" command.
設定をコピー
$ sudo cp /etc/memcached.conf /etc/memcached_server1.conf
コピーしたほうのconfを編集してポートを21211に変更
で、起動しなかった
ぐぐったらupstartだしね無理だよねという話に遭遇。
なのでsystemctlでそれっぽく動きそうなリファレンスを捜索
これがヒット
これベースでやるとよさそう
service をコピー
$ cd /lib/systemd/system $ sudo cp memcached.service memcached.21211.service
コピーした方を新しい設定ファイルを読みに行くように修正する
起動
$ sudo systemctl start memcached.21211 $ ps -ax | grep memcached 8501 ? Ssl 0:00 /usr/bin/memcached -m 64 -p 11211 -u memcache -l 127.0.0.1 10125 ? Ssl 0:00 /usr/bin/memcached -m 64 -p 21211 -u memcache -l 127.0.0.1
めでたしめでたし
x in alpine linux
TL, DR;
- 成功しませんでした
やりたいこと
- alpine linux(3.3)にXFCEを入れる
- 対象はvirtualbox VM(5.0.18)
ref
ここの通りに入れると結構すんなり進む。そらマニュアルなんだからそうだという話はさておき、
$ Xorg -configure
がこけるはずだ Xorg.0.log
を読むとなんかわかるんじゃないかなという話なのでエラーっぽい単語でぐぐる
Yes, Xorg -configure will disable the /etc/X11/xorg.conf.d/ which has the config for manually loading the modules in proper order.
The problem is that musl libc does not support lazy loading. I don't have any good ideas how to properly solve this.
Does it work if you skip the Xorg -configure step and just do startxfce4?
えっ叩いちゃだめなのこれ!!!? ということでstartxfce4を直接たたく
うーん真っ黒画面だ
再度Xorg.0.log
を見るとvboxなんちゃらというのが出るのでvirtualbox用アドオンを入れようとする
# apk add virtualbox-additions-grsec # apk add virtualbox-guest-modules-grsec
うん?両方こけるぞ?と思ってパッケージ検索を実行
Branchがedgeになっているので読めるようにしておきます。 /etc/apk/repositories
をsudo vim
grsecまわりが必要そうなのでlinux-grsec
もadd
$ cat /etc/apk/repositories #/media/cdrom/apks http://dl-3.alpinelinux.org/alpine/v3.3/main http://dl-3.alpinelinux.org/alpine/v3.3/community http://dl-3.alpinelinux.org/alpine/edge/main http://dl-3.alpinelinux.org/alpine/edge/community http://dl-3.alpinelinux.org/alpine/edge/testing
で、
# apk del virtualbox-additions-grsec # apk del virtualbox-guest-modules-grsec # apk add linux-grsec # apk add virtualbox-additions-grsec # apk add virtualbox-guest-modules-grsec
からの再起動して、startxfce4
。。。。同じ画面じゃないか
続く(かも)
マウスカーソルが出てる時点でおそらく半分くらい目的は達成されているはずなので、なぜxfceの画面が立ち上がらないかを調べたほうがよさそうだ
メモ書き
やりたいこと
- 庭用ランプを買いたい
— rane (@rane_hs) April 18, 2016
- 個別ソーラーみたいなやつは日照イマイチなところには置けない
⇒ 日照高いところで集光して18-24だけ給電するようなやつ(IoTデバイス?)を作る必要性
tools
電灯
- とくに理由はないけどUSBだと結線がイメージしやすそうという理由によりチョイス
- (外で置くには何かしらのガワが必要になるのでそれはおいおい)
被覆材
- このへんから適当に
コントローラ
- Cではない(これはC++。Lazurite ってのがあってこれも省電力を売りにしてたんだけどCしか使えなさそうなのでやめました)
- 省電力
- 安い
という点からチョイス
給電
- どうやって使おうかというイメージがまだできてない
docker & alpine
いまdocker熱いですね。
どうもそれとセットでalpine linuxってのが熱いらしいです
何がいいのそれっていうと、コンテナサイズが劇的に軽くなるということのようです
くわしくはこのあたりに:
Docker、オフィシャルイメージのOSをAlpine Linuxへ切り替える計画が明らかに。OSの軽量化に傾倒するDocker - Publickey
で、alpineベースでmemcachedとredisのコンテナがあるんですけど両方くっついたコンテナの方がほしくなったので、dockerの勉強がてら作ってみました
使い方は
$ git clone git@github.com:rane-hs/memcached-and-redis.docker.git $ cd memcached-and-redis.docker $ docker build -t memcached-redis-alpine . $ docker run --restart always --name mcdocker -i -t -d memcached-redis-alpine $ docker inspect mcdocker | grep IPAddr # コンテナのIPを入手
で、↑で入手したアドレスにログインします
$ telnet 123.45.67.89 11211 # telnet $ redis-cli 123.45.67.89 # redis
docker commands
使ったコマンドたち。
以下は↑のリンクをgit cloneしてきて1個中に入った状態で叩かれていることを想定しています
build container
docker build -t memcached-redis-alpine .
memcached-redis-alpine
という名前でコンテナイメージを作ります
run container
docker run --restart always --name mcdocker -i -t -d memcached-redis-alpine
mcdocker
という名前でコンテナを走らせます。イメージは↑で作った名前です
check running container
docker ps
- いまローカルにあるイメージの一覧は
docker images
で - 両方
-a
がoptionalで使えます
remove container (-f : force)
docker rm -f mcdocker
- イメージ削除は
rmi
remove unused container image (1liner)
docker rmi -f $(sudo docker images -a | awk '/^<none>/ { print $3 }')
- 全部きえるわけではないです
check container setting
docker inspect mcdocker
IPAddress
でコンテナのIPアドレスがわかります
run container shell
docker exec -it mcdocker /bin/ash
attach
はdocker run
したスクリプトにアタッチしちゃうので、Ctrl-Cとかexitしちゃうとコンテナごと閉じます。- ここでは
exec
を使ってシェルを立ち上げています。alpine linuxではbashがないのでashとしましたがubuntuではbashでよさそう
お役立ちリンク
- docker チートシート
- alpine linuxで
docker pull mysql
できないのは上記を見て対応してください
- dockerオススメTIPS15選。
- sudo dockerプレフィックスをdockerにする方法もあります
tweepy メモ書き
create App
https://apps.twitter.com/app/new
- callback url は空にする!!
requirements
pip install tweepy pyyaml
pyyamlはなんとなく
write code
import tweepy consumer_key = 'hogehogehoge-' consumer_secret = 'fugafugafuga-' auth = tweepy.OAuthHandler(consumer_key, consumer_secret) access_token = None access_token_secret = None import os import yaml class TwConfig: _setting_filepath = '.twpy.yml' def __init__(self): self._config = {} @property def access_token(self): return self._config.get('access_token', None) @property def access_token_secret(self): return self._config.get('access_token_secret', None) @property def followers(self): return self._config.get('followers', None) @property def protected_users(self): return self._config.get('protected_users', None) @property def followings(self): return self._config.get('followings', None) @property def config_path(self): return os.path.join(os.getcwd(), self._setting_filepath) def load(self): with open(self.config_path) as f: self._config = yaml.load(f) def write(self): with open(self.config_path, mode='w') as f: f.write(yaml.dump(self._config)) def update(self, **kwargs): for k, v in kwargs.items(): self._config.update({k: v}) _config = TwConfig() class tweepyAPI(tweepy.API): def following_iterator(self, user_id): cursor = tweepy.Cursor(api.friends, id=user_id) for _c in cursor.items(): yield _c def print_home(api): public_tweets = api.home_timeline() for tweet in public_tweets: print(tweet.text) def print_friends_simple(api, screen_name: str): user = api.get_user(screen_name) print('my name {}, followers {}'.format(user.screen_name, user.followers_count)) for friend in user.friends(): print('name {}, protected {}'.format(friend.screen_name, friend.protected)) def get_followers(api, screen_name: str): user = api.get_user(screen_name) print('my name {}, followers {}'.format(user.screen_name, user.followers_count)) cursor = tweepy.Cursor(api.followers, id=user.id) followers = [x.screen_name for x in cursor.items()] print('followers ', followers) return followers def get_followings(api, user): for friend in api.following_iterator(user.id): print('name {}, protected {}'.format(friend.screen_name, friend.protected)) def login(config): try: config.load() auth.set_access_token(config.access_token, config.access_token_secret) except: pass if not (config.access_token and config.access_token_secret): redirect_url = auth.get_authorization_url() print("access to -> {}".format(redirect_url)) import webbrowser webbrowser.open(redirect_url) verifier = input('Type the verification code: ').strip() auth.get_access_token(verifier) config.update(access_token=auth.access_token, access_token_secret=access_token_secret) config.write() return tweepyAPI(auth, wait_on_rate_limit=True, wait_on_rate_limit_notify=True) if __name__ == "__main__": api = login(_config) user = api.get_user('rane_hs') print('my name {}, followers {}'.format(user.screen_name, user.followers_count)) if not _config.followers: _config.followers = get_followers(api, user) _config.write() protected_users = [] followings = [] for friend in api.following_iterator(user.id): if friend.protected: protected_users.append(friend.screen_name) followings.append(friend.screen_name) _config.update(followings=followings, protected_users=protected_users) _config.write()
解説
class TwConfig
- 省略
getattr
を上手に使うともっときれいに書けるよ
class tweepyAPI(tweepy.API)
user.friends
を使う実装だと、取得件数が決まっているので(print_friends_simple()
を叩いてみるとわかるよ)、iterationしながらとってくる実装を作成cursor
をiterationするtweepy.Cursor
を使ってます
login
- アクセストークンが保存されてなかったらブラウザを開いてPINコードが表示されるので入力してねみたいな実装
wait_on_rate_limit=True, wait_on_rate_limit_notify=True
しないとすぐrate limitで死にます。死なない代わりに猛烈に遅いけど