Προσθέτοντας μια μέθοδο για την υπάρχουσα αντικειμένου

ψήφοι
488

Έχω διαβάσει ότι είναι δυνατό για να προσθέσετε μια μέθοδο σε ένα υπάρχον αντικείμενο (δηλαδή, όχι στον ορισμό τάξη) στην Python.

Καταλαβαίνω ότι δεν είναι πάντα καλό να το πράξει. Αλλά πώς θα μπορούσε κάποιος να το κάνετε αυτό;

Δημοσιεύθηκε 04/08/2008 στις 03:17
πηγή χρήστη
Σε άλλες γλώσσες...                            


18 απαντήσεις

ψήφοι
736

Στην Python, υπάρχει μια διαφορά μεταξύ των λειτουργιών και δεσμευμένου μεθόδους.

>>> 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>>
>>>

Δεσμώτης μέθοδοι έχουν «δεσμευμένο» (πώς περιγραφική) σε μια εμφάνιση, και ότι η περίπτωση θα πρέπει να περάσει ως το πρώτο επιχείρημα κάθε φορά που η μέθοδος ονομάζεται.

Callables που είναι χαρακτηριστικά μιας κατηγορίας (σε αντίθεση με την περίπτωση) εξακολουθούν να είναι μη συνδεδεμένο, όμως, έτσι μπορείτε να τροποποιήσετε τον ορισμό της κατηγορίας όποτε θέλετε:

>>> 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

Οι προηγουμένως ορίζεται περιπτώσεις ενημερώνεται καθώς (εφόσον δεν έχουν παρακαμφθεί οι ίδιοι το χαρακτηριστικό):

>>> a.fooFighters()
fooFighters

Το πρόβλημα έρχεται όταν θέλετε να επισυνάψετε μια μέθοδο για ένα μόνο παράδειγμα:

>>> 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)

Η λειτουργία δεν δεσμεύεται αυτόματα όταν είναι συνδεδεμένο απευθείας με ένα παράδειγμα:

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

Για να το δεσμεύουν, μπορούμε να χρησιμοποιήσουμε τη λειτουργία MethodType στη μονάδα τύπους :

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

Αυτή τη φορά οι άλλες περιπτώσεις της κατηγορίας δεν έχουν επηρεαστεί:

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

Περισσότερες πληροφορίες μπορούν να βρεθούν με την ανάγνωση για περιγραφές και μετακλάση προγραμματισμού .

Απαντήθηκε 06/08/2008 στις 01:33
πηγή χρήστη

ψήφοι
80

Ενότητα νέο έχει καταργηθεί από το python 2.6 και απομακρύνεται σε 3,0, χρήση τύπων

δείτε http://docs.python.org/library/new.html

Στο παρακάτω παράδειγμα έχω σκόπιμα αφαιρεθεί τιμή επιστροφής από patch_me()τη λειτουργία. Νομίζω ότι δίνει τιμή επιστροφής μπορεί να κάνει ένα πιστεύουν ότι μπάλωμα επιστρέφει ένα νέο αντικείμενο, το οποίο δεν είναι αλήθεια - να τροποποιεί το εισερχόμενο μία. Πιθανώς αυτό μπορεί να διευκολύνει μια πιο πειθαρχημένη χρήση 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'>
Απαντήθηκε 06/06/2009 στις 06:31
πηγή χρήστη

ψήφοι
47

Προσθέτοντας μια μέθοδο για την υπάρχουσα αντικειμένου

Έχω διαβάσει ότι είναι δυνατό για να προσθέσετε μια μέθοδο σε ένα υπάρχον αντικείμενο (π.χ. όχι στον ορισμό τάξη) στην Python.

Καταλαβαίνω ότι δεν είναι πάντα μια καλή απόφαση να το πράξει. Αλλά, πώς θα μπορούσε κάποιος να το κάνετε αυτό;

Ναι, είναι δυνατόν - Αλλά δεν συνιστάται

Δεν συνιστώ αυτό. Αυτό είναι μια κακή ιδέα. Μην το κάνεις.

