Seite 1 von 1

Methoden einer Klasse einem Dictionary der Klasse zuordnen

Verfasst: Freitag 7. August 2009, 16:17
von jbs
Ich möchte Methoden einer Klasse einem Dictionary der Klasse zuordnen. Ich dachte am schönsten wäre es, das mit Dekoratoren zu lösen. So ungefähr hatte ich mir das gedacht:

Code: Alles auswählen

class Command(object):
    commands = {}
    
    def command(name):
        def add_command(func):
            commands[name] = func
            return func
        return add_command

    @command('say'):
    def say(self, args): pass
Allerdings ist der Funktion command das Dictionary commands nicht bekannt.

Alle meine bisherigen Versuche schlugen Fehl :(

Verfasst: Freitag 7. August 2009, 16:25
von DasIch
Übergeb das commands dictionary als default Argument.

Verfasst: Freitag 7. August 2009, 16:29
von sma
In der Methode `command` müsste es so heißen:

Code: Alles auswählen

Command.commands[name] = func
Und mache den `:` hinter `@command` weg.

Aber das wird nicht funktionieren, weil Python anders als Ruby keine ausführbaren Klassenrümpfe im Kontext des Klassenobjekts hat, sondern wenn der Rumpf von `Command` ausgeführt wird, gibt es diese Klasse noch gar nicht. Ziehe das als Funktion raus.

Code: Alles auswählen

commands = {}

def command(name):
    def add_command(func):
        commands[name] = func
        return func
    return add_command

class Command(object):
    @command('say')
    def say(self, args): pass

print commands
Update: DasIch hat Recht. Dies geht auch:

Code: Alles auswählen

class Command(object):
    commands = {}

    def command(name, c=commands):
        def add_command(func):
            c[name] = func
            return func
        return add_command

    @command('say')
    def say(self, args): pass

print Command.commands
Stefan

Verfasst: Freitag 7. August 2009, 16:40
von jbs
:)

ich hatte mir eben überlegt es mit einer von dict abgeleiteten Klasse zu lösen:

Code: Alles auswählen

class FunctionsDict(dict):
	def __call__(self, cmd):
		def add_command(func):
			self[cmd] = func
			return func
		return add_command

class Command(object):
	commands = FunctionsDict()
	
	@commands('say')
	def say(self, args): pass

Verfasst: Freitag 7. August 2009, 19:31
von HerrHagen
Wie wärs denn mit sowas:

Code: Alles auswählen

>>> import types
>>> class Command(object):
    def say(self, args): pass
    def shout(self): pass
    commands = dict([(name, item) for name, item in Command.__dict__.iteritems() if isinstance(item, types.FunctionType)])

>>> Command.commands
{'say': <function say at 0x00BB9E30>, 'shout': <function shout at 0x00BB9E70>}
Da fällt der Dekorator und die redundante Bennenung der Funktion weg.

Verfasst: Samstag 8. August 2009, 10:27
von audax
sollte der Name sowieso immer gleich dem Eintrag sein:

Code: Alles auswählen

import types

class Commands(object):

    commands = {
        'say': lambda x: "Simons says %s" % x,
        'foo': lambda x: "Foo: %s" % x,
        }

    attrib = "foob"

    def __getattribute__(self, name):
        try:
            commands = object.__getattribute__(self, 'commands')
            if isinstance(commands[name],
                          types.FunctionType):
                return commands[name]
        except KeyError:
            pass
        return object.__getattribute__(self, name)

Code: Alles auswählen

>>> x = Commands()
>>> x.foo("bar")
'Foo: bar'
>>> x.attrib
'foob'
>>> x.invalid
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/tmp/py5530QFq", line 32, in __getattribute__
AttributeError: 'Commands' object has no attribute 'invalid'

Verfasst: Samstag 8. August 2009, 10:39
von cofi
Aber ... sag mal fuer was willst du das eigentlich benutzen? Mir kommt das reichlich abstrus vor.

