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})

みたいな書き方でもちゃんと結合させることが可能

感想

  • 日本語的に若干ツッコミどころがあるのにちゃんと出力するGPTすごいぞ
    • 言語モデルがすごい。
    • AIが翻訳者の仕事を奪うとかネットの記事で書いてるのが信じられる出来
  • ていうかエラーなく動くコードがでてえらい
    • copyするのえらすぎる。これ意識して書けるのは明らかに「pythonちゃんと書いてる」やつ

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だしね無理だよねという話に遭遇。

stackoverflow.com

なのでsystemctlでそれっぽく動きそうなリファレンスを捜索

これがヒット

yomon.hatenablog.com

これベースでやるとよさそう

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;

  • 成功しませんでした

やりたいこと

ref

XFCE Setup - Alpine Linux

ここの通りに入れると結構すんなり進む。そらマニュアルなんだからそうだという話はさておき、

$ Xorg -configure

がこけるはずだ Xorg.0.logを読むとなんかわかるんじゃないかなという話なのでエラーっぽい単語でぐぐる

Bug #3691: Xorg fails to launch due to module symbols not found - Alpine Linux - Alpine Linux Development

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を直接たたく

f:id:rane-hs:20160426123606p:plain うーん真っ黒画面だ

再度Xorg.0.logを見るとvboxなんちゃらというのが出るのでvirtualbox用アドオンを入れようとする

# apk add virtualbox-additions-grsec
# apk add virtualbox-guest-modules-grsec

うん?両方こけるぞ?と思ってパッケージ検索を実行

Alpine packages

Branchがedgeになっているので読めるようにしておきます。 /etc/apk/repositoriessudo 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の画面が立ち上がらないかを調べたほうがよさそうだ

メモ書き

やりたいこと

tools

電灯

www.amazon.co.jp

  • とくに理由はないけどUSBだと結線がイメージしやすそうという理由によりチョイス
  • (外で置くには何かしらのガワが必要になるのでそれはおいおい)

被覆材

www.monotaro.com

  • このへんから適当に

コントローラ

akizukidenshi.com

  • Cではない(これはC++。Lazurite ってのがあってこれも省電力を売りにしてたんだけどCしか使えなさそうなのでやめました)
  • 省電力
  • 安い

という点からチョイス

給電

www.amazon.co.jp

  • どうやって使おうかというイメージがまだできてない

docker & alpine

いまdocker熱いですね。

どうもそれとセットでalpine linuxってのが熱いらしいです

何がいいのそれっていうと、コンテナサイズが劇的に軽くなるということのようです

くわしくはこのあたりに:

Docker、オフィシャルイメージのOSをAlpine Linuxへ切り替える計画が明らかに。OSの軽量化に傾倒するDocker - Publickey

で、alpineベースでmemcachedとredisのコンテナがあるんですけど両方くっついたコンテナの方がほしくなったので、dockerの勉強がてら作ってみました

github.com

使い方は

$ 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

run container shell

docker exec -it mcdocker /bin/ash
  • attachdocker runしたスクリプトにアタッチしちゃうので、Ctrl-Cとかexitしちゃうとコンテナごと閉じます。
  • ここではexecを使ってシェルを立ち上げています。alpine linuxではbashがないのでashとしましたがubuntuではbashでよさそう

お役立ちリンク

qiita.com

Docker pull issue (ApplyLayer exit status 1 stdout: stderr: chmod /bin/mount: permission denied) | Alpine Linux forums

  • alpine linuxdocker pull mysqlできないのは上記を見て対応してください

speakerdeck.com

  • 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で死にます。死なない代わりに猛烈に遅いけど