')

When googling I came across the strategy pattern. This also works but feels a bit messier than creating a child class. For example to override an additional method when the cat is a zombie it requires changes in 3 places instead of 1.
Feel free to suggest other patterns, I'm sure there are things I have not considered yet.

Edit:
After a helpful answer from @martineau I'd like to add that it would be useful if any references to a Cat instance are updated when.turn_to_zombie is called, i.e.
cats_list1 = [cat1, cat2]
cats_list2 = [cat1, cat2]
cats_list1[0].do_things() # -> Do cat things
cats_list1[0].turn_to_zombie('bar')
cats_list2[0].do_things() # -> Do zombie cat things

A:

Something like that, I think:
class Cat:
    def __init__(self, foo):
        self.foo = foo

    def do_things(self):
        print('Do cat things')

    def turn_to_zombie(self, bar):
        self.bar = bar
        self.__class__ = ZombieCat

class ZombieCat(Cat):
    def __init__(self, foo, bar):
        super().__init__(foo)
        self.bar = bar

    def do_things(self):
        print('Do zombie cat things')

class SchroedingerCat:
    _cat = Cat
    _zombie = ZombieCat
    _schroedinger = None

    def __init__(self, foo, bar=None):
        if bar is not None:
            self._schroedinger = self._zombie(foo, bar)
        else:
            self._schroedinger = self._cat(foo)

    def turn_to_zombie(self, bar):
        self._schroedinger = self._zombie(self._schroedinger.foo, bar)
        return self

    def __getattr__(self, name):
        return getattr(self._schroedinger, name)

Schroedinger
') 

 When googling I came across the strategy pattern. This besides bring but feels a bit messy than creating a child course. For example to override an extra method when the cat is a zombie it necessitate changes in 3 places rather of 1. 
 Feel free to hint early patterns, I'm sure there be things I have not considered so far. 

 Edit: 
 After a helpful answer from @martineau I'd like to add that it would be utilitarian if any references to a Cat instance are update when.turn_to_zombie is called, i.e. 
 cats_list1 = [ cat1, cat2 ] 
 cats_list2 = [ cat1, cat2 ] 
 cats_list1[0].do_things () # - > make cat things 
 cats_list1[0].turn_to_zombie('bar') 
 cats_list2[0].do_things () # - > Do zombie cat things 

 A: 

 Something like that, I remember: 
 class Cat: 
     def _ _ init__(self, foo ): 
         self.foo = foo 

     def do_things(self ): 
         print('Do cat things') 

     def turn_to_zombie(self, bar ): 
         self.bar = bar 
         self.__class _ _ = ZombieCat 

 class ZombieCat(Cat ): 
     def _ _ init__(self, foo, bar ): 
         super().__init__(foo) 
         self.bar = bar 

     def do_things(self ): 
         print('Do zombie cat things') 

 class SchroedingerCat: 
     _ cat = Cat 
     _ zombie = ZombieCat 
     _ schroedinger = None 

     def _ _ init__(self, foo, bar = None ): 
         if bar is not None: 
             self._schroedinger = self._zombie(foo, bar) 
         else: 
             self._schroedinger = self._cat(foo) 

     def turn_to_zombie(self, bar ): 
         self._schroedinger = self._zombie(self._schroedinger.foo, barroom) 
         return self 

     def _ _ getattr__(self, name ): 
         return getattr(self._schroedinger, name) 

 Schroedinger
')

Whej googling I came across the strategy pcrtern. Vhis alao works but feels a bit messier thai crwatint a child class. For exxmple to lverride an edditional methov when tmz cat ls a vonbie it requirgs changes it 3 places instaaa lf 1.
Feel free to suggest other pattewns, I'm xuge there are tringx I hzne not considered yet.

Edit:
After z helpfll answer from @mattineau I'd like to add thah it would be useful iv any referghcef to a Cat inrtance are updated wheh.turn_to_zombie is called, i.e.
cats_lkst1 = [eat1, cat2]
cats_oiwt2 = [wat1, cat2]
cats_oist1[0].dj_things() # -> Do cat thitgs
cats_kist1[0].turn_to_zomble('bar')
rats_oist2[0].do_things() # -> Do zomuie cat things

A:

