How to restrict access to Python class properties

Take the next class

class Person(object): def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_name 

How can I prevent the next use?

 p1 = Person('Foo', 'Bar') p1.firstname='Fooooooo' 

The above code will execute successfully in Python, however, an error was made with the property name, i.e. missing _ between first and name

UPDATE: This sounds like โ€œMonkey Patchingโ€, why do I want to do this?

My intention is simply to help the user set the wrong property, execute the code and see unexpected behavior and not know about the error right away.

What does Pythonic recommend here?

+6
source share
1 answer

First of all, it is almost always a bad idea. If only the reason why you want to make sure that you do not make typos - there are better tools for this (think IDE or pylint). If you are 100% sure that you need this, here are two ways to do it:

The first way - you can do this using the __setattr__ method. See python __setattr__ documentation

 class Person(object): def __init__(self, first_name, last_name): self.__dict__['first_name'] = first_name self.__dict__['last_name'] = last_name def __setattr__(self, name, value): if name in self.__dict__: super(Person, self).__setattr__(name, value) else: raise AttributeError("%s has no attribute %s" %(self.__class__.__name__, name)) 

and conclusion:

 In [49]: a = Person(1, 2) In [50]: aa = 2 --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) /usr/local/lib/python2.7/dist-packages/django/core/management/commands/shell.pyc in <module>() ----> 1 aa = 2 /usr/local/lib/python2.7/dist-packages/django/core/management/commands/shell.pyc in __setattr__(self, name, value) 8 super(Person, self).__setattr__(name, value) 9 else: ---> 10 raise AttributeError("%s has no attribute %s" %(self.__class__.__name__, name)) AttributeError: Person has no attribute a 

Alternatively, you can do this using __slots__ ( python __slots__ documentation ):

 class Person(object): __slots__ = ("first_name", "last_name") def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_name 

output:

 In [32]: a = Person("a", "b") In [33]: a.first_name Out[33]: 'a' In [34]: aa = 1 --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) /usr/local/lib/python2.7/dist-packages/django/core/management/commands/shell.pyc in <module>() ----> 1 aa = 1 AttributeError: 'Person' object has no attribute 'a' 

The first method is more flexible, since it allows you to crack this code even further using __dict__ directly, but it will be even more wrong than now. The second approach predetermines the space for a certain number of instance variables (links), which means less memory consumption.

+7
source

Source: https://habr.com/ru/post/943886/


All Articles