Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing a python method that refers to both the instance and the class

Let's say we have a Pet class in Python:

class Pet(object):
    num_pets = 0

    def __init__(self, name):
        self.name = name
        Pet.num_pets += 1

    def speak(self):
        print("My name's %s and the number of pets is %d" % (self.name, self.num_pets))

I want the init method to create an instance, but also update an attribute on the class. Is there a more elegant way to do this than the code above? I tried passing in self and cls to the init method, and then referring to cls instead of Pet where num_pets is incremented, but that didn't work.

like image 992
michberr Avatar asked Apr 13 '17 21:04

michberr


3 Answers

You could use a classmethod to increment the number of pets:

class Pet(object):
    num_pets = 0

    def __init__(self, name):
        self.name = name
        self.incr_num_pets()

    @classmethod
    def incr_num_pets(cls):
        cls.num_pets += 1

Alternatively, you could increment num_pets on type(self):

def __init__(self, name):
    self.name = name
    type(self).num_pets += 1

though I find this second method to be slightly less elegant even if it is less typing.

like image 169
mgilson Avatar answered Oct 07 '22 15:10

mgilson


In your case you could use __new__ together with __init__:

class Pet(object):
    num_pets = 0

    def __new__(cls, *args, **kwargs):
        cls.num_pets += 1
        return object.__new__(cls)

    def __init__(self, name):
        self.name = name
like image 29
MSeifert Avatar answered Oct 07 '22 17:10

MSeifert


You can access own class using self.__class__, it means that your __init__ can looks like:

def __init__(self, name):
    self.name = name
    self.__class__.num_pets += 1
like image 42
msztolcman Avatar answered Oct 07 '22 17:10

msztolcman