1

Let's say I have a class A

class A:
    __slots__ = ['_x']

    def __init__(self):
         self._x = 10
    
    @property
    def x(self):
        return self._x

And I want to restrcit assigning to a._x from anywhere except other instance's methods.

How do I do that? Is that even possible in Python?

The thing is to write a class which attributes is changeable only within particular methods and never directly from outside.

regM
  • 13
  • 2
  • 1
    Does this answer your question? [How to restrict setting an attribute outside of constructor?](https://stackoverflow.com/questions/10929004/how-to-restrict-setting-an-attribute-outside-of-constructor) – TYZ May 14 '21 at 21:00

2 Answers2

2

Python doesn't really have "private" variables like C++. Even if you set the variable as private by using a the _ prefix from PEP8 (as you have done). You can always access the variable using A._x.

If you want to emulate private variables for some reason, you can use __ (double underscore) prefix as it mangles the name. Similarly you can use @property decorator to make a getter and setter function and prevent access to the attribute. However, even these fail as you can access the variables directly using __dict__.

So the Pythonic way is to leave it the way it is. Python is like perl in this respect. To paraphrase a famous line about privacy from the Perl book,

the philosophy is that you should stay out of the living room because you weren't invited, not because it is defended with a shotgun.

kinshukdua
  • 1,944
  • 1
  • 5
  • 15
  • Well, I'm not completely new to Python and am familiar with this philosophy. In this particular case, however, I was looking for a workaround. Kinda thing you want to do just because. As an exercise :) But I guess it would be already implemented if it were possible. Thanks for stopping me from wasting time :) – regM May 15 '21 at 07:26
-1

I totally agree with @kinshukdua on this. However, just to explore more options available to you. you can override the setattr by placing some condition

This might not be the most pythonic way, but i am open to a more cleaner way to acheive this.

class A:
    _x = 10 #dont think you need an init method since you are not adding any data
    def __setattr__(self, key, value):
        if 'yes' in value[1]:
            super().__setattr__(key,value[0])
        else:
            raise TypeError('You should not have access to this')

    def change(self, value,loc= 'yes'):
        self._x = value,loc
        return self._x
        
    
    
Ade_1
  • 1,480
  • 1
  • 6
  • 17
  • I actually thought of metaprogramming to solve this. Like creating a metaclass which creates Lock object and context manager for it and attaches it to a class instance and then overrides the setattr magic method so after that attributes can be added and assigned only if Lock is opened. Do all of that during '__new__' call and then use a lock to assign other attributes during init or other methods calls. – regM May 16 '21 at 14:48