plean plean - 2 months ago 13
Python Question

can python classes share variable with parent classe

I have a class named

SocialPlatform
:

class SocialPlatform:
nb_post = 0

def __init__(self, data):
self.data = data
self._init_type()
self.id_post = self._init_id_post()

@classmethod
def _init_id_post(cls):
cls.nb_post += 1
return cls.nb_post


and threee other classes that inherit from
SocialPlatform
:

class Facebook(SocialPlatform):
_NAME = 'facebook'

@classmethod
def get_class_name(cls):
return cls._NAME

# code here


class Twitter(SocialPlatform):
_NAME = 'twitter'

@classmethod
def get_class_name(cls):
return cls._NAME

# code here


class Instagram(SocialPlatform):
_NAME = 'instagram'

@classmethod
def get_class_name(cls):
return cls._NAME

# code here


My idea was to increment
nb_post
each time an instance of
SocialPlatform
was created. I tought this variable was shared between all the classes that inherit from
SocialPlatform


So I tested that in my main function :

def main():
post = Post() # an other class with stuff in it, it doesn't matter here
social_platform = {
'facebook': Facebook,
'twitter': Twitter,
'instagram': Instagram
}
while True:
try:
platform = social_platform[post.actual_post['header']['platform']](post.actual_post['data'])
except KeyError:
print 'Platform (%s) not implemented yet' % post.actual_post['header']['platform']
sys.exit(84)

print 'platform name : ' + platform.get_class_name()
print 'post id : ' + str(platform.id_post)
# platform.aff_content()

post.pop()
if not len(post.post):
break

print 'enter return to display next post'
while raw_input() != "": pass


but when I use this code I get this output :

platform name : twitter
post id : 1
enter return to display next post

platform name : facebook
post id : 1
enter return to display next post

platform name : twitter
post id : 2


With this method
nb_post
is shared between Twitter, Facebook or Instagram instance, not all of them.

So my question is : is there any way to do this in python ?

Answer

When an attribute is not found, it will be looked up on a higher level. When assigning, the most local level is used though.

For example:

class Foo:
    v = 1

a = Foo()
b = Foo()

print(a.v) # 1: v is not found in "a" instance, but found in "Foo" class
Foo.v = 2 # modifies Foo class's "v"
print(a.v) # 2: not found in "a" instance but found in class
a.v = 3 # creates an attribute on "a" instance, does not modify class "v"
print(Foo.v) # 2
print(b.v) # 2: not found in "b" instance but found in "Foo" class

Here _init_id_post was declared a classmethod, and you're doing cls.nb_post = cls.nb_post + 1. In this expression, the second cls.nb_post occurence will refer to SocialPlatform the first time, then you assign on the cls object which is refering to the Twitter or Instagram class, not SocialPlatform. When you call it again on the same class, the second cls.nb_post occurence will not refer to SocialPlatform since you created the attribute at the level of the Twitter class (for example).

The solution is not to use cls but use SocialPlatform.nb_post += 1 (and make it a @staticmethod)