मैं बस PEP8 के माध्यम से फिर से पढ़ रहा था और इस लाइन पर ठोकर खाई:

हम यहां "निजी" शब्द का उपयोग नहीं करते हैं, क्योंकि वास्तव में कोई विशेषता नहीं है पायथन में निजी (आम तौर पर अनावश्यक मात्रा में काम के बिना)।

मैं बस सोच रहा था कि अगर मैं एक विधि को वास्तव में निजी बनाना चाहता हूं तो यह "अनावश्यक काम" क्या होगा?

2
pavel 2 जुलाई 2020, 06:04

2 जवाब

सबसे बढ़िया उत्तर

इसके लिए एक स्पेक्ट्रम है। अधिक गोपनीयता अधिक काम लेती है, लेकिन इसे दरकिनार करना कठिन है। "वास्तव में निजी" के लिए कोई स्पष्ट रेखा नहीं है।

अग्रणी डबल अंडरस्कोर कम से कम निजी विकल्प हैं। किसी विशेषता पर अग्रणी डबल अंडरस्कोर चिपकाना आसान है, लेकिन मैन्युअल नाम मैंगलिंग द्वारा बाईपास करना भी आसान है।

कोड और बाईपास:

class Private1:
    def __init__(self, data):
        self.__data = data
    def get_data(self):
        return self.__data

x = Private1(1)

# Direct access fails...
x.__data = 2

# but you can do the name mangling manually.
x._Private1__data = 2

अगला अप क्लोजर वेरिएबल्स या हिडन स्लॉट्स जैसी चीजें होंगी। आप मैंगलिंग नाम से उन तक नहीं पहुंच सकते हैं, लेकिन आप अभी भी मैन्युअल रूप से क्लोजर सेल तक पहुंच सकते हैं या पता लगा सकते हैं कि स्लॉट गेटर कहां है।

बंद चर उदाहरण, बाईपास के साथ:

class Private2:
    def __init__(self, data):
        def get_data():
            return data
        self.get_data = get_data

x = Private2(1)

# It's not immediately obvious how you'd even try to access the data variable directly,
# but you can:
x.get_data.__closure__[0].cell_contents = 2

छिपे हुए स्लॉट उदाहरण, बाईपास के साथ:

class Private3:
    __slots__ = ('data',)
    def __init__(self, data):
        _hidden_slot.__set__(self, data)
    def get_data(self):
        return _hidden_slot.__get__(self, type(self))
_hidden_slot = Private3.data
del Private3.data

x = Private3(1)

# Direct access fails...
x.data = 2

# but you can directly access the slot getter the same way the actual class did:
_hidden_slot.__set__(x, 2)

उसके बाद अगला कदम सी एक्सटेंशन होगा। मैन्युअल रूप से C एक्सटेंशन लिखना बहुत काम का है, इतना है कि मैं एक उदाहरण के साथ परेशान नहीं होने जा रहा हूं (लेकिन यहां एक ट्यूटोरियल लिंक, और Cython इसे बहुत आसान बनाता है), लेकिन प्रकार सी में लागू डिफ़ॉल्ट रूप से अपने आंतरिक डेटा को पायथन स्तर पर उजागर नहीं करते हैं। यदि प्रकार पहुंच प्रदान करने के लिए कोई विशिष्ट प्रयास नहीं करता है, तो डेटा तक पहुंचने का एकमात्र तरीका अधिक सी, या ctypes, या gc.get_referents जैसे सामान के साथ होगा यदि छुपा डेटा एक जीसी है -उजागर पायथन संदर्भ। (gc.get_referents का सही उपयोग उपरोक्त सभी सुरक्षा को बायपास भी कर सकता है।)

उस के बाद अगला कदम डेटा को अपने निजी सर्वर पर रखना होगा, और केवल क्लाइंट को इंटरनेट एपीआई के माध्यम से इसे एक्सेस करने देना होगा। यह किसी भी private कीवर्ड की तुलना में बहुत अधिक निजी है, और इसे दरकिनार करने के लिए भेद्यता शोषण या सम्मन या शारीरिक हिंसा या कुछ और जैसी किसी चीज़ की आवश्यकता होती है।

1
user2357112 supports Monica 2 जुलाई 2020, 06:28

शुद्ध पायथन में, निकटतम आप "सत्य" एनकैप्सुलेशन प्राप्त कर सकते हैं, क्लोजर में चर के माध्यम से होता है (चूंकि फ़ंक्शन वापस आने के बाद आप उन्हें सीधे एक्सेस/असाइन नहीं कर सकते हैं)। यहाँ एक छोटा सा स्केच है:

def OneTruePrivate():
    """hax which uses a closure to make _truly_ private variables"""
    x = 1

    class OneTruePrivate:
        @property
        def val(self):
            return x

        def increment(self):
            nonlocal x
            x += 1

    return OneTruePrivate()


var = OneTruePrivate()
print('initial value')
print(var.val)
var.increment()
print('after incremnet')
print(var.val)
print('look ma, no object state!')
import pprint; pprint.pprint(vars(var))

आउटपुट:

initial value
1
after incremnet
2
look ma, no object state!
{}

उसने कहा, यहां तक ​​कि कुछ हैकरी के साथ भी आप अंतर्निहित क्लोजर मान को बदल सकते हैं

cell = var.increment.__func__.__closure__[0]
import ctypes
ctypes.pythonapi.PyCell_Set.argtypes = (ctypes.py_object, ctypes.py_object)
ctypes.pythonapi.PyCell_Set(cell, 9001)
print(var.val)

आउटपुट:

9001
2
Anthony Sottile 2 जुलाई 2020, 06:09