Methoden einer Klasse einem Dictionary der Klasse zuordnen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

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 :(
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Übergeb das commands dictionary als default Argument.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

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
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

:)

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
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
Benutzeravatar
HerrHagen
User
Beiträge: 430
Registriert: Freitag 6. Juni 2008, 19:07

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.
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

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'
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Aber ... sag mal fuer was willst du das eigentlich benutzen? Mir kommt das reichlich abstrus vor.
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

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
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

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.
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

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?
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

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

Zum Thema Singleton: Module sind in Python "natürliche" Singletons.
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

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?
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Dass die Aliase direkt im Code stehen und nur durch eine Aenderung am Code geandert werden koennen.
Antworten