Seite 1 von 2
Klassenmethode kann nicht gleichzeiting Membername sein?
Verfasst: Donnerstag 30. Januar 2014, 15:53
von Krischu
Mir fällt gerade auf, als ich eine membervariable self.header eingeführt hatte und eine
methode header() definiert hatte. Das scheint nicht erlaubt zu sein.
Re: Klassenmethode kann nicht gleichzeiting Membername sein?
Verfasst: Donnerstag 30. Januar 2014, 16:00
von cofi
Und du suchst jetzt eine Bestaetigung? Ja, ein Name/Attribut kann immer nur auf ein Objekt verweisen. Aber verboten ist es deshalb nicht. Man darf sich damit gerne selbst ins Knie schiessen.
So, warum macht es keinen Sinn dass der Name auf 2 Objekte verweisen koennte? Weil der Zugriffsweg derselbe ist. Du kannst an ein Attribut beliebige Werte zuweisen, u.a. auch Funktionen. Wie soll man dann zwischen dem Aufruf der "richtigen" Methode `Klass.header` und dem Aufruf einer Funktion, die an `klass.header` gebunden ist, unterscheiden?
Re: Klassenmethode kann nicht gleichzeiting Membername sein?
Verfasst: Donnerstag 30. Januar 2014, 16:02
von BlackJack
@Krischu:Das ist doch irgendwie klar, denn wie sollte ein Objekt denn auch mehrere Attribute mit dem gleichen Namen haben? Methoden benennt man üblicherweise auch nach Tätigkeiten, denn die tun ja etwas. Für `header()` gibt es also vielleicht einen besseren Namen der dem Leser verrät was die Methode tut.
Re: Klassenmethode kann nicht gleichzeiting Membername sein?
Verfasst: Donnerstag 30. Januar 2014, 17:37
von Krischu
cofi hat geschrieben:Und du suchst jetzt eine Bestaetigung? Ja, ein Name/Attribut kann immer nur auf ein Objekt verweisen. Aber verboten ist es deshalb nicht. Man darf sich damit gerne selbst ins Knie schiessen.
So, warum macht es keinen Sinn dass der Name auf 2 Objekte verweisen koennte? Weil der Zugriffsweg derselbe ist. Du kannst an ein Attribut beliebige Werte zuweisen, u.a. auch Funktionen. Wie soll man dann zwischen dem Aufruf der "richtigen" Methode `Klass.header` und dem Aufruf einer Funktion, die an `klass.header` gebunden ist, unterscheiden?
indem ich sage
Code: Alles auswählen
klass.header - damit greife ich direkt auf self.header zu (auch komisch, daß ich von draußen drauf zugreifen kann, aber gut
Python hat keine private members.
klass.header() - ist der Methodenaufruf. Was wäre daran verboten?
Re: Klassenmethode kann nicht gleichzeiting Membername sein?
Verfasst: Donnerstag 30. Januar 2014, 17:42
von EyDu
Krischu hat geschrieben:code=python file=Untitled.py]klass.header - damit greife ich direkt auf self.header zu (auch komisch, daß ich von draußen drauf zugreifen kann, aber gut Python hat keine private members.
Python benötigt keine privaten Attribute, dass wird über Konvention geregelt. Wenn du etwas als Implementierungsdetail kennzeichen willst, dann benutze Namen mit einem führenden Unterstrich.
Krischu hat geschrieben:klass.header() - ist der Methodenaufruf. Was wäre daran verboten?
Weil die Namensauflösung in Python anders funktioniert. Mit ``klass.header`` holst du dir das header-Attribut von "klass". Dabei kann "header" alles mögliche sein: ein Integer, ein Float oder auch etwas Aufrufbares wie eine Methode (Funktionen sind in Python First-Class-Objekte). Wenn du also ``klass.header()`` schreibst, dann holst du dir das header-Objekt und rufst dieses auf. Was konkret bedeutet, dass du die __call__-Methode von "header" aufrufst.
Code: Alles auswählen
>>> class Spam(object):
... def ham(self, x):
... print x
...
>>> s = Spam()
>>> h = s.ham
>>> h(42)
42
>>> h.__call__(42)
42
Re: Klassenmethode kann nicht gleichzeiting Membername sein?
Verfasst: Donnerstag 30. Januar 2014, 18:46
von Sirius3
oder der gegenteilige Fall:
Code: Alles auswählen
>>> class Spam(object):
... def __init__(self):
... self.ham = None
...
>>> def egg(x):
... print x
...
>>> spam = Spam()
>>> spam.ham = egg
>>> spam.ham(42)
42
>>>
Re: Klassenmethode kann nicht gleichzeiting Membername sein?
Verfasst: Freitag 31. Januar 2014, 01:33
von Leonidas
Du kannst natürlich auch ``self.header = 42`` setzen und dann versuchen ``self.header()`` aufzurufen und gucken was passiert. Tipp: 42 ist nicht "callable".
Re: Klassenmethode kann nicht gleichzeiting Membername sein?
Verfasst: Freitag 31. Januar 2014, 08:11
von mutetella
Wenn man mal nicht über Sinn oder Unsinn einer solchen Aktion nachdenkt: Wo genau ist die Stelle, an der man sich einklinken müsste, um zu ermitteln, ob ein Name abgefragt oder aufgerufen wird, sprich ob Klammern gesetzt sind oder nicht?
mutetella
Re: Klassenmethode kann nicht gleichzeiting Membername sein?
Verfasst: Freitag 31. Januar 2014, 09:49
von kbr
mutetella hat geschrieben:Wo genau ist die Stelle, an der man sich einklinken müsste, um zu ermitteln, ob ein Name abgefragt oder aufgerufen wird, sprich ob Klammern gesetzt sind oder nicht?
Meinst Du so was?
Code: Alles auswählen
>>> class A(object):
... b = 42
... def c(self):
... pass
...
>>> a = A()
>>> type(a.b)
<type 'int'>
>>> type(a.c)
<type 'instancemethod'>
Re: Klassenmethode kann nicht gleichzeiting Membername sein?
Verfasst: Freitag 31. Januar 2014, 11:12
von BlackJack
@mutetella: Da gibt es keine Stelle denn ein Attribut wird immer erst mit dem Punktoperator abgefragt, egal ob es ein ”Datenattribut” oder eine gebundene Methode ist. Und ob und wann das Objekt dann aufgerufen wird, sagt einem immer noch nicht ob es sich um eine Methode dieses Objekts oder ein ”Datenattribut” handelt. Und da der Punktoperator und das Aufrufen komplett voneinander unabhängig sind, kann man auch nicht Unterscheiden ob der Abrufer des Attributs ein ”Datenattribut” oder eine Methode haben wollte, wenn man denn diese zwei ”verschiedenen” Sachen unter dem selben Attributnamen anbieten möchte.
Re: Klassenmethode kann nicht gleichzeiting Membername sein?
Verfasst: Freitag 31. Januar 2014, 12:12
von diesch
Methoden sind in Python normale Objekte wie Strings, Zahlen usw. auch. Ich kann daher so was schreiben:
Code: Alles auswählen
class Foo:
def __init__(self):
self.a = 42
def b(self):
return 17
foo=Foo()
for name in 'a', 'b':
attr = getattr(foo, name)
if callable(attr):
value = attr()
else:
value = attr
print('%s: %s' % (name, value))
Re: Klassenmethode kann nicht gleichzeiting Membername sein?
Verfasst: Freitag 31. Januar 2014, 14:12
von mutetella
@BlackJack:
Keine Stelle, die ich mit Pythonmitteln erreiche oder generell keine, bzw. nur, wenn ich den Interpreter verändere?
mutetella
Re: Klassenmethode kann nicht gleichzeiting Membername sein?
Verfasst: Freitag 31. Januar 2014, 15:01
von BlackJack
@mutetella: Vielleicht solltest Du noch mal genau beschreiben was Du erreichen willst. Ob ein Name abgefragt oder (das Objekt hinter einem Namen) aufgerufen wird ist jedenfalls keine sauber getrennte Unterscheidung, weil aufrufen in diesem Fall immer ein abfragen vorausgehen muss. ``obj.spam()`` ist nicht eine Operation sondern zwei, das kann man auch entsprechend Klammern um es zu verdeutlichen: ``(obj . spam)()``. Das ist legale Python-Syntax.
Und ob ein abgefragtes Attribut aufgerufen wird: Wie willst Du das testen. Das muss ja auch nicht zwingend direkt nach dem Abfragen passieren wie von anderen ja hier schon an Beispielen gezeigt wurde.
Re: Klassenmethode kann nicht gleichzeiting Membername sein?
Verfasst: Freitag 31. Januar 2014, 16:51
von mutetella
@BlackJack
Ich meine, ob sowas in dieser Art machbar wäre:
Code: Alles auswählen
class Nonsense(object):
def __init__(self):
self._multiple = ('any_value', self.any_callable)
def any_callable(self, value):
pass
@property
def multiple(self):
request_has_brackets, value = interpreter.please_give_it_to_me()
if request_has_brackets:
return self._multiple[1](value)
return self._multiple[0]
mutetella
Re: Klassenmethode kann nicht gleichzeiting Membername sein?
Verfasst: Freitag 31. Januar 2014, 17:25
von cofi
@mutetella: Nein, das laesst die Semantik nicht zu. Wie BlackJack schon geschrieben hat, sind es zwei Operationen, die man u.a. auch trennen kann.
Selbst wenn man den Zugriff auf Methoden und Datenattributen noch durch einen moeglichen Aufruf unterscheiden koennte: Das ist zu kurz gegriffen, denn man verbietet damit zum einen callables als Datenattribute und zum anderen den blossen Zugriff auf die Methoden-Objekte.
Was man machen koennte ist, manuell 2 Namensraeume fuer Daten und Methoden einzufuehren ... nur braeuchte man dann zumindest fuer eines einen eigenen Zugriffweg, sonst steht man wieder vor dem Problem von oben.
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.