Domanda

Quello che sto cercando di ottenere è qualcosa del genere:

class object:
    def __init__(self):
        WidthVariable(self)

        print self.width
        #Imagine I did this 60frames/1second later
        print self.width

#output:
>>0
>>25

Cosa voglio che succeda (come sopra): quando viene creato WidthVariable - una classe - aggiunge la variabile width all'oggetto istanza . Questa variabile si comporta come una normale proprietà, ma in questo caso particolare è di sola lettura (è impostata solo la variabile fget ). Inoltre, fget chiama una funzione definita in WidthVariable che decide quale larghezza restituire.

Tuttavia, non ho idea di come farlo! L'ho provato usando le normali proprietà ma ho scoperto che funzionano solo su classi e non per istanza - tieni presente che il codice che uso dovrebbe essere il più simile possibile al precedente (cioè solo il codice all'interno del __init__ di WidthVariable dovrebbe impostare la variabile width , da nessun'altra parte). Inoltre, self.width non può essere funzionale, perché non so come chiamarlo self.width () , voglio self.width (perché continua con il resto del design che ho).

Per chiarire, il codice completo sarebbe qualcosa del genere:

class MyObject:
    def __init__(self)
        WidthVariable(self)
        print self.width

class WidthVariable:
    def __init__(self, object)
        object.width = property(self.get_width)

    def get_width(self):
        value = #do_stuff
        return value #The Value

#output:
>>25 #Whatever the Value was
È stato utile?

Soluzione

Dal momento che, come dice @Jonathan, i descrittori (comprese le proprietà) sono per classe, non per istanza, l'unico modo per ottenere descrittori per istanza diversi è quello di far individuare ciascuna istanza alla propria classe. È piuttosto superficiale e facile per quanto riguarda la metaprogrammazione; -) ...:

class Individualistic(object_or_whatever_bases):
  def __init__(self, whatever_args):
    self.__class__ = type('GottaBeMe', (self.__class__, object), {})
    # keep rocking...!-)

Sto anche aggiungendo oggetto esplicitamente perché è necessario (in Python 2. * , e dici che è quello che stai usando !!!) per creare classi di nuovo tipo. Non usare più classi legacy, non si comportano correttamente rispetto alle proprietà e molto altro (e per la retrocompatibilità non possono - in Python 3, le classi legacy sono state finalmente annientate, quindi OGNI classe è di nuovo stile senza l'obbligo di ereditare più esplicitamente dall'oggetto!).

Ora, qualsiasi descrittore inserito in self .__ class __.__ dict__ influenzerà solo questa istanza, nessuna altra. C'è un po 'di overhead (ogni classe GottaBeMe e quindi ogni istanza ha il suo __dict__ , ecc.), Ma niente di troppo terribile.

Ora, tutto ciò che serve per soddisfare la richiesta originale è cambiare:

class WidthVariable:
    def __init__(self, object)
        object.width = property(self.get_width)

(anche rinominando oggetto arg in modo ragionevole per evitare di calpestare un built-in e rendere la classe di nuovo stile perché dovresti SEMPRE rendere SEMPRE un nuovo stile di classe ;-), a:

class WidthVariable(object):
    def __init__(self, obj)
        obj.__class__.width = property(self.get_width)

Niente di troppo oscuro, come puoi vedere! -)

Altri suggerimenti

Non capisco il modo in cui hai costruito il tuo esempio, né capisco cosa intendi per "proprietà normali". funziona solo "su classi". Ecco come creare una proprietà di sola lettura:

class Foo(object):
    # create read-only property "rop"
    rop = property(lambda self: self._x)

    def __init__(self):
        self._x = 0

    def tick(self):
        self._x += 1    

f = Foo()
print f.rop # prints 0
f.tick()
f.tick()
print f.rop # prints 2
f.rop = 4 # this will raise AtributeError

Ora credo di capire la tua domanda e credo anche che tu sia per sfortuna .

  

Per le classi di nuovo stile, implicito   invocazioni di metodi speciali sono   garantito solo per funzionare correttamente se   definito sul tipo di un oggetto, non in   il dizionario dell'istanza dell'oggetto.

I descrittori (utilizzati per implementare le proprietà) devono apparire nella classe __dict__ e non possono apparire nella istanza __dict__ . In altre parole, Python non è Ruby!

Attendo felicemente la correzione da un pio metaprogrammatore di Python, ma penso di avere ragione.

Non hai capito bene cosa vuoi? ma suppongo che tu voglia personalizzare obj.width per ogni istanza Ecco un modo semplice usando le proprietà semplici, la proprietà width restituisce il valore restituito da un callback per istanza

class MyClass(object):
    def __init__(self, callback):
        self.callback = callback

    def get_width(self):
        return self.callback()

    width = property(get_width)

def w1(): return 0
def w2(): return 25

o1 = MyClass(w1)
o2 = MyClass(w2)

print o1.width
print o2.width

Se il callback non può essere passato, possiamo assegnarlo a WidthVariable che restituisce larghezza in base all'istanza

class MyClass(object):
    def __init__(self):
        self.callback = WidthVariable(self)

    def get_width(self):
        return self.callback()

    width = property(get_width)

class WidthVariable(object):
    def __init__(self, obj):
        self.obj = obj

    def __call__(self):
        return hash(self.obj)

o1 = MyClass()
o2 = MyClass()

print o1.width
print o2.width
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top