Mark
Mark

Reputation: 2148

create python factory method

I have the following simple example:

class CatZoo(object):
    def __init__(self):
        raise NotImplemented

    @classmethod
    def make_zoo_cat(cls, name, age, gender, location):
        cls._names = name
        cls._ages = age 
        cls._genders = gender
        cls._location = location
        return cls 

    @classmethod
    def make_zoo_cats(cls, names, ages, genders, location):
        cls._names = names
        cls._ages = ages
        cls._genders = genders
        cls._location = location
        return cls 

    @property
    def location(self):
        return self._location

    @property
    def names(self):
        return self._names

    def age(self, name):
        if name in self._names:
            return self._ages[self._names.index(name)]
        else:
            return None

    def gender(self, name):
        if name in self._names:
            return self._genders[self._names.index(name)]
        else:
            return None

    @property
    def meow(self):
        return "meow!"

And I am trying to create an object of this class by using the following:

cat_zoo = CatZoo.make_zoo_cat('squeakers', 12, 'M', 'KC')
print "The name is {}".format(cat_zoo.names)

This is just an example, I am just trying to make my factory methods work (make_zoo_cat, make_zoo_cats). The first will be passed one name, age, gender and location where the second would be passed a list of names, ages and genders and one location. If I run this code, I get the following output:

The name is <property object at 0x7fe313b02838>

Thanks,

Upvotes: 1

Views: 354

Answers (2)

MoiTux
MoiTux

Reputation: 818

You didn't create any object in your code.
In your make_zoo_cats you return cls, so you still have a class not an instance of this class.
This code will print the yes

if CatZoo.make_zoo_cat('squeakers', 12, 'M', 'KC') == CatZoo:
    print 'yes'

You agree than you can't do that, since name its a property it will only exist if you have an instance of that class.

CatZoo.names

to be able to use the property you need on instance of that class
something like that (this will raise in your code):

cat = CatZoo()
cat.names  # I can do this now

An other point in your make_zoo_cat you create Class variables, those variables are accessible from the class (no need to have an instance on that class) but are "common" to all.

c1 = CatZoo.make_zoo_cat('squeakers', 12, 'M', 'KC')
print c1._names
print c1._ages
print c1._genders
print c1._location

print '*'*10

print CatZoo._names
print CatZoo._ages
print CatZoo._genders
print CatZoo._location

print '*'*10

c2 = CatZoo.make_zoo_cat('other', 42, 'F', 'FR')
print c2._names
print c2._ages
print c2._genders
print c2._location

print '*'*10

print CatZoo._names
print CatZoo._ages
print CatZoo._genders
print CatZoo._location

print '*'*10

print c1._names
print c1._ages
print c1._genders
print c1._location

the result will be someting like that:

squeakers
12
M
KC
**********
squeakers
12
M
KC
**********
other
42
F
FR
**********
other
42
F
FR
**********
other
42
F
FR

The first two give me the same result, and the last three as well, this is because they are class variables and you always have the same class so modifying one of those variable will affect the other

Upvotes: 1

Martijn Pieters
Martijn Pieters

Reputation: 1121534

Remove the NotImplemented initializer and actually create instances of your class, instead of mutating the class itself:

class CatZoo(object):
    def __init__(self, name, age, gender, location):
        self._names = name
        self._ages = age 
        self._genders = gender
        self._location = location

    @classmethod
    def make_zoo_cat(cls, name, ages, genders, location):
        return cls.mak_zoo_cats([name], age, gender, location)

    @classmethod
    def make_zoo_cats(cls, names, ages, genders, location):
        return CatZoo(names, age, gender, location)

    @property
    def location(self):
        return self._location

    @property
    def names(self):
        return self._names

    def age(self, name):
        if name in self._names:
            return self._ages[self._names.index(name)]
        else:
            return None

    def gender(self, name):
        if name in self._names:
            return self._genders[self._names.index(name)]
        else:
            return None

    @property
    def meow(self):
        return "meow!"

Note that there was no real difference other than the method name between make_zoo_cat and make_zoo_cats, the difference in argument names doesn't change the functionality here.

Instead, I presumed that ._names should always be a list and that make_zoo_cat (singular) should create a CatZoo with one cat name in it.

Just remember that Python is not Java; you really don't need all those property objects, not where you could just access the attribute directly.

Upvotes: 3

Related Questions