Εδώ είναι μερικοί λόγοι:

  • Θα προσθέσετε ένα συνδεδεμένο αντικείμενο σε κάθε περίπτωση το κάνετε αυτό για να. Εάν το κάνετε αυτό πολύ, θα πρέπει πιθανώς να χάνουμε πολλή μνήμη. δεσμεύονται μέθοδοι δημιουργούνται συνήθως μόνο για τη μικρή διάρκεια της κλήσης τους, και στη συνέχεια παύουν να υπάρχουν όταν αυτόματα τα σκουπίδια που συλλέγονται. Αν το κάνετε αυτό με το χέρι, θα έχετε ένα όνομα δεσμευτική αναφορά του δεσμευμένου μέθοδο - η οποία θα εμποδίσει τη συλλογή σκουπιδιών της για τη χρήση του.
  • Περιπτώσεις αντικείμενο ενός συγκεκριμένου τύπου έχουν γενικά τις μεθόδους της σε όλα τα αντικείμενα αυτού του τύπου. Αν προσθέσετε μεθόδους αλλού, ορισμένες περιπτώσεις θα έχουν αυτές τις μεθόδους και άλλοι όχι. Οι προγραμματιστές δεν θα περιμένουν αυτή, και υπάρχει κίνδυνος να παραβιάζει το κράτος τουλάχιστον έκπληξη .
  • Δεδομένου ότι υπάρχουν και άλλοι πολύ καλοί λόγοι για να μην το κάνετε αυτό, θα πρόσθετα δώσετε στον εαυτό σας μια κακή φήμη, αν το κάνεις.

Έτσι, προτείνω να μην το κάνετε αυτό, εκτός αν έχετε ένα πολύ καλό λόγο. Είναι πολύ καλύτερο να καθορίσει τη σωστή μέθοδο στον ορισμό κατηγορίας ή λιγότερο κατά προτίμηση σε πίθηκο-μπάλωμα η τάξη άμεσα, όπως αυτό:

Foo.sample_method = sample_method

Δεδομένου ότι είναι διδακτικό, όμως, Πάω να σας δείξω μερικούς τρόπους για να γίνει αυτό.

Πώς μπορεί να γίνει

Εδώ είναι μερικά κωδικό εγκατάστασης. Χρειαζόμαστε έναν ορισμό της κατηγορίας. Θα μπορούσε να εισαχθούν, αλλά αυτό πραγματικά δεν έχει σημασία.

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

Δημιουργήστε ένα παράδειγμα:

foo = Foo()

Δημιουργήστε μια μέθοδο για να προσθέσει σε αυτό:

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

Μέθοδος μηδέν (0) - χρησιμοποιούν τη μέθοδο Περιγραφέας, __get__

Διακεκομμένη αναζητήσεις σε λειτουργίες καλούν τη __get__μέθοδο της συνάρτησης με το παράδειγμα, η σύνδεση του αντικειμένου με τη μέθοδο και δημιουργώντας έτσι ένα «δεσμευμένο μέθοδο.»

foo.sample_method = sample_method.__get__(foo)

και τώρα:

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

Μέθοδος ένα - types.MethodType

Κατ 'αρχάς, είδη εισαγωγής, από το οποίο θα πάρουμε τη μέθοδο κατασκευαστή:

import types

Τώρα προσθέτουμε τη μέθοδο με την περίπτωση. Για να γίνει αυτό, χρειαζόμαστε τον κατασκευαστή MethodType από τη typesμονάδα (που θα εισάγονται παραπάνω).

Η υπογραφή επιχείρημα για types.MethodType είναι (function, instance, class):

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

και τη χρήση:

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

Μέθοδος δύο: λεξική δεσμευτικές

Πρώτον, δημιουργούμε μια λειτουργία περιτύλιγμα που συνδέει τη μέθοδο με την περίπτωση:

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

χρήση:

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

Μέθοδος τρία: functools.partial

Μια μερική λειτουργία ισχύει το πρώτο επιχείρημα (ες) σε μια λειτουργία (και τα επιχειρήματα προαιρετικά λέξη κλειδί), και μπορεί αργότερα να ονομάζεται με τα υπόλοιπα επιχειρήματα (και επιτακτικό ορίσματα με λέξεις κλειδιά). Ετσι:

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

Αυτό είναι λογικό αν σκεφτεί κανείς ότι δεσμεύεται μέθοδοι είναι μερική λειτουργίες του παράδειγμα.

Χωρίς περιορισμούς λειτουργούν ως ένα χαρακτηριστικό αντικείμενο - γιατί αυτό δεν λειτουργεί:

Αν προσπαθήσουμε να προσθέσετε το sample_method με τον ίδιο τρόπο όπως θα μπορούσαμε να το προσθέσετε στην τάξη, είναι μη δεσμευμένο από το παράδειγμα, και δεν λαμβάνει τη σιωπηρή εαυτό ως το πρώτο επιχείρημα.

