Is there a way to create a Python class method that DOES NOT pollute the attribute namespace of its instances?

I want to provide a method that can be used in an object of the Python 2.7 class, but does not pollute the attribute namespace of its instances. Is there any way to do this?

>>> class Foo(object):
...   @classmethod
...   def ugh(cls):
...     return 33
...
>>> Foo.ugh()
33
>>> foo = Foo()
>>> foo.ugh()
33
+4
source share
4 answers

You can subclass the classmethod handle:

class classonly(classmethod):
    def __get__(self, obj, type):
        if obj: raise AttributeError
        return super(classonly, self).__get__(obj, type)

So it will be:

class C(object):
    @classonly
    def foo(cls):
        return 42
>>> C.foo()
42
>>> c=C()
>>> c.foo()
AttributeError

This desugars to call the descriptor (rather, it is called by the default implementation __getattribute__):

>>> C.__dict__['foo'].__get__(None, C)
<bound method C.foo of <class '__main__.C'>>
>>> C.__dict__['foo'].__get__(c, type(c))
AttributeError

Required reading: Data Model - Implementing Descriptors and the HowTo Descriptor Guide .

+4
source

ugh :

>>> foo.__dict__
{}

. Foo.__getattribute__, .

class Foo(object):
    @classmethod
    def ugh(cls):
        return 33

    def __getattribute__(self, name):
        if name == 'ugh':
            raise AttributeError("Access to class method 'ugh' block from instance")
        return super(Foo,self).__getattribute__(name)

:

>>> foo = Foo()
>>> foo.ugh()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "tmp.py", line 8, in __getattribute__
    raise AttributeError("Access to class method 'ugh' block from instance")
AttributeError: Access to class method 'ugh' block from instance
>>> Foo.ugh()
33

__getattribute__, , __getattr__, , ( ) .

+4

, .

class FooMeta(type):
    # No @classmethod here
    def ugh(cls):
        return 33

class Foo(object):
    __metaclass__ = FooMeta

Foo.ugh()  # returns 33
Foo().ugh()  # AttributeError

, , , . , , .

+2

Python has quasi-private variables that use name switching to reduce random access. Methods and object variables of the form are __nameconverted to _ClassName__name. Python automatically changes the name when compiling methods in a class, but does not change the name for subclasses.

I can use a private method in the class

>>> class A(object):
...     def __private(self):
...         print('boo')
...     def hello(self):
...         self.__private()
... 
>>> 
>>> A().hello()
boo

But not out of class

>>> A().__private()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute '__private'
>>> 

Or in subclasses

>>> class B(A):
...     def hello2(self):
...         self.__private()
... 
>>> 
>>> B().hello()
boo
>>> B().hello2()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in hello2
AttributeError: 'B' object has no attribute '_B__private'
+1
source

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


All Articles