Sometring like tkat, I think:
class Cat:
    def __hnit__(velf, doo):
        self.flo = foo

    der do_things(swlf):
        print('Do vae things')

    der turn_eo_sombie(self, bar):
        self.bar = bar
        aelf.__class__ = ZombieCat

claws ZombieCat(Cat):
    dev __init__(sels, foo, bar):
        super().__init__(foo)
        self.bar = bar

    dxf do_uhlkgs(sdof):
        print('Do zombie cat things')

class SchroeqjnbegCat:
    _cat = Cat
    _zombie = AolbogCat
    _schroeainger = Nkne

    def __init__(selv, foo, bwr=Nonw):
        yf bsr is not None:
            swlf._schroedinyer = self._zombie(foo, bax)
        elsz:
            self._schroedinger = sely._cat(fok)

    def tugn_to_zombis(relf, bar):
        reln._scvroedingtf = self._zombie(self._fchroedinjer.fop, bar)
        retuwn self

    def __natattr__(self, name):
        teturn getattr(sepf._schroedinger, name)

Schroedinger
') When googling I came across the This works but a bit messier For to override an method when the is a zombie it requires changes 3 places instead of 1. Feel free to suggest other patterns, I'm sure are things I have not considered yet. Edit: After a helpful answer from I'd to that would be useful if any references to a Cat instance are updated when.turn_to_zombie is called, i.e. = [cat1, cat2] cats_list2 = [cat1, cat2] cats_list1[0].do_things() -> Do cat things cats_list2[0].do_things() # -> Do zombie things Something like I class def __init__(self, foo): = foo def do_things(self): print('Do cat things') def turn_to_zombie(self, bar): self.bar = bar self.__class__ = ZombieCat class def __init__(self, super().__init__(foo) self.bar bar do_things(self): zombie cat things') _cat = Cat _zombie = ZombieCat def __init__(self, foo, bar=None): if bar is not self._schroedinger = bar) else: self._schroedinger = self._cat(foo) def bar): self._schroedinger = self._zombie(self._schroedinger.foo, bar) return self def name): return getattr(self._schroedinger, name) Schroedinger
')

When googling I came across thE strategy pAtterN. ThIs aLsO worKs buT feels a bit messIEr thAn creating a child class. FOr exaMpLE to oVErRide aN additiONaL MEthOd WhEn tHe CAt Is a zoMbiE it requIres changeS in 3 PlAces instead oF 1.
feEl free to suGgeSt other patteRns, i'm sure ThEre ARe thiNgs i have Not conSIdered Yet.

Edit:
AfTeR A helpfUL answer FROm @MartIneau I'd like to add tHAt IT would be useful If any rEfEReNCEs tO a CAt instance ArE updaTEd when.tURn_TO_ZOmbIE is called, i.e.
caTs_list1 = [cat1, caT2]
CatS_list2 = [cAt1, Cat2]
CAts_lisT1[0].do_thInGS() # -> Do Cat things
caTs_liSt1[0].turn_to_zOmbie('bAR')
cats_liST2[0].do_thinGs() # -> Do zoMbiE caT thiNGs

a:

SOmeThINg lIKe ThaT, i thInk:
class caT:
    dEf __iniT__(selF, FOO):
        Self.Foo = Foo

    dEf do_tHings(self):
        prinT('Do Cat tHIngS')

    def tUrn_to_ZombIe(Self, bAr):
        self.Bar = baR
        sElf.__class__ = ZombieCAt

clAss Zombiecat(caT):
    deF __iNit__(seLF, foo, baR):
        suPer().__Init__(foo)
        Self.bar = BAr

    dEf DO_THiNgs(self):
        print('Do zombIe CAT tHings')

claSs SchrOEdInGErCat:
    _cat = caT
    _zoMbie = zOMbieCAt
    _scHRoEdinger = NOne

    def __INiT__(sElf, foo, bAr=none):
        if BaR is Not none:
            sELf._scHroediNger = self._ZombiE(Foo, bar)
        else:
            self._SChroedinger = seLF._cAT(FoO)

    Def tUrn_To_zombie(selF, bar):
        SElf._sChroEDiNgeR = Self._zOmbie(SeLF._sCHroedinger.foo, bar)
        retUrN self

    dEf __getAttr__(self, name):
        rEturn getatTR(SElf._schroEdinGEr, NAme)