>>> 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)

Μπορούμε να κάνουμε το μη δεσμευμένο δουλειά λειτουργία με το πέρασμα ρητά την περίπτωση (ή οτιδήποτε άλλο, δεδομένου ότι αυτή η μέθοδος δεν χρησιμοποιεί την selfμεταβλητή επιχείρημα), αλλά δεν θα ήταν σύμφωνη με την αναμενόμενη υπογραφή άλλες περιπτώσεις (αν είμαστε μαϊμού-επιδιόρθωση αυτό το παράδειγμα):

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

συμπέρασμα

Τώρα ξέρετε αρκετοί τρόποι που θα μπορούσε να γίνει αυτό, αλλά με κάθε σοβαρότητα - δεν το κάνουμε αυτό.

Απαντήθηκε 21/01/2015 στις 05:31
πηγή χρήστη

ψήφοι
30

Νομίζω ότι οι παραπάνω απαντήσεις χάσει το σημείο κλειδί.

Ας ρίξουμε μια τάξη με μια μέθοδο:

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

Τώρα, ας παίξουμε με αυτό το IPython:

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

Ok, οπότε m () γίνεται κατά κάποιο τρόπο μια μη δεσμευμένο μέθοδο Α . Αλλά είναι πραγματικά έτσι;

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

Αποδεικνύεται ότι m () είναι απλά μια λειτουργία, αναφορά στην οποία προστίθεται A λεξικό τάξη - δεν υπάρχει μαγική. Τότε γιατί Am μας δίνει ένα μη συνδεδεμένο τρόπο; Είναι επειδή η τελεία δεν μεταφράζεται σε μια απλή αναζήτηση λεξικό. Είναι εκ των πραγμάτων μια κλήση από μια .__ κατηγορίας __.__ getAttribute __ (Α, «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

Τώρα, δεν είμαι σίγουρος από την κορυφή του κεφαλιού μου, γιατί η τελευταία γραμμή εκτυπώνεται δύο φορές, αλλά είναι ακόμα σαφές το τι συμβαίνει εκεί.

Τώρα, ποια είναι η προεπιλεγμένη __getattribute__ κάνει είναι ότι ελέγχει εάν το χαρακτηριστικό είναι το λεγόμενο Περιγραφέας ή όχι, δηλαδή αν εφαρμόζει μια ειδική μέθοδο __get__. Αν εφαρμόζει τη μέθοδο αυτή, τότε αυτό επιστρέφεται είναι το αποτέλεσμα της κλήσης της μεθόδου αυτής __get__. Πηγαίνοντας πίσω στην πρώτη έκδοση του μας Α κατηγορίας, αυτό είναι ό, τι έχουμε:

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

Και επειδή λειτουργεί Python εφαρμόσει το πρωτόκολλο Περιγραφέας, εάν καλούνται για λογαριασμό ενός αντικειμένου, που δεσμεύονται σε αυτό το αντικείμενο στη μέθοδο __get__ τους.

Εντάξει, οπότε πώς να προσθέσετε μια μέθοδο σε ένα υπάρχον αντικείμενο; Αν υποθέσουμε ότι δεν σας πειράζει επιδιόρθωση τάξη, είναι τόσο απλό όσο:

B.m = m

Στη συνέχεια, Bm «γίνεται» ένα μη συνδεδεμένο τρόπο, χάρη στο μαγικό Περιγραφέας.

Και αν θέλετε να προσθέσετε μια μέθοδο μόνο σε ένα αντικείμενο, τότε θα πρέπει να μιμηθούν τα μηχανήματα σας, χρησιμοποιώντας types.MethodType:

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

Παρεμπιπτόντως:

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'>
Απαντήθηκε 22/01/2012 στις 15:20
πηγή χρήστη

ψήφοι
16

Στην Python επιδιόρθωση μαϊμού λειτουργεί γενικά με την αντικατάσταση μιας κατηγορίας ή λειτουργίες υπογραφή με τη δική σας. Παρακάτω είναι ένα παράδειγμα από το Zope Wiki :

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

Ο κώδικας θα αντικαταστήσει / δημιουργήσει μια μέθοδο που ονομάζεται μιλούν για την κατηγορία. Σε Jeff Atwood της πρόσφατης δημοσίευσης την επιδιόρθωση μαϊμού . Δείχνει ένα παράδειγμα σε C # 3.0, που είναι η γλώσσα που χρησιμοποιώ για τη δουλειά.

Απαντήθηκε 04/08/2008 στις 03:31
πηγή χρήστη

ψήφοι
9

Υπάρχουν τουλάχιστον δύο τρόποι για να επισυνάψετε μια μέθοδο σε μια εμφάνιση χωρίς 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>>

Χρήσιμοι σύνδεσμοι:
μοντέλο δεδομένων - επικαλούμενη περιγραφές
Οδηγός περιγραφής HowTo - επίκληση περιγραφές

Απαντήθηκε 26/04/2013 στις 16:47
πηγή χρήστη

ψήφοι
7

Μπορείτε να χρησιμοποιήσετε λάμδα για να δεσμεύσει μια μέθοδο σε μια εμφάνιση:

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()

Αυτό είναι παράδειγμα εγχόρδων

Μέθοδος τελείωσε με κωδικό εξόδου 0

Απαντήθηκε 21/07/2014 στις 13:55
πηγή χρήστη

ψήφοι
6

Από αυτή την ερώτηση για τις εκδόσεις μη Python, εδώ είναι JavaScript:

a.methodname = function () { console.log("Yay, a new method!") }
Απαντήθηκε 09/03/2012 στις 16:07
πηγή χρήστη

ψήφοι
6

Αυτό που ψάχνετε είναι setattrπιστεύω. Χρησιμοποιήστε το για να ορίσετε ένα χαρακτηριστικό σε ένα αντικείμενο.

>>> 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>
Απαντήθηκε 07/08/2008 στις 12:30
πηγή χρήστη

ψήφοι
5

Αυτό είναι πραγματικά ένα addon για την απάντηση της «Jason Πρατ»

Παρά το γεγονός ότι Jasons απαντήσει έργα, δεν λειτουργεί μόνο αν κάποιος θέλει να προσθέσει μια λειτουργία σε μια τάξη. Δεν λειτούργησε για μένα όταν προσπάθησα να φορτώσετε μια ήδη υπάρχουσα μέθοδο από την .py αρχείο πηγαίου κώδικα.

Μου πήρε για πολύ καιρό για να βρούμε μια λύση, αλλά το κόλπο φαίνεται απλό ... 1.st εισάγετε τον κωδικό από το αρχείο πηγαίου κώδικα 2.ο αναγκάσει types.FunctionType χρήση reload 3.rd (...) για να μετατρέψει το εισάγονται και δεσμεύεται μεθόδου σε μια λειτουργία μπορείτε να περάσετε στις τρέχουσες παγκόσμιες μεταβλητές, όπως η επαναφόρτωση μέθοδος θα ήταν σε διαφορετικό χώρο ονομάτων 4.th τώρα μπορείτε να συνεχίσετε όπως προτείνεται από το «Jason Pratt» χρησιμοποιώντας το types.MethodType (... )

Παράδειγμα:

# 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
Απαντήθηκε 18/08/2015 στις 15:32
πηγή χρήστη

ψήφοι
5

Εσείς πρέπει να το δούμε σε απαγορευμένο καρπό , είναι μια βιβλιοθήκη Python που παρέχει υποστήριξη σε πίθηκο επιδιόρθωση οποιασδήποτε κατηγορίας python, ακόμα και χορδές.

Απαντήθηκε 25/08/2013 στις 22:56
πηγή χρήστη

ψήφοι
5

Εδραίωση Jason Pratt και η κοινότητα wiki απαντήσεις, με μια ματιά στα αποτελέσματα των διαφόρων μεθόδων δέσμευσης:

Ειδικά σημειωθεί πως η προσθήκη της λειτουργίας δεσμευτική ως μια μέθοδος τάξη λειτουργεί , αλλά η αναφορά πεδίο είναι λανθασμένη.

#!/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>>

Προσωπικά, προτιμώ την εξωτερική διαδρομή λειτουργία ADDMETHOD, καθώς μου επιτρέπει να ορίσετε δυναμικά νέα ονόματα μεθόδων μέσα σε ένα iterator, καθώς και.

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>>
Απαντήθηκε 28/01/2012 στις 01:12
πηγή χρήστη

ψήφοι
4

Τι Jason Pratt δημοσιεύτηκε είναι σωστή.

>>> 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'>

Όπως μπορείτε να δείτε, Python δεν θεωρεί β () κάτι διαφορετικό από ό, τι ένα (). Στην Python όλες οι μέθοδοι είναι μόνο μεταβλητές που τυχαίνει να είναι λειτουργίες.

Απαντήθηκε 22/08/2008 στις 15:40
πηγή χρήστη

ψήφοι
3

Αν μπορεί να είναι οποιαδήποτε βοήθεια, που κυκλοφόρησε πρόσφατα μια βιβλιοθήκη Python που ονομάζεται Gorilla για να κάνουν τη διαδικασία της μαϊμούς επιδιόρθωση πιο βολικό.

Χρησιμοποιώντας μια λειτουργία needle()για να επιδιορθώσει ένα δομοστοιχείο που ονομάζεται guineapigπηγαίνει ως εξής:

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

Αλλά λαμβάνει επίσης μέριμνα πιο ενδιαφέρουσες περιπτώσεις χρήσης, όπως φαίνεται στο FAQ από την τεκμηρίωση .

Ο κώδικας είναι διαθέσιμος στο GitHub .

Απαντήθηκε 15/07/2014 στις 03:12
πηγή χρήστη

ψήφοι
2

Θεωρώ ότι είναι περίεργο το γεγονός ότι κανείς δεν ανέφερε ότι το σύνολο των μεθόδων που αναφέρονται παραπάνω δημιουργεί μια αναφορά κύκλο μεταξύ της προστιθέμενης μέθοδο και το παράδειγμα, προκαλώντας το αντικείμενο να είναι ανθεκτικές μέχρι τη συλλογή σκουπιδιών. Υπήρχε ένα παλιό κόλπο προσθήκη ενός περιγραφητή επεκτείνοντας την κλάση του αντικειμένου:

def addmethod(obj, name, func):
    klass = obj.__class__
    subclass = type(klass.__name__, (klass,), {})
    setattr(subclass, name, func)
    obj.__class__ = subclass
Απαντήθηκε 30/04/2017 στις 04:57
πηγή χρήστη

ψήφοι
2

Αυτή η ερώτηση άνοιξε χρόνια πριν, αλλά hey, υπάρχει ένας εύκολος τρόπος για να προσομοιώσει τη σύνδεση μιας λειτουργίας σε περίπτωση τάξη με τη χρήση διακοσμητών:

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 ()

Εκεί, όταν περνάτε τη λειτουργία και το βαθμό στον συνδετικό διακοσμητής, θα δημιουργήσει μια νέα λειτουργία, με τον ίδιο αντικειμενικό κώδικα όπως το πρώτο. Στη συνέχεια, η συγκεκριμένη περίπτωση της κατηγορίας είναι αποθηκευμένο σε ένα χαρακτηριστικό της λειτουργίας που δημιουργήθηκε πρόσφατα. Ο διακοσμητής επιστρέψει ένα (τρίτο) λειτουργία καλώντας αυτόματα την αντιγραφή λειτουργία, δίνοντας το παράδειγμα με την πρώτη παράμετρο.

Εν κατακλείδι μπορείτε να πάρετε μια λειτουργία προσομοίωσης είναι δεσμευτική για την περίπτωση τάξη. Αφήνοντας την αρχική λειτουργία αμετάβλητες.

Απαντήθηκε 21/12/2015 στις 21:39
πηγή χρήστη

ψήφοι
1
from types import MethodType

def method(self):
   print 'hi!'


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

Με αυτό, μπορείτε να χρησιμοποιήσετε τον εαυτό δείκτη

Απαντήθηκε 27/07/2017 στις 04:21
πηγή χρήστη

ψήφοι
-8

Δεν ξέρω Python σύνταξη, αλλά ξέρω Ruby μπορεί να το κάνει, και είναι μάλλον ασήμαντο. Ας υποθέσουμε ότι θέλετε να προσθέσετε μια μέθοδο για να Array που εκτυπώνει το μήκος τυποποιημένα:

class Array
  def print_length
    puts length
  end
end

Εάν δεν θέλετε να τροποποιήσετε ολόκληρη την τάξη, μπορείτε να προσθέσετε ακριβώς τη μέθοδο σε ένα μόνο παράδειγμα του πίνακα, και κανένα άλλο συστοιχίες θα έχουν την μέθοδο:

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

Απλά να γνωρίζουν τα θέματα που σχετίζονται με τη χρήση αυτής της δυνατότητας. Jeff Atwood πραγματικότητα έγραψε γι 'αυτό δεν είναι πολύ καιρό πριν.

Απαντήθηκε 04/08/2008 στις 03:36
πηγή χρήστη

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