Aggiunta di un metodo a un'istanza oggetto esistente

voti
488

Ho letto che è possibile aggiungere un metodo a un oggetto esistente (cioè, non nella definizione della classe) in Python.

Capisco che non è sempre bene farlo. Ma come può uno fare questo?

È pubblicato 04/08/2008 alle 01:17
fonte dall'utente
In altre lingue...                            


18 risposte

voti
16

In Python scimmia patch generalmente funziona sovrascrivendo una classe o di funzioni di firma con il proprio. Di seguito è riportato un esempio dalla Zope Wiki :

from SomeOtherProduct.SomeModule import SomeClass
def speak(self):
   return "ook ook eee eee eee!"
SomeClass.speak = speak

Quel codice sovrascrive / creare un metodo chiamato parlare sulla classe. In Jeff Atwood recente post sul scimmia patch . Egli mostra un esempio in C # 3.0, che è la lingua corrente che uso per lavoro.

Risposto il 04/08/2008 a 01:31
fonte dall'utente

voti
-8

Non so la sintassi di Python, ma so di Ruby può farlo, ed è piuttosto banale. Diciamo che si desidera aggiungere un metodo per Array che stampa la lunghezza fuori standard:

class Array
  def print_length
    puts length
  end
end

Se non si desidera modificare tutta la classe, si può semplicemente aggiungere il metodo a una singola istanza della matrice, e nessun altro array avrà il metodo:

array = [1, 2, 3]
def array.print_length
  puts length
end

Basta essere consapevoli dei problemi coinvolti in questa funzione. Jeff Atwood in realtà ha scritto su di esso non troppo tempo fa.

Risposto il 04/08/2008 a 01:36
fonte dall'utente

voti
736

In Python, v'è una differenza tra le funzioni e metodi vincolati.

>>> def foo():
...     print "foo"
...
>>> class A:
...     def bar( self ):
...         print "bar"
...
>>> a = A()
>>> foo
<function foo at 0x00A98D70>
>>> a.bar
<bound method A.bar of <__main__.A instance at 0x00A9BC88>>
>>>

Metodi vincolati sono stati "legati" (come descrittiva) a un'istanza, e tale istanza sarà passata come primo argomento ogni volta che viene chiamato il metodo.

Callable che sono attributi di una classe (al contrario di un esempio) sono ancora legato, anche se, in modo da poter modificare la definizione di classe ogni volta che vuoi:

>>> def fooFighters( self ):
...     print "fooFighters"
...
>>> A.fooFighters = fooFighters
>>> a2 = A()
>>> a2.fooFighters
<bound method A.fooFighters of <__main__.A instance at 0x00A9BEB8>>
>>> a2.fooFighters()
fooFighters

