2011-12-17 14 views
25

Çalışma zamanında bir nesne örneğine (sınıf değil!) Bir temel sınıf eklenebilir mi? Ruby nasıl Object#extend eserlerin şey satırları:Python'daki bir örneğe dinamik olarak bir temel sınıfı karıştırın

class Gentleman(object): 
    def introduce_self(self): 
    return "Hello, my name is %s" % self.name 

class Person(object): 
    def __init__(self, name): 
    self.name = name 

p = Person("John") 
# how to implement this method? 
extend(p, Gentleman) 
p.introduce_self() # => "Hello, my name is John" 
+0

Neden bunu bir yorum yapmadan reddediyorsunuz? Belki de Ruby kelimesi metinde göründüğü için? o0 –

+1

Uuuuurrgghhh !!!!! Sınıfı değiştirmeden bir örneği değiştirmek, felaket için bir reçete. Bunu yapmanın en güzel yolu, 'Kişinin bir alt sınıfını yapmak ve' Beyefendiyi 'karıştırmaktır. – katrielalex

+1

@katrielalex: Muhtemelen çoğu durumda haklısınız. Yine de, bu işlevselliğe ihtiyacım var çünkü ara yüzünü değiştiremediğim bir üçüncü taraf kitaplığına işlevsellik eklemek istiyorum. Karışımlar ya da proxy modeli arasında seçim yapmak zorunda kaldım. –

cevap

32

Bu dinamik 'buna ler sınıfı:

İsteğiniz
class Gentleman(object): 
    def introduce_self(self): 
    return "Hello, my name is %s" % self.name 

class Person(object): 
    def __init__(self, name): 
    self.name = name 

p = Person("John") 
p.__class__ = type('GentlePerson',(Person,Gentleman),{}) 
print(p.introduce_self()) 
# "Hello, my name is John" 

, bu p değiştirir' p yeni bir sınıf GentlePerson tanımlar ve yeniden atar s üsleri, ancak p 'in orijinal sınıfını Person değiştirmez. Böylece, Person'un diğer örnekleri etkilenmez (AttributeError ise introduce_self çağrıldı).


yol, söz konusu istendi değil de, ben dinamik bir sınıfın üsleri değiştirmek de mümkündür ancak (AFAIK) sınıfı doğrudan devralan olmayan tek takdirde, Google'cuların ve meraklılar için ekleyeceğiz object den:

def extend(instance, new_class): 
    instance.__class__ = type(
      '%s_extended_with_%s' % (instance.__class__.__name__, new_class.__name__), 
      (instance.__class__, new_class), 
      {}, 
     ) 
+0

Çok hoş. Aslında '__class__' için tahsis etmeye çalıştım, ancak bu sadece dinamik olarak oluşturulan sınıflarla çalışacak gibi görünüyor. Umduğum çözüm bu, teşekkürler. –

+0

Güzel! _Directly_ 'object' den anahtar iirc; standart çözüm, 'class object (object): pass' tanımlamaktır. – katrielalex

+0

“Beyefendi” sınıfının “Person” sınıfının bir özelliğini geçersiz kılmasını istediğim gibi biraz tökezledim. Bu durumda, siparişi '' ('GentlePerson', (Beyefendi, Kişi), {}) 'olarak değiştirdim. Umarım bu hiçbir kötülük getirmez. – letmaik

5

zaten cevap vermedi rağmen, burada bir fonksiyondur

def extend_instance(obj, cls): 
    """Apply mixins to a class instance after creation""" 
    base_cls = obj.__class__ 
    base_cls_name = obj.__class__.__name__ 
    obj.__class__ = type(base_cls_name, (base_cls, cls),{}) 
+0

Bir çalışma çözümüne sahip olmak iyidir, ancak anlaşılması zor ve zor hata kodunun cehenneme giden yolu olabileceği için, kara büyü kullanımının iyi düşünülmesi gerektiğini unutmayın. –

7

Biraz daha temiz versiyonu:

class Gentleman(object): 
    def introduce_self(self): 
    return "Hello, my name is %s" % self.name 

class Base(object):pass 
class Person(Base): 
    def __init__(self, name): 
    self.name = name 

p = Person("John") 
Person.__bases__=(Gentleman,object,) 
print(p.introduce_self()) 
# "Hello, my name is John" 

q = Person("Pete") 
print(q.introduce_self()) 
# Hello, my name is Pete 
+1

güzel bir çözüm. Bunu, varolan örneklerde yöntemleri geçersiz kılmak için kullanıyorum; bu durumda, tür sırasının "(cls, base_cls)" olması gerekir – miraculixx

İlgili konular