Seite 1 von 2

Re: Klassenmethode kann nicht gleichzeiting Membername sein?

Verfasst: Freitag 31. Januar 2014, 17:32
von BlackJack
@mutetella: Nein das ist nicht möglich, das hätte aber aus den bisherigen Beiträgen schon ersichtlich sein müssen, denn ob und wann das abgefragte Objekt aufgerufen wird kann der Interpeter beim Abfragen ja nicht ermitteln. Das kann ja irgendwann an einer ganz anderen Stelle im Code passieren und muss nicht direkt nach dem Abfragen des Attributs passieren. Warum Du im Falle von `request_has_brackets` das zweite Objekt in dem Tupel *aufrufst* ist mir auch nicht so ganz klar, denn dann muss das selber ja wieder etwas aufrufbares zurückgeben weil der Code der diesen Rückgabewert bekommt, ihn ja offensichtlich aufrufen wird, sonst wäre `request_has_brackets` nicht wahr.

Was Du im Grunde fragst ist ob eine Funktion/Methode herausfinden kann was der Aufrufer mit ihrem Rückgabewert machen wird. Nein, das geht nicht, weil das nicht vorgesehen ist. Das wäre auch ziemlich schräg.

Re: Klassenmethode kann nicht gleichzeiting Membername sein?

Verfasst: Freitag 31. Januar 2014, 19:07
von Leonidas
Vielleicht ist es doch möglich, wenn man im aufrufenden Stackframe schaut was das noch für Bytecodes hat und ob danach ein Funktionsaufruf kommt. So ähnlich wie birkenfeld ``runkit_return_value_used`` implementiert hat ;-)

Re: Klassenmethode kann nicht gleichzeiting Membername sein?

Verfasst: Freitag 31. Januar 2014, 19:26
von BlackJack
@Leonidas: Ich ging davon aus das wir von Python reden und nicht von Interna einer bestimmten Implementierung wo man schmutzige Hacks anwenden kann. :-)

Re: Klassenmethode kann nicht gleichzeiting Membername sein?

Verfasst: Samstag 1. Februar 2014, 00:27
von DasIch
Also so schmutzig ist dass gar nicht, nachdem man die Magie hinter einer Metaklasse versteckt hat :)

Code: Alles auswählen

import sys
import dis
import inspect


NO_ATTRIBUTE = object()


class SeparateNamedspacedMeta(type):
    def __new__(cls, name, bases, attributes):
        _methods = {}
        for name, attribute in attributes.iteritems():
            if name.startswith('__') and name.endswith('__'):
                continue
            if inspect.isfunction(attribute):
                _methods[name] = attribute
                attributes[name] = AttributeOrMethodDescriptor(name)
        attributes['_methods'] = _methods
        return type.__new__(cls, name, bases, attributes)


class AttributeOrMethodDescriptor(object):
    def __init__(self, name):
        self.name = name
        self.attribute_value = NO_ATTRIBUTE

    def __get__(self, instance, owner):
        if instance is None or self.attribute_value is NO_ATTRIBUTE:
            return owner._methods[self.name].__get__(instance, owner)
        calling_frame = sys._getframe(1)
        next_opcode = ord(calling_frame.f_code.co_code[calling_frame.f_lasti + 3])
        if dis.opname[next_opcode] == 'CALL_FUNCTION':
            return owner._methods[self.name].__get__(instance, owner)
        return self.attribute_value

    def __set__(self, instance, value):
        self.attribute_value = value

    def __delete__(self, instance):
        self.attribute_value = NO_ATTRIBUTE


class SeparateNamespacedClass(object):
    __metaclass__ = SeparateNamedspacedMeta

    def __init__(self):
        self.spam = 'attribute'

    def spam(self):
        return 'method'


foo = SeparateNamespacedClass()
print SeparateNamespacedClass.spam # <unbound method spam.spam>
print foo.spam # attribute
print foo.spam() # method

Re: Klassenmethode kann nicht gleichzeiting Membername sein?

Verfasst: Samstag 1. Februar 2014, 00:50
von BlackJack
Egal was man da drumherum an Magie veranstaltet: ``next_opcode = ord(calling_frame.f_code.co_code[calling_frame.f_lasti + 3])`` wird unter Jython, IronPython, und PyPy wohl nicht funktionieren. Das ist halt ein Implementierungsdetail von CPython. `sys._getframe()` kann man ja im Grunde schon nicht als gegeben ansehen. Und es löst nicht das Problem das man manchmal auch die Methode haben möchte ohne sie direkt aufzurufen.

Re: Klassenmethode kann nicht gleichzeiting Membername sein?

Verfasst: Samstag 1. Februar 2014, 01:05
von DasIch
Das war auch nicht ganz ernst gemeint ;)

Tatsächlich funktioniert der Code unter PyPy nicht weil PyPy eine Optimierung für Methodenaufrufe hat. PyPys Compiler produziert statt CALL_FUNCTION an dieser Stelle CALL_METHOD und damit funktioniert es nicht mehr.