Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
494 views
in Technique[技术] by (71.8m points)

metaprogramming - Can Python instance methods be automatically defined at __init__ time?

I'm wondering if instance methods can be created automatically in Python when __init__ is executed. Consider this code example where a class is defined to handle some audio file format metadata (exceptions handling and not relevant stuff omitted):

__tags__ = ['album', 'artist', 'date', 'genre', 'title', 'tracknumber']

class Tags():
    def __init__(self):
        for tag in __tags__:
            setattr(self, tag, None)

    def print(self):
        for k, v in self.__dict__.items():
            if v:
                print('{}: {}'.format(k, str(v)))

    def get(self, *pa):
        ret = [getattr(k) for k in pa if k in __tags__]
        return ret if len(pa)>1 else ret[0]

    def set(self, **ka):
        for k, v in ka.items():
            if k in __tags__:
                setattr(self, k, str(v))

Now:

    mytags = Tags()
    mytags.set(album='The best of Ennio Morricone', artist='Various Artists')
    mytags.print()
    print()
    mytags.set(genre='Soundtrack', tracknumber=3)
    mytags.set(title='Secret Of The Sahara')
    mytags.print()
    print(mytags.album is mytags.get('album'))

prints:

album: The best of Ennio Morricone
artist: Various Artists

album: The best of Ennio Morricone
artist: Various Artists
genre: Soundtrack
title: Secret Of The Sahara
tracknumber: 3
True

Suppose now I want to add get_<tag>/set_<tag> methods for every single tag, i.e. mytags.set_album(album) or title=mytags.get_title(). Given that mytags.set_album(album) translates to mytags.set({'album':album,}), is there a pythonic way to automatically create these methods when the instance is created? Stupid non-working example just to try to explain what I mean:

    class Tags():
        def __init__(self):
            for tag in __tags__:
                setattr(self, tag, None)
                setattr(self, 'set_'+tag<reference to passed in argument>,
                        <reference to the respective self.set() method>)

This would save a lot of typing and, above all, it wouldn't require any change should __tags__ be updated.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Yes, you can create functions and bind them to instances as instance methods, e.g.,

def __init__(...):
    tag = "album"
    def whatever_func(self, gettag=tag):
       return getattr(self, gettag)
    setattr(self, f"get_{tag}", whatever_func.__get__(self))

It's not pretty, though, right? I think you'd be better off defining a __getattr__ to deal with any attribute access that is not defined; you should also define __dir__ so that these dynamic attributes are tab-completable.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...