[TasPython] decorators + Lots of __init__ args

Themistoklis Savvidis themhs at gmail.com
Mon Dec 20 19:00:24 CET 2010


Χαίρετε,

στα πλαίσια της τελευταίας συνάντησης σχετικά με τους decorators, σκέφτηκα
να
μοιραστώ με τη λίστα μια λύση που μου πρότεινε ο Δημήτρης (Γλέζος) στο
παρακάτω
θέμα:

Ε: Έστω πως έχω μια κλάση User. Κάθε αντικείμενο της User θέλω να μπορει να
   αρχικοποιεί 20 μεταβλητές (username, name, surname, age, email, phone_num
και
   ό,τι άλλο μπορείτε να φανταστείτε) όταν αυτό δημιουργείται. Πώς λοιπόν θα
το
   πετύχω αυτό;

   α) Θα έχει ο constructor της User 20 όρισματα με τα οποία θα αρχικoποιώ
      μία-μία τις μεταβλητές αντικειμένου; (hint: είμαι σίγουρος πως τα
μαλλιά
      κάποιοων έχουν σηκωθεί ανεπανόρθωτα στο ανάγνωσμα της (a) πρότασης)

   β) Θα βάλω σαν όρισμα **kwargs και θα κάνω κάποια 'χακιά';
      Σα 'χακιά' εδώ εννούσα να παίξω απευθείας με το self.__dict__, τεχνική
      που δεν ξέρω αν είναι γενικώς αποδεκτή και προτεινόμενη:

      def __init__(self, **kwargs):
          for (key, item) in kwargs.items():
              self.__dict__[key] = item

   γ) Υπάρχει κάποιος πιο όμορφος τρόπος;

A: O Δημήτρης μου πρότεινε σε πρώτη φάση να χρησιμοποιήσω την update() των
   λεξικών, της οποίας την ύπαρξη αγνοούσα:

    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

   Αυτό όμως, όπως μου εξήγησε, είναι κάπως περίεργο γιατί ένας Theoς ξέρει
μόνο
   τι θα του περάσουμε σαν kwargs - αν κ ακόμη κ αυτό τις τελευταίες 2
βδομάδες
   αμφίσβητείται. So, μια πιο restricted λύση είναι η εξής:

   class User:

       init_properties = ['username', 'name', 'surname']

       @autoargs(init_properties)
       def __init__(self, **kwargs):
           self.__dict_.update(kwargs)

   όπου η init_properties είναι αυτή που καθορίζει ποια kwargs θα περαστούν
σαν
   instance variables και ο decorator autoargs είναι αυτός που κάνει τη
βρώμικη
   δουλειά, 'κόβοντας' όλα τα 'περίεργα' args.

    Μου άρεσε η ιδέα του, άνοιξα τον αγαπημένο editor του Κεραμίδα, πάτησα
'i'
    (sic) και έγραψα τον παρακάτω decorator:

    def autoargs(arg_list):
        def decorator(func):
            def wrapper(self, **kwargs):
                [setattr(self,k,v) for (k,v) in kwargs.items() if k in
arg_list]
                func(self, **kwargs)
            return wrapper
        return decorator

    ώστε πλέον o constructor γίνεται:

      @autoargs(init_properties)
       def __init__(self, **kwargs):
           pass

    Παρ' ολ' αυτά, επειδή αρχικά την ερώτηση έκανα στο Γιάννη (Καλαντζή),
    έδωσα κ σ' αυτόν την απάντηση του Δημήτρη. Μου απαντάει "nice, για να
δούμε
    πως το κάνει το django". Όπως αποδείχθηκε, και το το django χρησιμποιεί
την ίδια
    λογική αλλά χωρίς τη χρήση decorators.

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


http://stackoverflow.com/questions/1389180/python-automatically-initialize-instance-variables

-- 
Themis
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/taspython/attachments/20101220/960ad733/attachment.html>


More information about the TasPython mailing list