le istanze precedentemente definite vengono aggiornati così (a patto che essi non hanno ignorato l'attributo se stessi):

>>> a.fooFighters()
fooFighters

Il problema nasce quando si desidera allegare un metodo per una singola istanza:

>>> def barFighters( self ):
...     print "barFighters"
...
>>> a.barFighters = barFighters
>>> a.barFighters()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: barFighters() takes exactly 1 argument (0 given)

La funzione non è vincolata automaticamente quando è associato direttamente a un'istanza:

>>> a.barFighters
<function barFighters at 0x00A98EF0>

Per associare, possiamo utilizzare la funzione di MethodType nel modulo tipi :

>>> import types
>>> a.barFighters = types.MethodType( barFighters, a )
>>> a.barFighters
<bound method ?.barFighters of <__main__.A instance at 0x00A9BC88>>
>>> a.barFighters()
barFighters

Questa volta le altre istanze della classe non sono state colpite:

>>> a2.barFighters()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: A instance has no attribute 'barFighters'

Maggiori informazioni possono essere trovate leggendo su descrittori e metaclasse programmazione .

Risposto il 05/08/2008 a 23:33
fonte dall'utente

voti
6

Quello che stai cercando è setattrcredo. Usare questo per impostare un attributo su un oggetto.

>>> def printme(s): print repr(s)
>>> class A: pass
>>> setattr(A,'printme',printme)
>>> a = A()
>>> a.printme() # s becomes the implicit 'self' variable
< __ main __ . A instance at 0xABCDEFG>
Risposto il 07/08/2008 a 10:30
fonte dall'utente

voti
4

Che Jason Pratt ha scritto è corretto.

>>> class Test(object):
...   def a(self):
...     pass
... 
>>> def b(self):
...   pass
... 
>>> Test.b = b
>>> type(b)
<type 'function'>
>>> type(Test.a)
<type 'instancemethod'>
>>> type(Test.b)
<type 'instancemethod'>

Come si può vedere, Python non considera b () qualcosa di diverso rispetto a (). In Python tutti i metodi sono solo le variabili che capita di essere le funzioni.

Risposto il 22/08/2008 a 13:40
fonte dall'utente

voti
80

Modulo nuovo è deprecato dal Python 2.6 e rimosso in 3.0, utilizzare i tipi

vedi http://docs.python.org/library/new.html

Nell'esempio che segue ho volutamente rimosso valore restituito da patch_me()funzione. Penso che dare valore di ritorno può far credere che cerotto restituisce un nuovo oggetto, che non è vero - si modifica quello in entrata. Probabilmente questo può facilitare un uso più disciplinato monkeypatching.

import types

class A(object):#but seems to work for old style objects too
    pass

def patch_me(target):
    def method(target,x):
        print "x=",x
        print "called from", target
    target.method = types.MethodType(method,target)
    #add more if needed

a = A()
print a
#out: <__main__.A object at 0x2b73ac88bfd0>  
patch_me(a)    #patch instance
a.method(5)
#out: x= 5
#out: called from <__main__.A object at 0x2b73ac88bfd0>
patch_me(A)
A.method(6)        #can patch class too
#out: x= 6
#out: called from <class '__main__.A'>
Risposto il 06/06/2009 a 04:31
fonte dall'utente

voti
30

Credo che le risposte di cui sopra mancato il punto chiave.

Diamo una classe con un metodo:

class A(object):
    def m(self):
        pass

Ora, cerchiamo di giocare con lui in ipython:

In [2]: A.m
Out[2]: <unbound method A.m>

Ok, quindi m () diventa in qualche modo un metodo non legato di A . Ma è davvero così?

In [5]: A.__dict__['m']
Out[5]: <function m at 0xa66b8b4>

Si scopre che m () è solo una funzione, riferimento al quale viene aggiunto un dizionario di classe - non c'è nessuna magia. Allora perché Am ci dà un metodo non legato? È perché il punto non è tradotto in una semplice consultazione dei dizionari. E 'di fatto una chiamata di A .__ classe __.__ getattribute __ (A, 'm'):

In [11]: class MetaA(type):
   ....:     def __getattribute__(self, attr_name):
   ....:         print str(self), '-', attr_name

In [12]: class A(object):
   ....:     __metaclass__ = MetaA

In [23]: A.m
<class '__main__.A'> - m
<class '__main__.A'> - m

Ora, io non sono sicuro dalla parte superiore della mia testa perché l'ultima riga viene stampato due volte, ma comunque è chiaro che cosa sta succedendo lì.

Ora, ciò che il __getattribute__ di default fa è che controlla se l'attributo è un cosiddetto descrittore o no, vale a dire se si implementa un metodo __get__ speciale. Se si implementa tale metodo, quindi ciò che viene restituito è il risultato della chiamata che il metodo __get__. Tornando alla prima versione del nostro A di classe, questo è ciò che abbiamo:

In [28]: A.__dict__['m'].__get__(None, A)
Out[28]: <unbound method A.m>

E perché le funzioni Python implementare il protocollo descrittore, se essi sono chiamati a nome di un oggetto, si legano a tale oggetto nel loro metodo __get__.

Ok, così come aggiungere un metodo a un oggetto esistente? Supponendo che non vi occupate di classe patch, è semplice come:

B.m = m

Poi Bm "diventa" un metodo non legato, grazie alla magia descrittore.

E se si desidera aggiungere un metodo solo per un singolo oggetto, poi si deve emulare la macchina da soli, utilizzando types.MethodType:

b.m = types.MethodType(m, b)

A proposito:

In [2]: A.m
Out[2]: <unbound method A.m>

In [59]: type(A.m)
Out[59]: <type 'instancemethod'>

In [60]: type(b.m)
Out[60]: <type 'instancemethod'>

In [61]: types.MethodType
Out[61]: <type 'instancemethod'>
Risposto il 22/01/2012 a 12:20
fonte dall'utente

voti
5

Consolidare Jason Pratt e il wiki comunità di risposte, con uno sguardo ai risultati di diversi metodi di rilegatura:

Soprattutto notare come l'aggiunta la funzione di legame come metodo di classe funziona , ma il campo di applicazione fa riferimento non è corretto.

#!/usr/bin/python -u
import types
import inspect

## dynamically adding methods to a unique instance of a class


# get a list of a class's method type attributes
def listattr(c):
    for m in [(n, v) for n, v in inspect.getmembers(c, inspect.ismethod) if isinstance(v,types.MethodType)]:
        print m[0], m[1]

# externally bind a function as a method of an instance of a class
def ADDMETHOD(c, method, name):
    c.__dict__[name] = types.MethodType(method, c)

class C():
    r = 10 # class attribute variable to test bound scope

    def __init__(self):
        pass

    #internally bind a function as a method of self's class -- note that this one has issues!
    def addmethod(self, method, name):
        self.__dict__[name] = types.MethodType( method, self.__class__ )

    # predfined function to compare with
    def f0(self, x):
        print 'f0\tx = %d\tr = %d' % ( x, self.r)

a = C() # created before modified instnace
b = C() # modified instnace


def f1(self, x): # bind internally
    print 'f1\tx = %d\tr = %d' % ( x, self.r )
def f2( self, x): # add to class instance's .__dict__ as method type
    print 'f2\tx = %d\tr = %d' % ( x, self.r )
def f3( self, x): # assign to class as method type
    print 'f3\tx = %d\tr = %d' % ( x, self.r )
def f4( self, x): # add to class instance's .__dict__ using a general function
    print 'f4\tx = %d\tr = %d' % ( x, self.r )


b.addmethod(f1, 'f1')
b.__dict__['f2'] = types.MethodType( f2, b)
b.f3 = types.MethodType( f3, b)
ADDMETHOD(b, f4, 'f4')


b.f0(0) # OUT: f0   x = 0   r = 10
b.f1(1) # OUT: f1   x = 1   r = 10
b.f2(2) # OUT: f2   x = 2   r = 10
b.f3(3) # OUT: f3   x = 3   r = 10
b.f4(4) # OUT: f4   x = 4   r = 10


k = 2
print 'changing b.r from {0} to {1}'.format(b.r, k)
b.r = k
print 'new b.r = {0}'.format(b.r)

b.f0(0) # OUT: f0   x = 0   r = 2
b.f1(1) # OUT: f1   x = 1   r = 10  !!!!!!!!!
b.f2(2) # OUT: f2   x = 2   r = 2
b.f3(3) # OUT: f3   x = 3   r = 2
b.f4(4) # OUT: f4   x = 4   r = 2

c = C() # created after modifying instance

# let's have a look at each instance's method type attributes
print '\nattributes of a:'
listattr(a)
# OUT:
# attributes of a:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x000000000230FD88>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x000000000230FD88>>
# f0 <bound method C.f0 of <__main__.C instance at 0x000000000230FD88>>

print '\nattributes of b:'
listattr(b)
# OUT:
# attributes of b:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x000000000230FE08>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x000000000230FE08>>
# f0 <bound method C.f0 of <__main__.C instance at 0x000000000230FE08>>
# f1 <bound method ?.f1 of <class __main__.C at 0x000000000237AB28>>
# f2 <bound method ?.f2 of <__main__.C instance at 0x000000000230FE08>>
# f3 <bound method ?.f3 of <__main__.C instance at 0x000000000230FE08>>
# f4 <bound method ?.f4 of <__main__.C instance at 0x000000000230FE08>>

print '\nattributes of c:'
listattr(c)
# OUT:
# attributes of c:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x0000000002313108>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x0000000002313108>>
# f0 <bound method C.f0 of <__main__.C instance at 0x0000000002313108>>

Personalmente, preferisco la via funzione di ADDMETHOD esterna, in quanto mi permette di assegnare dinamicamente nuovi nomi di metodo all'interno di un iteratore pure.

def y(self, x):
    pass
d = C()
for i in range(1,5):
    ADDMETHOD(d, y, 'f%d' % i)
print '\nattributes of d:'
listattr(d)
# OUT:
# attributes of d:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x0000000002303508>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x0000000002303508>>
# f0 <bound method C.f0 of <__main__.C instance at 0x0000000002303508>>
# f1 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
# f2 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
# f3 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
# f4 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
Risposto il 27/01/2012 a 22:12
fonte dall'utente

voti
6

Dal momento che questa domanda ha chiesto per le versioni non-Python, ecco JavaScript:

a.methodname = function () { console.log("Yay, a new method!") }
Risposto il 09/03/2012 a 13:07
fonte dall'utente

voti
9

Ci sono almeno due modi per allegare un metodo per un'istanza senza types.MethodType:

>>> class A:
...  def m(self):
...   print 'im m, invoked with: ', self

>>> a = A()
>>> a.m()
im m, invoked with:  <__main__.A instance at 0x973ec6c>
>>> a.m
<bound method A.m of <__main__.A instance at 0x973ec6c>>
>>> 
>>> def foo(firstargument):
...  print 'im foo, invoked with: ', firstargument

>>> foo
<function foo at 0x978548c>

1:

>>> a.foo = foo.__get__(a, A) # or foo.__get__(a, type(a))
>>> a.foo()
im foo, invoked with:  <__main__.A instance at 0x973ec6c>
>>> a.foo
<bound method A.foo of <__main__.A instance at 0x973ec6c>>

2:

>>> instancemethod = type(A.m)
>>> instancemethod
<type 'instancemethod'>
>>> a.foo2 = instancemethod(foo, a, type(a))
>>> a.foo2()
im foo, invoked with:  <__main__.A instance at 0x973ec6c>
>>> a.foo2
<bound method instance.foo of <__main__.A instance at 0x973ec6c>>

Link utili:
Modello di dati - invocando descrittori
Guida descrittore HowTo - descrittori invocando

Risposto il 26/04/2013 a 14:47
fonte dall'utente

voti
5

Voi ragazzi dovrebbe davvero guardare frutto proibito , è una libreria Python che fornisce il supporto per l'applicazione di patch scimmia qualsiasi classe di pitone, anche le stringhe.

Risposto il 25/08/2013 a 20:56
fonte dall'utente

voti
3

Se può essere di alcun aiuto, mi ha recentemente rilasciato una libreria Python chiamato Gorilla per rendere il processo di patching scimmia più conveniente.

Utilizzando una funzione needle()di rattoppare un modulo di nome guineapigè la seguente:

import gorilla
import guineapig
@gorilla.patch(guineapig)
def needle():
    print("awesome")

Ma si occupa anche di casi d'uso più interessanti come indicato nella FAQ della documentazione .

Il codice è disponibile su GitHub .

Risposto il 15/07/2014 a 01:12
fonte dall'utente

voti
7

È possibile utilizzare lambda per associare un metodo a un'istanza:

def run(self):
    print self._instanceString

class A(object):
    def __init__(self):
        self._instanceString = "This is instance string"

a = A()
a.run = lambda: run(a)
a.run()

Questa è la stringa istanza

Processo terminato con codice di uscita 0

Risposto il 21/07/2014 a 11:55
fonte dall'utente

voti
47

Aggiunta di un metodo a un'istanza oggetto esistente

Ho letto che è possibile aggiungere un metodo a un oggetto esistente (ad esempio, non nella definizione della classe) in Python.

Capisco che non è sempre una buona decisione in tal senso. Ma, come potrebbe uno fare questo?

Sì, è possibile - ma non è raccomandato

Non consiglio questo. Questa è una cattiva idea. Non farlo.

Ecco un paio di motivi:

  • Verrà aggiunto un oggetto associato a ogni istanza si esegue questa operazione a. Se si esegue questa operazione molto, probabilmente sprecare un sacco di memoria. metodi legati vengono in genere creati solo per la breve durata della loro chiamata, e poi cessano di esistere quando automaticamente garbage collection. Se si esegue questa operazione manualmente, avrete un nome vincolante riferimento al metodo vincolato - che impedirà la sua raccolta dei rifiuti sul loro utilizzo.
  • Istanze di oggetti di un dato tipo presentano generalmente suoi metodi su tutti gli oggetti di quel tipo. Se si aggiungono i metodi altrove, alcuni casi avranno quei metodi e altri no. I programmatori non si aspettano questo, e si rischia di violare la regola della minima sorpresa .
  • Dato che ci sono altri davvero buoni motivi per non fare questo, ti inoltre ti dai una cattiva reputazione se lo si fa.

Così, vi suggerisco di non fare questo se non si ha una buona ragione. È molto meglio definire il metodo corretto nella definizione di classe o meno , preferibilmente di scimmia-patch classe direttamente, in questo modo:

Foo.sample_method = sample_method

Dal momento che è istruttivo, però, ho intenzione di mostrarvi alcuni modi di fare questo.

Come si può fare

Ecco alcuni codice di installazione. Abbiamo bisogno di una definizione di classe. Potrebbe essere importato, ma in realtà non importa.

class Foo(object):
    '''An empty class to demonstrate adding a method to an instance'''

Creare un'istanza:

foo = Foo()

Creare un metodo per aggiungere ad essa:

def sample_method(self, bar, baz):
    print(bar + baz)

Metodo zero (0) - utilizzare il metodo descrittore, __get__

Ricerche tratteggiate sulle funzioni chiamano il __get__metodo della funzione con l'istanza, legando l'oggetto al metodo e creando così una "metodo vincolato".

foo.sample_method = sample_method.__get__(foo)

e adesso:

>>> foo.sample_method(1,2)
3

Metodo uno - types.MethodType

In primo luogo, tipi di importazione, da cui si otterrà il costruttore metodo:

import types

Ora aggiungiamo il metodo per l'istanza. Per fare questo, abbiamo bisogno il costruttore MethodType dal typesmodulo (che abbiamo importato sopra).

La firma argomento per types.MethodType è (function, instance, class):

foo.sample_method = types.MethodType(sample_method, foo, Foo)

e il loro utilizzo:

>>> foo.sample_method(1,2)
3

Metodo due: lessicale vincolante

In primo luogo, creiamo una funzione wrapper che lega il metodo per l'istanza:

def bind(instance, method):
    def binding_scope_fn(*args, **kwargs): 
        return method(instance, *args, **kwargs)
    return binding_scope_fn

utilizzo:

>>> foo.sample_method = bind(foo, sample_method)    
>>> foo.sample_method(1,2)
3

Metodo tre: functools.partial

Una funzione parziale applica il primo argomento (s) ad una funzione (e opzionalmente argomenti di parole chiave), e può essere successivamente chiamata con gli argomenti rimanenti (e argomenti chiave imperative). Così:

>>> from functools import partial
>>> foo.sample_method = partial(sample_method, foo)
>>> foo.sample_method(1,2)
3    

Questo ha senso se si considera che i metodi bound sono funzioni parziali dell'istanza.

Funzione non legato come un attributo dell'oggetto - il motivo per cui questo non funziona:

Se cerchiamo di aggiungere il sample_method nello stesso modo in cui potremmo aggiungere alla classe, è non legato dall'istanza, e non tiene il sé implicita come primo argomento.

>>> foo.sample_method = sample_method
>>> foo.sample_method(1,2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: sample_method() takes exactly 3 arguments (2 given)

Siamo in grado di far funzionare la funzione non associata passando esplicitamente l'istanza (o qualsiasi cosa, dal momento che questo metodo non viene effettivamente utilizzato la selfvariabile di argomento), ma non sarebbe coerente con la firma prevista di altri casi (se siamo scimmia-patching questo esempio):

>>> foo.sample_method(foo, 1, 2)
3

Conclusione

Ora sapete diversi modi si può fare questo, ma in tutta serietà - non si esegue questa.

Risposto il 21/01/2015 a 03:31
fonte dall'utente

voti
5

Questo è in realtà un addon per la risposta di "Jason Pratt"

Anche se Jasons rispondere opere, funziona solo se si vuole aggiungere una funzione a una classe. Non ha funzionato per me quando ho provato a caricare un metodo già esistente dal file di codice sorgente .py.

Mi ci sono voluti secoli per trovare una soluzione, ma il trucco sembra semplice ... 1.st importare il codice dal file di codice sorgente 2.nd forzare un types.FunctionType uso reload 3.rd (...) per convertire il importati e metodo associato a una funzione che si può anche trasmettere le variabili globali attuali, come il metodo ricaricato sarebbe in un diverso spazio dei nomi 4.th ora è possibile continuare come suggerito da "Jason Pratt" utilizzando il types.MethodType (... )

Esempio:

# this class resides inside ReloadCodeDemo.py
class A:
    def bar( self ):
        print "bar1"

    def reloadCode(self, methodName):
        ''' use this function to reload any function of class A'''
        import types
        import ReloadCodeDemo as ReloadMod # import the code as module
        reload (ReloadMod) # force a reload of the module
        myM = getattr(ReloadMod.A,methodName) #get reloaded Method
        myTempFunc = types.FunctionType(# convert the method to a simple function
                                myM.im_func.func_code, #the methods code
                                globals(), # globals to use
                                argdefs=myM.im_func.func_defaults # default values for variables if any
                                ) 
        myNewM = types.MethodType(myTempFunc,self,self.__class__) #convert the function to a method
        setattr(self,methodName,myNewM) # add the method to the function

if __name__ == '__main__':
    a = A()
    a.bar()
    # now change your code and save the file
    a.reloadCode('bar') # reloads the file
    a.bar() # now executes the reloaded code
Risposto il 18/08/2015 a 14:32
fonte dall'utente

voti
2

Questa domanda è stato aperto anni fa, ma hey, c'è un modo semplice per simulare il legame di una funzione a un'istanza classe utilizzando decoratori:

def binder (function, instance):
  copy_of_function = type (function) (function.func_code, {})
  copy_of_function.__bind_to__ = instance
  def bound_function (*args, **kwargs):
    return copy_of_function (copy_of_function.__bind_to__, *args, **kwargs)
  return bound_function


class SupaClass (object):
  def __init__ (self):
    self.supaAttribute = 42


def new_method (self):
  print self.supaAttribute


supaInstance = SupaClass ()
supaInstance.supMethod = binder (new_method, supaInstance)

otherInstance = SupaClass ()
otherInstance.supaAttribute = 72
otherInstance.supMethod = binder (new_method, otherInstance)

otherInstance.supMethod ()
supaInstance.supMethod ()

Lì, quando si passa la funzione e l'istanza di decoratore legante, si creerà una nuova funzione, con lo stesso codice oggetto come il primo. Quindi, l'istanza data della classe è memorizzato in un attributo della funzione appena creato. Il decoratore restituire una funzione (terzo) chiama automaticamente la funzione copiato, dando l'istanza come primo parametro.

In conclusione, si ottiene una funzione che simula è vincolante per l'istanza della classe. Lasciando la funzione originale invariata.

Risposto il 21/12/2015 a 19:39
fonte dall'utente

voti
2

Trovo strano che nessuno ha detto che tutti i metodi di cui sopra crea un riferimento ciclo tra il metodo aggiunto e l'istanza, causando l'oggetto di essere persistente fino garbage collection. C'era un vecchio trucco di aggiungere un descrittore estendendo la classe dell'oggetto:

def addmethod(obj, name, func):
    klass = obj.__class__
    subclass = type(klass.__name__, (klass,), {})
    setattr(subclass, name, func)
    obj.__class__ = subclass
Risposto il 30/04/2017 a 03:57
fonte dall'utente

voti
1
from types import MethodType

def method(self):
   print 'hi!'


setattr( targetObj, method.__name__, MethodType(method, targetObj, type(method)) )

Con questo, è possibile utilizzare il puntatore di auto

Risposto il 27/07/2017 a 03:21
fonte dall'utente

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more