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

3

11

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.

Latoria answered 13/4, 2017 at 21:13 Comment(1)
I see the above code to be elegant enough. Unless num_pets is an attribute that's managed per-class. I don't see any obvious reason why to consider the need of using a class method here.Knecht
Z
13

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.

Zabrze answered 13/4, 2017 at 21:15 Comment(0)
I
4

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
Infirmary answered 13/4, 2017 at 21:26 Comment(0)
F
1

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
Feuchtwanger answered 15/4, 2017 at 0:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.