読者です 読者をやめる 読者になる 読者になる

cocuh's note

type(あうとぷっと) -> 駄文

How to write GUI application in python one-liner

Python 雑記

i wrote this article drinking ebisu red-label beer*1 and tanqueray no10*2. i suppose there are typos and mistakes. if you want more rich commentary, plz comment.

in japanese or 日本語.
qiita.com

pythonワンライナーのすゝめ

python one-liner base theory

statement and expression

the statement require '\n', so you should use the expression in one-liner. you can write almost all process in expression. only try: catch: statement can't be written in expression.(if you have some idea, plz tell me) exec()? it is not cool.

semicolon? it's ugly.

you should learn short-circuit evaluation and implicit coversion.

if condition:
  A
else:
  B
condition and A or B

if you want to chain process, you should consider A return.

A
B
C
A;B;C
# useful in golf, but ugly....
A or B or C
# it's sooooo cooooool.
# A and B should return False

# if B returns True, ...
A or not B or C

# if return of B is uncertain.
# 0 is useful in golf.
A or (B and 0) or C

how write assignment in one-liner?

assignment is statement, so you should find same meaning expression.

7. Simple statements — Python 3.4.4 documentation

use build-in globals() function.

2. Built-in Functions — Python 3.4.4 documentation

in one-liner, all variable is in global scope, because local() is read-only. you should define assign lambda function with globals(), like this.

2. Built-in Functions — Python 3.4.4 documentation

globals().update({'assign': lambda k,v:globals().update({k:v})})

assign is lambda function with side effect. cool.

import in one-liner

use build-in function: __import__()