Verfasst: Samstag 8. August 2009, 12:08
von jbs
Wir haben in der Schule mit sockets angefangen und ich hab das zum Anlass genommen mal ein wenig auszuprobieren, was geht und wie man einen Chatserver implementieren könnte. Ich hab mich letztlich für die abgeleitete Dictionary-Klasse entschieden, weil dadurch die Klasse ohne die ``command`` Funktion auskommt.

http://paste.pocoo.org/show/133140/

Zum Ablauf:
Der ChatServer wird gestartet und für jede Verbindung wird ein ClientThread gestartet. Beim Empfang eines Befehls wird die Nachricht mittels des CommandHandler ausgeführt. Im ClientContainer sind alle Verbindungen gespeichert.


Inhalt von _tools.py:

Code: Alles auswählen

class FunctionsDict(dict):
        """Dictionary with decorator function"""
        def __call__(self, cmd):
                def add_command(func):
                        self[cmd] = func
                        return func
                return add_command

class Singleton(type):
    def __init__(cls, name, bases, dict):
        super(Singleton, cls).__init__(name, bases, dict)
        cls.instance = None

    def __call__(cls, *args, **kw):
        if cls.instance is None:
            cls.instance = super(Singleton, cls).__call__(*args, **kw)
        return cls.instance

Verfasst: Samstag 8. August 2009, 12:40
von cofi
Das heisst du willst Aliases fuer die Befehle einrichten? An deiner Stelle wuerde ich das eher in die Konfiguration auslagen.
``CommandHandler`` sieht fuer mich auch nicht unbedingt so aus, als muesste das eine Klasse sein.
Und das Singleton ... in Python sehr unueblich und sonst auch eher verhasst. Das Borg-Pattern waere eine Alternative, aber am besten ist es ein Singleton schlicht nur einmal zu instantiieren.

Verfasst: Samstag 8. August 2009, 12:45
von jbs
cofi hat geschrieben:Das heisst du willst Aliases fuer die Befehle einrichten? An deiner Stelle wuerde ich das eher in die Konfiguration auslagen.
``CommandHandler`` sieht fuer mich auch nicht unbedingt so aus, als muesste das eine Klasse sein.
Und das Singleton ... in Python sehr unueblich und sonst auch eher verhasst. Das Borg-Pattern waere eine Alternative, aber am besten ist es ein Singleton schlicht nur einmal zu instantiieren.
Wie gesagt, es ging darum auzuprobieren, was geht :)

Wie würdest du denn die Aliase implementieren?

Verfasst: Samstag 8. August 2009, 12:51
von cofi
Im Prinzip genauso, d.h. ueber ein Dict, dass die Aliase den Befehlen zuordnet, allerdings sind die bei dir Hart-codiert und so dem Benutzer eher unzugaenglich.

Ich wuerde ``command`` so abaendern, dass es die Funktion einfach als Befehl - vllt auch mit einem sinnvollen Namen - kennzeichnet & registriert und den so fuer das Userinterface, Config, etc. zugaenglich macht.

Verfasst: Samstag 8. August 2009, 13:40
von BlackJack
Zum Thema Singleton: Module sind in Python "natürliche" Singletons.

Verfasst: Samstag 8. August 2009, 13:41
von jbs
cofi hat geschrieben:Im Prinzip genauso, d.h. ueber ein Dict, dass die Aliase den Befehlen zuordnet, allerdings sind die bei dir Hart-codiert und so dem Benutzer eher unzugaenglich.

Ich wuerde ``command`` so abaendern, dass es die Funktion einfach als Befehl - vllt auch mit einem sinnvollen Namen - kennzeichnet & registriert und den so fuer das Userinterface, Config, etc. zugaenglich macht.
wie meinst du das mit "hart"-codiert?

Verfasst: Samstag 8. August 2009, 13:55
von cofi
Dass die Aliase direkt im Code stehen und nur durch eine Aenderung am Code geandert werden koennen.