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:
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.