[https://docs.python.org/3.4/library/functions.html?highlight=globals#import:title]

sys=__import__('sys')

# i always define utility lambda function like follows.
assign('i',lambda n:__import__(n))
assign('sys',i('sys'))

python one-liner application theory

dynamic class definition

type() function enable to create class dynamically, and inherit parent classes.

2. Built-in Functions — Python 3.4.4 documentation

pythonic ex code.

class Gui(tk.Frame):
    def __init__(self, parent=None):
        self.parent = parent

in one-liner,

Gui = type('Gui', (tk.Frame), {'__init__': lambda self, parent=None: self.__setattr__('parent', parent)})

learn special methods, modules, build-in functions.

instance and class have useful special methods; __setattr__, __getattr__ or __dict__. modules; itertools, functools, operator. build-in functions: map, all, sorted, sum.

if you want to flatten list, sum's argument is sum(iter[, start]), so sum([[1,2],[3],[4,5]],[]) will work.

https://docs.python.org/3.4/library/functions.html?highlight=globals#sum

gui application

write in standard python

i use wallpaperchanger script which i wrote. publishing code in github

(i think this code is not pythonic. i wrote this in beginner... i bother to refactor this code... but ONELINIZE!)

require pillow or PIL for previewing images.

github.com

encode with those techniques

WallpaperChanger/clean_wallpaperchanger.py at oneliner · cocuh/WallpaperChanger · GitHub

#!/usr/bin/env python
c=lambda k,v:globals().update({k:v})
i=lambda n:c(n,__import__(n))

i('os')
i('sys')
i('subprocess')
i('shlex')
i('argparse')
i('random')
i('itertools')

c('CONFIG_PATH',os.path.expanduser('~/.config/wallpaperchanger.conf'))

(sys.version_info.major==2 and(
    c('configparser',__import__('ConfigParser'))or c('tk',__import__('Tkinter'))or c('next',lambda o:o.next())
)or(
    i('configparser')or c('tk',__import__('tkinter'))
))

i('PIL')or i('PIL.Image')or i("PIL.ImageTk") # TODO

c("WallpaperChanger",type('WallpaperChanger',(),
  {
      '__doc__':"main class\n\n    this contains filenames, config.\n",
      '__init__':lambda s:s.__dict__.update({'wrap_config':WrapConfig()})or s.wrap_config.load()or s.__dict__.update({'config':s.wrap_config.config,'base_path':os.path.expanduser(s.wrap_config.config.get('Main', 'path'))}),
      'call':lambda s,fn,ia=False:subprocess.call([l.format(file=fn if ia else os.path.join(s.base_path, fn))for l in shlex.split(s.config.get('Main','command'))])==0and(s.config.set('Wallpaper', 'current', fn)or s.wrap_config.write()),
      'get_filenames': lambda s:sorted(os.listdir(s.base_path)),
        'get_abspath': lambda s,fn:os.path.join(s.base_path, fn),
  }
))

c("WrapConfig",type("WrapConfig",(),{
    "__doc__":"""\nWrap ConfigParser,\n""",
    "DEFAULT":{'Main':{'path':'~/picture/wallpaper','command':'feh --bg-fill {file}',},'Wallpaper':{'current':'','default':'',}},
    "__init__":lambda s:s.__dict__.update({"config":configparser.ConfigParser()})or None,
    'load':lambda s:s.is_exists()and (s.config.read(CONFIG_PATH)and None)or(s.set_default()or s.write()),
    'write':lambda s:(s.is_exists_parent_directory()or os.makedirs(s._get_parent_path())or True)and(lambda fp:(s.config.write(fp)and None)or fp.close())(open(CONFIG_PATH, 'w')),
    'set_default':lambda s,ow=False:[(s.config.has_section(sec)or s.config.add_section(sec))and[(ow or not s.config.has_option(sec, opt)and s.config.set(sec,option,s.DEFAULT[sec][opt]))for opt in s.DEFAULT.get(sec, {}).keys()]for sec in s.DEFAULT.keys()]and None,
    'is_exists_parent_directory':lambda s:os.path.isdir(s._get_parent_path()),
    'is_exists':lambda s:os.path.exists(CONFIG_PATH),
    '_get_parent_path':lambda s:os.path.abspath(os.path.dirname(CONFIG_PATH)),
}))

c("Gui",type("Gui",(tk.Frame,),{
    '__doc__':'\nGraphical interface for wallpaper selecting.\n',
    'THUMBNAIL_SIZE':(400, 400),
    '__init__':lambda s,master,ch: s.__dict__.update({'_changer':ch,'filename':None,'key':''})or tk.Frame.__init__(s, master)or s.pack()or s.create_widgets()or s.init_binds()or s.set_listbox_filenames()or s.set_thumbnail(),
    'create_widgets':lambda s:(lambda fl:fl.pack({'fill': tk.BOTH, 'side': 'left'})or s.__dict__.update({'elem_listbox':tk.Listbox(fl),'elem_entry':tk.Entry(fl,textvariable=s.gen_entry_callback())}))(tk.Frame(s))or s.elem_listbox.pack({'side': 'top', 'fill': tk.BOTH})or s.elem_entry.pack({'side': 'bottom'})or s.elem_entry.focus_set()or PIL is None or(lambda fr:fr.pack({'fill': tk.BOTH})or s.__dict__.update({'elem_thumbnail':tk.Label(fr)}) or s.elem_thumbnail.pack({'side': 'right',}))(tk.Frame(s))or None,
    'init_binds':lambda s:s.master.bind('<Escape>', s.action_destroy)and s.master.bind('<Return>', s.action_finish)and s.master.bind('<Tab>', s.action_completion)and s.elem_listbox.bind('<<ListboxSelect>>', s.action_select)and s.elem_listbox.bind('<Double-Button-1>', s.action_finish)and None,
    'action_destroy':lambda s,*args:s.master.destroy(),
    'action_select':lambda s,e=None:(e and s.__dict__.update({'filename':s.elem_listbox.get(int(s.elem_listbox.curselection()[0]))})or s.set_thumbnail(s.filename))or None,
    'action_finish':lambda s,*args:(s.filename and s._changer.call(s.filename)or s.action_destroy()),
    'action_completion':lambda s,*args:(lambda names:(lambda idx:idx and (s.elem_entry.delete(0, tk.END)or s.elem_entry.insert(0, names[0][:idx])and None))(next(itertools.dropwhile(lambda idx:not all(names[0][:idx]in l for l in names[1:]),(len(names[0])-x for x in range(len(names[0])))),None)))(s.get_filtered_filenames(s.key))or 'break',
    'gen_entry_callback':lambda s:(lambda string_var:string_var.trace('w', lambda name, index, mode, sv=string_var: (lambda sv:(lambda names:s.set_listbox_filenames(names)or len(names)==1 and(s.__dict__.update({'filename':names[0]})or s.set_thumbnail(names[0])or True)or(s.__dict__.update({'filename':None})or s.set_thumbnail()))(s.__dict__.update({'key':sv.get()})or s.get_filtered_filenames(s.key)))(sv))and None or string_var)(tk.StringVar()),
    'set_listbox_filenames':lambda s,fn=None:[s.elem_listbox.insert(tk.END, n)for n in s.elem_listbox.delete(0,s.elem_listbox.size()-1)or(fn and fn or s._changer.get_filenames())]+[1]and None,
    'set_thumbnail':lambda s,fn=None:(not PIL or(lambda thumbnail:((fn and (lambda img:img.thumbnail(s.THUMBNAIL_SIZE,PIL.Image.ANTIALIAS)or thumbnail.paste(img,(int(max((s.THUMBNAIL_SIZE[0]-img.size[0])/2, 0)),int(max((s.THUMBNAIL_SIZE[1]-img.size[1])/2,0)))))(PIL.Image.open(s._changer.get_abspath(fn))))and None)or s.__dict__.update({'thumbnail':PIL.ImageTk.PhotoImage(thumbnail)})or s.elem_thumbnail.configure(image=s.thumbnail))(PIL.Image.new('RGBA', s.THUMBNAIL_SIZE, (0, 0, 0, 0)))or True)and None,
    'get_filtered_filenames':lambda s,kw:[x for x in s._changer.get_filenames() if x.find(kw) == 0]
}))

Gui(tk.Tk(), WallpaperChanger()).mainloop()
check returning False and replace '\n' to 'or'.

WallpaperChanger/wallpaperchanger.py at oneliner · cocuh/WallpaperChanger · GitHub

globals().update({'c':lambda k,v:globals().update({k:v})})or c('i',lambda n:c(n,__import__(n)))or i('os')or i('sys')or i('subprocess')or i('shlex')or i('argparse')or i('random')or i('itertools')or c('CONFIG_PATH',os.path.expanduser('~/.config/wallpaperchanger.conf'))or (sys.version_info.major==2 and(c('configparser',__import__('ConfigParser'))or c('tk',__import__('Tkinter'))or c('next',lambda o:o.next()))or(i('configparser')or c('tk',__import__('tkinter'))))or i('PIL')or i('PIL.Image')or i("PIL.ImageTk")or c("WallpaperChanger",type('WallpaperChanger',(),{'__doc__':"main class\n\n    this contains filenames, config.\n",'__init__':lambda s:s.__dict__.update({'wrap_config':WrapConfig()})or s.wrap_config.load()or s.__dict__.update({'config':s.wrap_config.config,'base_path':os.path.expanduser(s.wrap_config.config.get('Main', 'path'))}),'call':lambda s,fn,ia=False:subprocess.call([l.format(file=fn if ia else os.path.join(s.base_path, fn))for l in shlex.split(s.config.get('Main','command'))])==0 and(s.config.set('Wallpaper', 'current', fn)or s.wrap_config.write()),'get_filenames': lambda s:sorted(os.listdir(s.base_path)),'get_abspath': lambda s,fn:os.path.join(s.base_path, fn),}))or c("WrapConfig",type("WrapConfig",(),{"__doc__":"""\nWrap ConfigParser,\n""","DEFAULT":{'Main':{'path':'~/picture/wallpaper','command':'feh --bg-fill {file}',},'Wallpaper':{'current':'','default':'',}},"__init__":lambda s:s.__dict__.update({"config":configparser.ConfigParser()})or None,'load':lambda s:s.is_exists()and (s.config.read(CONFIG_PATH)and None)or(s.set_default()or s.write()),'write':lambda s:(s.is_exists_parent_directory()or os.makedirs(s._get_parent_path())or True)and(lambda fp:(s.config.write(fp)and None)or fp.close())(open(CONFIG_PATH, 'w')),'set_default':lambda s,ow=False:[(s.config.has_section(sec)or s.config.add_section(sec))and[(ow or not s.config.has_option(sec, opt)and s.config.set(sec,option,s.DEFAULT[sec][opt]))for opt in s.DEFAULT.get(sec, {}).keys()]for sec in s.DEFAULT.keys()]and None,'is_exists_parent_directory':lambda s:os.path.isdir(s._get_parent_path()),'is_exists':lambda s:os.path.exists(CONFIG_PATH),'_get_parent_path':lambda s:os.path.abspath(os.path.dirname(CONFIG_PATH))}))or c("Gui",type("Gui",(tk.Frame,),{'__doc__':'\nGraphical interface for wallpaper selecting.\n','THUMBNAIL_SIZE':(400, 400),'__init__':lambda s,master,ch: s.__dict__.update({'_changer':ch,'filename':None,'key':''})or tk.Frame.__init__(s, master)or s.pack()or s.create_widgets()or s.init_binds()or s.set_listbox_filenames()or s.set_thumbnail(),'create_widgets':lambda s:(lambda fl:fl.pack({'fill': tk.BOTH, 'side': 'left'})or s.__dict__.update({'elem_listbox':tk.Listbox(fl),'elem_entry':tk.Entry(fl,textvariable=s.gen_entry_callback())}))(tk.Frame(s))or s.elem_listbox.pack({'side': 'top', 'fill': tk.BOTH})or s.elem_entry.pack({'side': 'bottom'})or s.elem_entry.focus_set()or PIL is None or(lambda fr:fr.pack({'fill': tk.BOTH})or s.__dict__.update({'elem_thumbnail':tk.Label(fr)}) or s.elem_thumbnail.pack({'side': 'right',}))(tk.Frame(s))or None,'init_binds':lambda s:s.master.bind('<Escape>', s.action_destroy)and s.master.bind('<Return>', s.action_finish)and s.master.bind('<Tab>', s.action_completion)and s.elem_listbox.bind('<<ListboxSelect>>', s.action_select)and s.elem_listbox.bind('<Double-Button-1>', s.action_finish)and None,'action_destroy':lambda s,*args:s.master.destroy(),'action_select':lambda s,e=None:(e and s.__dict__.update({'filename':s.elem_listbox.get(int(s.elem_listbox.curselection()[0]))})or s.set_thumbnail(s.filename))or None,'action_finish':lambda s,*args:(s.filename and s._changer.call(s.filename)or s.action_destroy()),'action_completion':lambda s,*args:(lambda names:(lambda idx:idx and (s.elem_entry.delete(0, tk.END)or s.elem_entry.insert(0, names[0][:idx])and None))(next(itertools.dropwhile(lambda idx:not all(names[0][:idx]in l for l in names[1:]),(len(names[0])-x for x in range(len(names[0])))),None)))(s.get_filtered_filenames(s.key))or 'break','gen_entry_callback':lambda s:(lambda string_var:string_var.trace('w', lambda name, index, mode, sv=string_var: (lambda sv:(lambda names:s.set_listbox_filenames(names)or len(names)==1 and(s.__dict__.update({'filename':names[0]})or s.set_thumbnail(names[0])or True)or(s.__dict__.update({'filename':None})or s.set_thumbnail()))(s.__dict__.update({'key':sv.get()})or s.get_filtered_filenames(s.key)))(sv))and None or string_var)(tk.StringVar()),'set_listbox_filenames':lambda s,fn=None:[s.elem_listbox.insert(tk.END, n)for n in s.elem_listbox.delete(0,s.elem_listbox.size()-1)or(fn and fn or s._changer.get_filenames())]+[1]and None,'set_thumbnail':lambda s,fn=None:(not PIL or(lambda thumbnail:((fn and (lambda img:img.thumbnail(s.THUMBNAIL_SIZE,PIL.Image.ANTIALIAS)or thumbnail.paste(img,(int(max((s.THUMBNAIL_SIZE[0]-img.size[0])/2, 0)),int(max((s.THUMBNAIL_SIZE[1]-img.size[1])/2,0)))))(PIL.Image.open(s._changer.get_abspath(fn))))and None)or s.__dict__.update({'thumbnail':PIL.ImageTk.PhotoImage(thumbnail)})or s.elem_thumbnail.configure(image=s.thumbnail))(PIL.Image.new('RGBA', s.THUMBNAIL_SIZE, (0, 0, 0, 0)))or True)and None,'get_filtered_filenames':lambda s,kw:[x for x in s._changer.get_filenames() if x.find(kw) == 0]}))or Gui(tk.Tk(), WallpaperChanger()).mainloop()

It works!!!!

f:id:cocu_628496:20151212045944p:plain

it's end!
thank you for reading!!

*1:japanese famous lager beer, bitter

*2:famous gin