SORU
13 HAZİRAN 2009, CUMARTESİ


Örneği Reclassing Python

Harici bir kütüphane tarafından bana verilen bir ders var. Bu sınıfın bir alt sınıf oluşturduk. Ben de orijinal sınıfının bir örneği var.

Ben şimdi bu örneği zaten sahip olduğu tüm özellikleri (ALT sınıf zaten geçersiz kılan durumlar hariç) değiştirmeden benim sınıfın bir örnek, bu örnek açmak istiyorum.

Aşağıdaki çözüm gibi görünüyor.

# This class comes from an external library. I don't (want) to control
# it, and I want to be open to changes that get made to the class
# by the library provider.
class Programmer(object):
    def __init__(self,name):
        self._name = name

    def greet(self):
        print "Hi, my name is %s." % self._name

    def hard_work(self):
        print "The garbage collector will take care of everything."

# This is my subclass.
class C_Programmer(Programmer):
    def __init__(self, *args, **kwargs):
        super(C_Programmer,self).__init__(*args, **kwargs)
        self.learn_C()

    def learn_C(self):
        self._knowledge = ["malloc","free","pointer arithmetic","curly braces"]

    def hard_work(self):
        print "I'll have to remember "   " and ".join(self._knowledge)   "."

    # The questionable thing: Reclassing a programmer.
    @classmethod
    def teach_C(cls, programmer):
        programmer.__class__ = cls # <-- do I really want to do this?
        programmer.learn_C()


joel = C_Programmer("Joel")
joel.greet()
joel.hard_work()
#>Hi, my name is Joel.
#>I'll have to remember malloc and free and pointer arithmetic and curly braces.

jeff = Programmer("Jeff")

# We (or someone else) makes changes to the instance. The reclassing shouldn't
# overwrite these.
jeff._name = "Jeff A" 

jeff.greet()
jeff.hard_work()
#>Hi, my name is Jeff A.
#>The garbage collector will take care of everything.

# Let magic happen.
C_Programmer.teach_C(jeff)

jeff.greet()
jeff.hard_work()
#>Hi, my name is Jeff A.
#>I'll have to remember malloc and free and pointer arithmetic and curly braces.

Ancak ikna olmadım bu çözüm değil içeren herhangi bir uyarı almadım düşünce (üzgünüm üçlü negatiflik), özellikle çünkü Yeniden Atama sihirli __class__ sadece doğru gelmiyor. Eğer bu çalışırsa bile, bunu yapmanın daha pythonic bir yolu olmalı, düşünmeden edemiyorum.

Orada mı?

< / ^ hr .

Edit: Teşekkürler cevaplar için herkese. Onlardan şunu anladım:

  • __class__ atayarak örneği reclassing fikri yaygın olarak kullanılan bir deyim değildir, ancak çoğu cevapları (yazma anda 4 6) geçerli bir yaklaşım düşünün. Bir anwswer (ojrac) olduğunu söylüyor "çok tuhaf ilk bakışta," katılıyorum (soru sorma nedeni vardı). Tek bir cevap (Jason Baker; iki olumlu yorum & oy ile) aktif olarak beni bunu yapmaktan vazgeçmesi, ancak bunu yaparken genel olarak örnek tekniğine göre davayı daha çok kullanımına dayalı.

  • Cevap hiçbiri, olumlu olsun ya da olmasın, bu yöntemde gerçek bir teknik sorun bulur. Küçük bir istisna muhtemelen doğru olan tarzı eski sınıfları, ve C uzantıları alaka bahseden idea. Yeni-stil-sınıf-bilinçli C uzantıları eğer aynı fikirde değilsen, cevaplar gelmeye devam, ancak kendisi (ikincisi küstah geçerlidir) Python gibi bu yöntem ile iyi olmalı diye düşünüyorum.

Nasıl pythonic bu sorusuna gelince, birkaç olumlu bir cevap vardı, ama gerçek bir sebep vermiş. Zen (import this) bakarken, bu durumda en önemli kural sanırım "Açık örtülü daha iyidir." Bu kural veya bu şekilde reclassing için karşı konuşuyor emin değilim,.

  • {has,get,set}attr kullanarak açıkça nesne yaptığımız değişiklikler yapmak yerine büyü gibi daha açık görünüyor.

  • Kullanarak __class__ = newclass daha açık görünüyor çünkü biz açıkça söylüyor, "Bu artık bir nesnenin sınıf newclass,' beklemek farklı bir davranış" yerine sessizce değişen öznitelikler ama bırakarak kullanıcıların nesne mümin oldukları ile ilgili düzenli bir nesnenin eski sınıf.

Özetle: teknik açıdan bakıldığında, bu yöntem iyi görünüyor; pythonicity soruya "Evet." yönünde bir önyargı ile cevapsız kalır

Eklenti Mercurial örnek oldukça güçlü bir tane de ben bile kendime sordum henüz gelmemiş bir soru cevap vermediğin için) çünkü Martin Geisler cevabı kabul edebilirim. Eğer pythonicity soru üzerine herhangi bir tartışma varsa, ancak, yine de onları duymak isterim. Teşekkürler şu ana kadar.

P. S. gerçek kullanım durumunda büyümek için ihtiyaç duyduğu UI veri kontrol nesnesi ek işlevlerçalışma zamanında. Ancak, bu soru çok genel olması gerekiyordu.

CEVAP
13 HAZİRAN 2009, CUMARTESİ


Bu gibi Reclassing örnekleri uzantıları (eklentileri) yerel depoyu temsil eden nesne değiştirmek istediğinizde Mercurial (dağıtılmış sürüm kontrol sistemi) yapılır. Nesne repo denir ve başlangıçta localrepo bir örneğidir. Sırayla her uzantısı geçirilir ve gerektiğinde, uzantıları yeni bir sınıf tanımlamak. repo.__class__ bir alt sınıfı olan vedeğiştirinbu yeni sınıf repo sınıf!

like this kod görünüyor:

def reposetup(ui, repo):
    # ...

    class bookmark_repo(repo.__class__): 
        def rollback(self):
            if os.path.exists(self.join('undo.bookmarks')):
                util.rename(self.join('undo.bookmarks'), self.join('bookmarks'))
            return super(bookmark_repo, self).rollback() 

        # ...

    repo.__class__ = bookmark_repo

Uzantısı (yer imleri uzantısı kod aldım) bir modül düzeyi reposetup adlı fonksiyonu tanımlar. Mercurial uzantısı başlatırken bu çağrı ve ui (kullanıcı arayüzü) ve repo (depo) bir argüman.

Fonksiyonu repo ne olursa olsun, bir alt sınıfı tanımlar. Olurdeğiluzantıları birbirlerini genişletebilmek için gereken bu yana sadece localrepo alt sınıf için yeterli. Eğer öyleyse ilk uzatma foo_repo, bir sonraki uzantısı repo.__class__ değişirse repo.__class__ foo_repo arasında bir fark yoktur. ve sadece localrepo bir alt sınıfı değil değiştirmek gerekir. Son olarak işlev kodu nasıl instanceø sınıf değiştirir.

Bu kod, bu dil özelliği, meşru bir kullanım gösterebilir umarım. Vahşi kullanıldığını gördüm tek yer bence.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • BachelorsPadTv

    BachelorsPad

    17 Ocak 2012
  • Living Waters

    Living Water

    9 AĞUSTOS 2006
  • Vortez

    Vortez

    27 Temmuz 2009