1

Since my privatization trick works in both IDLE and the python3 REPL:

>>> class A(object):
...     __slots__ = ['attr']
... 
>>> dscget = A.__dict__['attr'].__get__
>>> dscset = A.__dict__['attr'].__set__
>>> del A.attr
>>> 

but not quite in my program (same exact setup and mechanics)

Python 3.4.3 |Anaconda 2.3.0 (32-bit)| (default, Mar  6 2015, 12:08:17) [MSC v.1600 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>> 
Traceback (most recent call last):
  File "\home\tcll\Projects\python\UGE\test_FORMAT.py", line 5, in <module>
    import API
  File "\home\tcll\Projects\python\UGE\API\__init__.py", line 43, in <module>
    from . import CONST, OBJECT
  File "\home\tcll\Projects\python\UGE\API\OBJECT\__init__.py", line 191, in <module>
    from ._collection import *
  File "\home\tcll\Projects\python\UGE\API\OBJECT\_collection.py", line 209, in <module>
    private()
  File "\home\tcll\Projects\python\UGE\API\OBJECT\_collection.py", line 187, in private
    getbase,        setbase         = getset( UGECollection, '__base__' );          del UGECollection.__base__
AttributeError: readonly attribute
>>> 

I should note this is actually the 3rd class that loads, the first 2 classes actually work as expected and load without issue, though they don't delete the attributes, only overwrite them with read-only properties.

I want to know how member_descriptor is initialized and registered to the class so I can look into creating them without the need for a reference in the class dict.

the member_descriptor name can be obtained easily, but instance creation seems very difficult:

>>> class A(object):
...     __slots__ = ['attr']
... 
>>> member_descriptor = A.attr.__class__
>>> member_descriptor()
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    member_descriptor()
TypeError: cannot create 'member_descriptor' instances
>>> member_descriptor.__new__(member_descriptor)
Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    member_descriptor.__new__(member_descriptor)
TypeError: object.__new__(member_descriptor) is not safe, use member_descriptor.__new__()
>>> 

I'm pretty sure it's impossible to do it through python, but how can I do it through something like ctypes or cffi??

Tcll
  • 7,140
  • 1
  • 20
  • 23
  • I'm not sure I have understood your question, but perhaps are you interested in [properties](https://docs.python.org/3/howto/descriptor.html?highlight=property#properties)? If not, could you please show the code that is not working, and could you also clarify what you're trying to obtain? – Andrea Corbellini Jan 13 '18 at 00:35
  • unfortunately, the code is too large to simply show, but the console example above gives the general idea, and no, it doesn't matter if it's in a function, or through setattr() or whatever, it behaves the same regardless... what I'm trying to do is separate the descriptor from the class, I don't need nor want instance access to the descriptor, hence the privatization. – Tcll Jan 13 '18 at 01:07
  • I'm currently trying to find out of there's anything that might be interfering to cause the third class to break, since I'm basically doing setattr() in the first 2: https://stackoverflow.com/questions/20019333/modify-class-dict-mappingproxy-in-python – Tcll Jan 13 '18 at 01:07

1 Answers1

0

Well, creating a member_descriptor outside of a defined class isn't exactly possible since a __slots__ class is basically a C struct{}, where the member_descriptor instance is basically a wrapper that handles a pointer to the struct instance...
and as I understand, you can't modify an existing struct definition...

so I ultimately decided on using an alternate privatized class as a workaround for storing the private attributes like so:

def private():
    privateRegistry = {} # as long as I don't need access to private attributes within __hash__ it won't infinitely recurse
    getprivate = privateRegistry.__getitem__; setprivate = privateRegistry.__setitem__ # just for quick access

    class privateAttrs(object):
        __slots__ = ['a']
    get_a, set_a = getset( privateAttrs, 'a', privatize=False ) # just for quick access

    new = object.__new__
    class Object(object):
        __slots__ = ['public']
        def __new__(cls):
            i = new(cls)
            p = new(privateAttrs); setprivate( i, p )
            set_a( p, 15 ) # p.a = 15 with no dot operator slowness since you're calling __set__ directly

        def __getitem__(i, item):
            p = getprivate(i)
            return get_a(p)

    return Object

Object = private()
del private

Something I find funny though... Out of about 15 classes I'm privatizing in the same manner as UGECollection above, UGECollection is the only offender...

EDIT: Also, I know this isn't truely private, but it's better than __not_so_private attributes...
you can pick any one of Object's methods to gain access to specific getters and setters of the private attributes (or the private class itself in this case) from __closure__ (despite knowing it's possible to write to read-only properties), but there's a level of security from that which I'm comfortable with since cells are indexed rather than keyed and you can't expect cells to remain in the same order (if at all) with an active project.

Tcll
  • 7,140
  • 1
  • 20
  • 23