@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.
Klassenmethode kann nicht gleichzeiting Membername sein?
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
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
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
@Leonidas: Ich ging davon aus das wir von Python reden und nicht von Interna einer bestimmten Implementierung wo man schmutzige Hacks anwenden kann.
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
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.
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.
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.