Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I'm new with oop and python. I've been trying to do a simple thing: there is class called Foo(),it contains a variable called x which is initially set to zero.

>>>a = Foo()
>>>a.x
>>>0 

now I want to give a new value to x so:

>>>p.x = 1983

now a math operation should happen to x, for instance 1 is add to x.now x is 1984,so now when I call x:

>>> p.x
>>> 1984

also the program should check that whether or not the value given to x is negative or not.If it is negative it should return -1. I did this but it didn't work:(as I said it should do some mathematical operation on x,the operation itself is not really important)

class Foo():
    x = 0
    if x > 0:
        x %= 100
    elif x < 0:
        x = -1

I really don't now how should I update a class variable in they I mentioned. Thank you very much for your attention.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
126 views
Welcome To Ask or Share your Answers For Others

1 Answer

Assuming you don't need actual class attributes (you're always constructing an instance of Foo to use the attribute anyway, and it's not common for class attributes to be both public and logically mutable), the correct solution is to make x a property that wraps an instance attribute, which has independent values per instance, established in the __init__ initializer for the class:

class Foo:
    def __init__(self):
        self._x = 0  # _x is a protected instance attr that the property uses behind the scenes

    @property
    def x(self):  # getter for x is normal
        return self._x

    @x.setter
    def x(self, newx):  # setter for x massages the value before setting it
        if newx >= 0:  # Cheaper to handle 0 on same code path as > 0 so you needn't test < 0
            newx %= 100
        else:
            newx = -1
        self._x = newx

Usage is pretty simple:

>>> myfoo = Foo()
>>> myfoo.x = 1983
>>> myfoo.x
83
>>> myfoo.x = -3748972983
>>> myfoo.x
-1

In case it really needs to be a class attribute and it must be accessible on instances, the solution gets ugly, as you need a metaclass to provide propertys on classes, and additional properties on the class itself to delegate access on instances to the class itself.

Note: I strongly discourage actually doing this as anything other than an exercise:

class FooMeta(type):  # Inheriting from type makes metaclass
    @property
    def x(cls):
        return cls._x
    @x.setter
    def x(cls, newx):
        if newx >= 0:
            newx %= 100
        else:
            newx = -1
        cls._x = newx

class Foo(metaclass=FooMeta):
    _x = 0
    # Must make properties on class if instances are to "benefit" from class property
    @property
    def x(self):
        return type(self).x
    @x.setter
    def x(self, newx):
        type(self).x = newx

That allows the following to work:

>>> Foo.x  # x exists on Foo itself, not just instances
>>> Foo.x = 1983
>>> Foo.x
83
>>> f = Foo()
>>> f.x  # Accessible on instances too
83
>>> f.x = -234789
>>> f.x  # Same behavior on instance
-1
>>> Foo.x  # Changing instance changed class

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...