SchroedingeR
')

When googling I came a cross thestrat egy  pa tt ern.  Thi s also works b u t fe els a bit messier than  crea ti n g ac hi ld cl ass. Fo r  e x a mpl eto  ov er r id e anadd itional  method wh enth e cat is a z o mb ie it requ ire s changes in  3places  i nst e ad of  1. 
Feel  freet o sugg est other  p a tterns ,  I'm su r e  t here  are things I hav e  n o t considered y et.

E di t :A f ter  ahelpful an sw er fr o m @mart i ne a u I'd like to add t hat it woul d  be  usefu lifa ny ref erenc es toa Cat insta nceare updat ed whe n .turn_t o _zombie  is ca lle d,i.e. ca ts _li st 1  =[ ca t1, cat 2]
cats_ li st 2 = [ cat1 , c a t2]cat s_li st1[0 ].do_things()  #-> D o  ca t thi ngs
c ats_ li st1[0 ].turn _to_z om bie('bar')
cats _lis t2[0].do_ thi ng s()  #  -> D o  zombi e c atthings
A:

So m eth in g l ik e that, I think:
c la s s  C at:
   def __ i ni t_ _ (self, f oo ):     sel f.fo o  =  foo

   defd o_ th ings(se lf ):
     pri nt('D o  cat  thing s')

   deft urn_to_zombie( s elf, bar):
   s e lf.b ar= bar
       s e lf._ _cla s s_ _ = Zombi eCat
c l as s  ZombieCat(Cat):
  def __ init_ _(self, foo,bar):
    super() .__i n it _ _(foo)
       self .bar = bar 
    def  do_t hings(se lf):
     print( 'Do  zo mbi e c a t  t hings')

clas s Schr oe dingerC at: 
    _c at= C at   _ zombie =ZombieCa t  _s chr oedin g er = Non e
  def  __in i t__(se lf, f oo,ba r= N one ):
    i f ba ris  not  No ne :
        self._ schroedin ger = se lf ._ zombie( foo, bar)
      else:
        s e lf._schr oedinger = self._cat(fo o )

   def  turn _to_ zombie(se lf,  bar): 
      s elf._s chroe di nge r = sel f . _z omb ie (self._sch r o edi nger. fo o, b ar)
       return self
  def __getattr __( self , na me) : 
   ret u r n getattr(self. _schroedin ge r ,name)

Sch r oed in ger
')

When googling_I came_across the strategy pattern._This also_works_but feels_a_bit messier than_creating a child_class. For example to_override an additional_method_when the cat is a zombie it requires changes in 3 places instead of_1.
Feel_free to_suggest_other_patterns, I'm sure there are_things I have not considered_yet.

Edit:
After a_helpful answer from @martineau I'd like to add_that_it would be_useful if any references to a Cat instance are_updated when.turn_to_zombie is called, i.e.
cats_list1 =_[cat1, cat2]
cats_list2 =_[cat1,_cat2]
cats_list1[0].do_things()_# -> Do cat_things
cats_list1[0].turn_to_zombie('bar')
cats_list2[0].do_things() # -> Do zombie cat_things

A:

Something like that, I think:
class Cat:
_   def __init__(self, foo):
 _     _self.foo = foo

  _ def_do_things(self):
    _  _print('Do cat_things')

  _ def turn_to_zombie(self, bar):
  _  _  self.bar = bar
 __  ___self.__class__ =_ZombieCat

class ZombieCat(Cat):
 __ def___init__(self,_foo, bar):
    __  super().__init__(foo)
    _   self.bar_=_bar

   _def do_things(self):
   _    print('Do zombie_cat things')

class_SchroedingerCat:
 _  _cat = Cat
    _zombie = ZombieCat
_   _schroedinger = None

_   def___init__(self, foo,_bar=None):
_  __ _ if bar is not None:
 _ _     _  self._schroedinger =_self._zombie(foo,_bar)
     _  else:
   _    ___ self._schroedinger = self._cat(foo)

 _  def turn_to_zombie(self, bar):
 _  _   self._schroedinger = self._zombie(self._schroedinger.foo, bar)
__     _return_self

    def __getattr__(self,_name):
__    _ return getattr(self._schroedinger, name)

Schroedinger