Properti hanya baca Python

97

Saya tidak tahu kapan atribut harus bersifat pribadi dan apakah saya harus menggunakan properti.

Saya baru-baru ini membaca bahwa setter dan getter bukan pythonic dan saya harus menggunakan dekorator properti. Tidak apa-apa.

Tetapi bagaimana jika saya memiliki atribut, yang tidak boleh disetel dari luar kelas tetapi dapat dibaca (atribut read-only). Haruskah atribut ini bersifat pribadi, dan yang saya maksud dengan garis bawah, seperti itu pribadi self._x? Jika ya, bagaimana saya bisa membacanya tanpa menggunakan getter? Satu-satunya metode yang saya ketahui saat ini adalah menulis

@property
def x(self):
    return self._x

Dengan cara itu saya bisa membaca atribut dengan obj.xtetapi saya tidak bisa mengaturnya obj.x = 1jadi tidak apa-apa.

Tetapi haruskah saya benar-benar peduli tentang pengaturan objek yang tidak boleh disetel? Mungkin sebaiknya aku tinggalkan saja. Tetapi sekali lagi saya tidak dapat menggunakan garis bawah karena membaca obj._xitu aneh bagi pengguna, jadi saya harus menggunakan obj.xdan sekali lagi pengguna tidak tahu bahwa dia tidak boleh menyetel atribut ini.

Apa pendapat dan praktik Anda?

Rafał Łużyński
sumber
1
Ide dari properti adalah bahwa properti berperilaku seperti atribut tetapi dapat memiliki kode tambahan. Jika yang Anda inginkan hanyalah mendapatkan nilai, saya tidak akan repot-repot: gunakan saja self.xdan percaya bahwa tidak ada yang akan berubah x. Jika memastikan bahwa xtidak dapat diubah itu penting, gunakan properti.
li.davidm
Juga, _xtidak aneh sama sekali: menurut konvensi , itu berarti sesuatu yang "pribadi".
li.davidm
1
Maksud saya, membaca dari _x itu aneh. Bukan nama _x itu sendiri. Jika pengguna membaca langsung dari _x maka dia tidak bertanggung jawab.
Rafał Łużyński
3
Penting! Kelas Anda harus merupakan kelas gaya baru yaitu mewarisi dari object, agar ini benar-benar menghentikan pengaturan Anda obj.x. Pada kelas gaya lama Anda sebenarnya masih dapat mengatur obj.x, dengan hasil yang cukup tidak terduga.
Ian H
Ada beberapa alasan yang valid untuk memiliki properti hanya-baca. Pertama adalah ketika Anda memiliki nilai yang terdiri dari penggabungan dua nilai (baca / tulis) lainnya. Anda dapat melakukan ini dengan metode, tetapi Anda juga dapat melakukannya di properti hanya baca.
philologon

Jawaban:

73

Umumnya, program Python harus ditulis dengan asumsi bahwa semua pengguna menyetujui orang dewasa, dan karenanya bertanggung jawab untuk menggunakan berbagai hal dengan benar sendiri. Namun, dalam kasus yang jarang terjadi di mana tidak masuk akal jika atribut dapat diatur (seperti nilai turunan, atau nilai yang dibaca dari beberapa sumber data statis), properti khusus pengambil umumnya merupakan pola yang disukai.

Silas Ray
sumber
26
Sepertinya jawaban Anda bertentangan dengan dirinya sendiri. Anda mengatakan bahwa pengguna harus bertanggung jawab dan menggunakan sesuatu dengan benar, lalu Anda mengatakan bahwa kadang-kadang tidak masuk akal untuk atribut yang harus diselesaikan dan properti pengambil adalah cara yang diutamakan. Menurut pendapat saya Anda bisa atau tidak bisa mengatur atribut. Satu-satunya pertanyaan adalah apakah saya harus melindungi atribut ini atau meninggalkannya. Seharusnya tidak ada jawaban di antaranya.
Rafał Łużyński
20
Tidak, saya katakan jika Anda benar-benar tidak dapat menetapkan nilai, maka tidak masuk akal untuk memiliki penyetel. Misalnya, jika Anda memiliki objek lingkaran dengan anggota radius dan atribut keliling yang diturunkan dari radius, atau Anda memiliki objek yang membungkus beberapa api waktu-nyata hanya-baca dengan sejumlah properti hanya-pengambil. Tidak ada yang bertentangan.
Silas Ray
9
Tetapi pengguna yang bertanggung jawab tidak akan mencoba menyetel attr yang secara harfiah tidak bisa disetel. Dan lagi-lagi pengguna yang tidak bertanggung jawab akan mengeset attr yang secara harfiah bisa disetel dan akan menimbulkan kesalahan di tempat lain dalam kode karena setnya. Jadi pada akhirnya kedua attr tidak bisa disetel. Haruskah saya menggunakan properti di keduanya atau tidak menggunakannya di mana pun?
Rafał Łużyński
8
Tetapi pengguna yang bertanggung jawab tidak boleh mencoba menyetel attr yang secara harfiah tidak bisa disetel. Dalam pemrograman, jika sesuatu benar-benar merupakan nilai yang tidak dapat ditentukan, hal yang bertanggung jawab atau masuk akal adalah memastikan bahwa itu tidak dapat terjadi. Hal-hal kecil ini semuanya berkontribusi pada program yang andal.
Robin Smith
6
Itu adalah posisi yang diambil oleh banyak orang dan bahasa. Jika ini adalah posisi yang menurut Anda tidak dapat ditawar, Anda mungkin tidak boleh menggunakan Python.
Silas Ray
75

Hanya dua sen saya, Silas Ray berada di jalur yang benar, namun saya ingin menambahkan contoh. ;-)

Python adalah jenis bahasa yang tidak aman dan oleh karena itu Anda harus selalu mempercayai pengguna kode Anda untuk menggunakan kode seperti orang yang masuk akal (masuk akal).

Per PEP 8 :

Gunakan satu garis bawah hanya untuk metode non-publik dan variabel instan.

Untuk memiliki properti 'hanya-baca' di kelas Anda dapat menggunakan @propertydekorasi, Anda harus mewarisi dari objectsaat Anda melakukannya untuk menggunakan kelas gaya baru.

Contoh:

>>> class A(object):
...     def __init__(self, a):
...         self._a = a
...
...     @property
...     def a(self):
...         return self._a
... 
>>> a = A('test')
>>> a.a
'test'
>>> a.a = 'pleh'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
siebz0r
sumber
9
Python bukanlah tipe yang tidak aman, itu diketik secara dinamis. Dan name mangling bukan untuk membuatnya lebih sulit untuk ditipu, tetapi untuk mencegah bentrokan nama dalam skenario di mana warisan bisa menjadi masalah (jika Anda tidak memprogram secara besar-besaran Anda seharusnya tidak peduli).
memeplex
3
Tetapi Anda harus tetap ingat, bahwa objek yang bisa berubah dapat diubah menggunakan metode ini. Misalnya jika self.__a = [], Anda masih bisa melakukan ini a.a.append('anything')dan itu akan berhasil.
Igor
3
Tidak jelas bagi saya apa arti sikap "orang yang berakal sehat" terhadap jawaban ini. Dapatkah Anda lebih eksplisit tentang hal-hal yang menurut Anda akan dan tidak akan dilakukan oleh orang yang berakal sehat?
winni2k
3
Bagi saya, gunakan dekorasi @property, Anda harus mewarisi dari objek ketika Anda melakukannya adalah inti dari jawaban ini. Terima kasih.
akki
2
@kkm satu-satunya cara untuk tidak pernah membiarkan bug menyusup ke dalam kode adalah dengan tidak pernah menulis kode.
Alechan
58

Berikut adalah cara untuk menghindari anggapan itu

semua pengguna menyetujui orang dewasa, dan dengan demikian bertanggung jawab untuk menggunakan berbagai hal dengan benar.

silakan lihat pembaruan saya di bawah ini

Menggunakan @property, sangat bertele-tele misalnya:

   class AClassWithManyAttributes:
        '''refactored to properties'''
        def __init__(a, b, c, d, e ...)
             self._a = a
             self._b = b
             self._c = c
             self.d = d
             self.e = e

        @property
        def a(self):
            return self._a
        @property
        def b(self):
            return self._b
        @property
        def c(self):
            return self._c
        # you get this ... it's long

Menggunakan

Tanpa garis bawah: ini adalah variabel publik.
Satu garis bawah: ini adalah variabel yang dilindungi.
Dua garis bawah: ini adalah variabel privat.

Kecuali yang terakhir, ini konvensi. Anda masih dapat, jika benar-benar berusaha keras, mengakses variabel dengan garis bawah ganda.

Jadi apa yang kita lakukan? Apakah kita menyerah untuk memiliki properti hanya baca di Python?

Melihat! read_only_propertiesdekorator untuk menyelamatkan!

@read_only_properties('readonly', 'forbidden')
class MyClass(object):
    def __init__(self, a, b, c):
        self.readonly = a
        self.forbidden = b
        self.ok = c

m = MyClass(1, 2, 3)
m.ok = 4
# we can re-assign a value to m.ok
# read only access to m.readonly is OK 
print(m.ok, m.readonly) 
print("This worked...")
# this will explode, and raise AttributeError
m.forbidden = 4

Anda bertanya:

Dari mana read_only_propertiesasalnya

Senang Anda bertanya, berikut adalah sumber read_only_properties :

def read_only_properties(*attrs):

    def class_rebuilder(cls):
        "The class decorator"

        class NewClass(cls):
            "This is the overwritten class"
            def __setattr__(self, name, value):
                if name not in attrs:
                    pass
                elif name not in self.__dict__:
                    pass
                else:
                    raise AttributeError("Can't modify {}".format(name))

                super().__setattr__(name, value)
        return NewClass
    return class_rebuilder

memperbarui

Saya tidak pernah menyangka jawaban ini akan mendapat banyak perhatian. Anehnya memang begitu. Ini mendorong saya untuk membuat paket yang dapat Anda gunakan.

$ pip install read-only-properties

di shell python Anda:

In [1]: from rop import read_only_properties

In [2]: @read_only_properties('a')
   ...: class Foo:
   ...:     def __init__(self, a, b):
   ...:         self.a = a
   ...:         self.b = b
   ...:         

In [3]: f=Foo('explodes', 'ok-to-overwrite')

In [4]: f.b = 5

In [5]: f.a = 'boom'
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-5-a5226072b3b4> in <module>()
----> 1 f.a = 'boom'

/home/oznt/.virtualenvs/tracker/lib/python3.5/site-packages/rop.py in __setattr__(self, name, value)
    116                     pass
    117                 else:
--> 118                     raise AttributeError("Can't touch {}".format(name))
    119 
    120                 super().__setattr__(name, value)

AttributeError: Can't touch a
Oz123
sumber
1
Ini sangat membantu, dan melakukan apa yang ingin saya lakukan. Terima kasih. Namun, ini untuk mereka yang menginstal Python 3. Saya menggunakan Python 2.7.8, jadi saya harus menerapkan dua perubahan kecil pada solusi Anda: "class NewClass (cls, <b> object <\ b>):" ... "<b> super (NewClass, self) <\ b> .__ setattr __ (nama, nilai) ".
Ying Zhang
1
Selain itu, seseorang harus berhati-hati tentang variabel anggota kelas menjadi daftar dan kamus. Anda tidak dapat benar-benar 'mengunci mereka' agar tidak diperbarui dengan cara ini.
Ying Zhang
1
Satu perbaikan dan tiga masalah di sini. Perbaikan: if..elif..elseblok bisa saja if name in attrs and name in self.__dict__: raise Attr...tanpa passdiperlukan. Masalah 1: kelas-kelas yang didekorasi dengan demikian semuanya berakhir dengan sebuah identik __name__, dan representasi string dari tipenya juga dihomogenisasi. Masalah 2: dekorasi ini menimpa kebiasaan apa pun __setattr__. Masalah 3: Pengguna dapat mengalahkan ini dengan del MyClass.__setattr__.
TigerhawkT3
Hanya masalah bahasa. "Aduh ..." berarti "Sedih untuk mengatakan, ..." yang bukan itu yang Anda inginkan, menurut saya.
Thomas Andrews
Tidak ada yang akan menghalangi saya untuk melakukan object.__setattr__(f, 'forbidden', 42). Saya tidak melihat read_only_propertiespenambahan apa yang tidak ditangani oleh nama garis bawah ganda mangling.
L3viathan
4

Berikut adalah pendekatan yang sedikit berbeda untuk properti hanya-baca, yang mungkin harus disebut properti sekali tulis karena harus diinisialisasi, bukan? Untuk paranoid di antara kita yang khawatir bisa mengubah properti dengan mengakses kamus objek secara langsung, saya telah memperkenalkan mangling nama "ekstrim":

from uuid import uuid4

class Read_Only_Property:
    def __init__(self, name):
        self.name = name
        self.dict_name = uuid4().hex
        self.initialized = False

    def __get__(self, instance, cls):
        if instance is None:
            return self
        else:
            return instance.__dict__[self.dict_name]

    def __set__(self, instance, value):
        if self.initialized:
            raise AttributeError("Attempt to modify read-only property '%s'." % self.name)
        instance.__dict__[self.dict_name] = value
        self.initialized = True

class Point:
    x = Read_Only_Property('x')
    y = Read_Only_Property('y')
    def __init__(self, x, y):
        self.x = x
        self.y = y

if __name__ == '__main__':
    try:
        p = Point(2, 3)
        print(p.x, p.y)
        p.x = 9
    except Exception as e:
        print(e)
Booboo
sumber
Bagus. dict_nameSebaliknya, jika Anda mengacaukan , misalnya dict_name = "_spam_" + namemenghapus ketergantungan pada uuid4dan membuat debugging menjadi jauh lebih mudah.
cz
Tapi kemudian saya bisa mengatakan p.__dict__['_spam_x'] = 5untuk mengubah nilai p.x, jadi ini tidak memberikan nama mangling yang cukup.
Booboo
1

Saya tidak puas dengan dua jawaban sebelumnya untuk membuat properti hanya baca karena solusi pertama memungkinkan atribut readonly dihapus dan kemudian disetel dan tidak memblokir __dict__. Solusi kedua dapat diselesaikan dengan pengujian - menemukan nilai yang sama dengan yang Anda tetapkan dua dan mengubahnya pada akhirnya.

Sekarang, untuk kodenya.

def final(cls):
    clss = cls
    @classmethod
    def __init_subclass__(cls, **kwargs):
        raise TypeError("type '{}' is not an acceptable base type".format(clss.__name__))
    cls.__init_subclass__ = __init_subclass__
    return cls


def methoddefiner(cls, method_name):
    for clss in cls.mro():
        try:
            getattr(clss, method_name)
            return clss
        except(AttributeError):
            pass
    return None


def readonlyattributes(*attrs):
    """Method to create readonly attributes in a class

    Use as a decorator for a class. This function takes in unlimited 
    string arguments for names of readonly attributes and returns a
    function to make the readonly attributes readonly. 

    The original class's __getattribute__, __setattr__, and __delattr__ methods
    are redefined so avoid defining those methods in the decorated class

    You may create setters and deleters for readonly attributes, however
    if they are overwritten by the subclass, they lose access to the readonly
    attributes. 

    Any method which sets or deletes a readonly attribute within
    the class loses access if overwritten by the subclass besides the __new__
    or __init__ constructors.

    This decorator doesn't support subclassing of these classes
    """
    def classrebuilder(cls):
        def __getattribute__(self, name):
            if name == '__dict__':
                    from types import MappingProxyType
                    return MappingProxyType(super(cls, self).__getattribute__('__dict__'))
            return super(cls, self).__getattribute__(name)
        def __setattr__(self, name, value): 
                if name == '__dict__' or name in attrs:
                    import inspect
                    stack = inspect.stack()
                    try:
                        the_class = stack[1][0].f_locals['self'].__class__
                    except(KeyError):
                        the_class = None
                    the_method = stack[1][0].f_code.co_name
                    if the_class != cls: 
                         if methoddefiner(type(self), the_method) != cls:
                            raise AttributeError("Cannot set readonly attribute '{}'".format(name))                        
                return super(cls, self).__setattr__(name, value)
        def __delattr__(self, name):                
                if name == '__dict__' or name in attrs:
                    import inspect
                    stack = inspect.stack()
                    try:
                        the_class = stack[1][0].f_locals['self'].__class__
                    except(KeyError):
                        the_class = None
                    the_method = stack[1][0].f_code.co_name
                    if the_class != cls:
                        if methoddefiner(type(self), the_method) != cls:
                            raise AttributeError("Cannot delete readonly attribute '{}'".format(name))                        
                return super(cls, self).__delattr__(name)
        clss = cls
        cls.__getattribute__ = __getattribute__
        cls.__setattr__ = __setattr__
        cls.__delattr__ = __delattr__
        #This line will be moved when this algorithm will be compatible with inheritance
        cls = final(cls)
        return cls
    return classrebuilder

def setreadonlyattributes(cls, *readonlyattrs):
    return readonlyattributes(*readonlyattrs)(cls)


if __name__ == '__main__':
    #test readonlyattributes only as an indpendent module
    @readonlyattributes('readonlyfield')
    class ReadonlyFieldClass(object):
        def __init__(self, a, b):
            #Prevent initalization of the internal, unmodified PrivateFieldClass
            #External PrivateFieldClass can be initalized
            self.readonlyfield = a
            self.publicfield = b


    attr = None
    def main():
        global attr
        pfi = ReadonlyFieldClass('forbidden', 'changable')
        ###---test publicfield, ensure its mutable---###
        try:
            #get publicfield
            print(pfi.publicfield)
            print('__getattribute__ works')
            #set publicfield
            pfi.publicfield = 'mutable'
            print('__setattr__ seems to work')
            #get previously set publicfield
            print(pfi.publicfield)
            print('__setattr__ definitely works')
            #delete publicfield
            del pfi.publicfield 
            print('__delattr__ seems to work')
            #get publicfield which was supposed to be deleted therefore should raise AttributeError
            print(pfi.publlicfield)
            #publicfield wasn't deleted, raise RuntimeError
            raise RuntimeError('__delattr__ doesn\'t work')
        except(AttributeError):
            print('__delattr__ works')


        try:
            ###---test readonly, make sure its readonly---###
            #get readonlyfield
            print(pfi.readonlyfield)
            print('__getattribute__ works')
            #set readonlyfield, should raise AttributeError
            pfi.readonlyfield = 'readonly'
            #apparently readonlyfield was set, notify user
            raise RuntimeError('__setattr__ doesn\'t work')
        except(AttributeError):
            print('__setattr__ seems to work')
            try:
                #ensure readonlyfield wasn't set
                print(pfi.readonlyfield)
                print('__setattr__ works')
                #delete readonlyfield
                del pfi.readonlyfield
                #readonlyfield was deleted, raise RuntimeError
                raise RuntimeError('__delattr__ doesn\'t work')
            except(AttributeError):
                print('__delattr__ works')
        try:
            print("Dict testing")
            print(pfi.__dict__, type(pfi.__dict__))
            attr = pfi.readonlyfield
            print(attr)
            print("__getattribute__ works")
            if pfi.readonlyfield != 'forbidden':
                print(pfi.readonlyfield)
                raise RuntimeError("__getattr__ doesn't work")
            try:
                pfi.__dict__ = {}
                raise RuntimeError("__setattr__ doesn't work")
            except(AttributeError):
                print("__setattr__ works")
            del pfi.__dict__
            raise RuntimeError("__delattr__ doesn't work")
        except(AttributeError):
            print(pfi.__dict__)
            print("__delattr__ works")
            print("Basic things work")


main()

Tidak ada gunanya membuat atribut hanya baca kecuali ketika Anda menulis kode perpustakaan, kode yang didistribusikan ke orang lain sebagai kode untuk digunakan untuk meningkatkan program mereka, bukan kode untuk tujuan lain, seperti pengembangan aplikasi. Masalah __dict__ terpecahkan, karena __dict__ sekarang dalam tipe yang tidak dapat diubah.MappingProxyType , jadi atribut tidak dapat diubah melalui __dict__. Menyetel atau menghapus __dict__ juga diblokir. Satu-satunya cara untuk mengubah properti hanya baca adalah dengan mengubah metode kelas itu sendiri.

Meskipun saya yakin solusi saya lebih baik daripada dua solusi sebelumnya, namun dapat ditingkatkan. Ini adalah kelemahan kode ini:

a) Tidak mengizinkan penambahan ke metode dalam subclass yang menyetel atau menghapus atribut hanya baca. Sebuah metode yang didefinisikan dalam subclass secara otomatis dilarang mengakses atribut readonly, bahkan dengan memanggil versi metode superclass '.

b) Metode hanya-baca kelas dapat diubah untuk mengalahkan batasan hanya-baca.

Namun, tidak ada cara tanpa mengedit kelas untuk menyetel atau menghapus atribut hanya baca. Ini tidak tergantung pada konvensi penamaan, yang bagus karena Python tidak begitu konsisten dengan konvensi penamaan. Ini menyediakan cara untuk membuat atribut hanya baca yang tidak dapat diubah dengan celah tersembunyi tanpa mengedit kelas itu sendiri. Cukup daftarkan atribut yang akan dibaca hanya saat memanggil dekorator sebagai argumen dan atribut tersebut akan menjadi hanya baca.

Penghargaan untuk jawaban Brice di Bagaimana cara mendapatkan nama kelas pemanggil di dalam fungsi kelas lain dengan python? untuk mendapatkan kelas dan metode pemanggil.

Michael
sumber
object.__setattr__(pfi, 'readonly', 'foobar')memecahkan solusi ini, tanpa mengedit kelas itu sendiri.
L3viathan
0

Perhatikan bahwa metode instance juga merupakan atribut (dari kelas) dan Anda dapat mengaturnya di kelas atau tingkat instance jika Anda benar-benar ingin menjadi seorang badass. Atau Anda dapat menyetel variabel kelas (yang juga merupakan atribut kelas), di mana properti hanya baca yang praktis tidak akan berfungsi dengan baik di luar kotak. Apa yang ingin saya katakan adalah bahwa masalah "atribut hanya baca" sebenarnya lebih umum daripada biasanya. Untungnya ada ekspektasi konvensional di tempat kerja yang begitu kuat untuk membutakan kita terhadap kasus-kasus lain ini (lagipula, hampir semuanya adalah atribut dalam python).

Berdasarkan ekspektasi ini, menurut saya pendekatan yang paling umum dan ringan adalah dengan mengadopsi konvensi bahwa atribut "publik" (tanpa garis bawah) hanya dapat dibaca kecuali jika didokumentasikan secara eksplisit sebagai dapat ditulisi. Ini mencakup ekspektasi biasa bahwa metode tidak akan ditambal dan variabel kelas yang menunjukkan default instance lebih baik, apalagi. Jika Anda merasa sangat paranoid tentang beberapa atribut khusus, gunakan deskriptor hanya-baca sebagai ukuran sumber daya terakhir.

memeplex
sumber
0

Meskipun saya menyukai dekorator kelas dari Oz123, Anda juga dapat melakukan hal berikut, yang menggunakan pembungkus kelas eksplisit dan __new__ dengan metode Pabrik kelas yang mengembalikan kelas dalam closure:

class B(object):
    def __new__(cls, val):
        return cls.factory(val)

@classmethod
def factory(cls, val):
    private = {'var': 'test'}

    class InnerB(object):
        def __init__(self):
            self.variable = val
            pass

        @property
        def var(self):
            return private['var']

    return InnerB()
Apollo Marquis
sumber
Anda harus menambahkan beberapa pengujian yang menunjukkan cara kerjanya dengan beberapa properti
Oz123
0

Itu solusi saya.

@property
def language(self):
    return self._language
@language.setter
def language(self, value):
    # WORKAROUND to get a "getter-only" behavior
    # set the value only if the attribute does not exist
    try:
        if self.language == value:
            pass
        print("WARNING: Cannot set attribute \'language\'.")
    except AttributeError:
        self._language = value
rusiano
sumber
0

seseorang menyebutkan menggunakan objek proxy, saya tidak melihat contohnya jadi saya akhirnya mencobanya, [buruk].

/! \ Silakan pilih definisi kelas dan konstruktor kelas jika memungkinkan

kode ini secara efektif menulis ulang class.__new__(konstruktor kelas) kecuali lebih buruk dalam segala hal. Selamatkan diri Anda dari rasa sakit dan jangan gunakan pola ini jika Anda bisa.

def attr_proxy(obj):
    """ Use dynamic class definition to bind obj and proxy_attrs.
        If you can extend the target class constructor that is 
        cleaner, but its not always trivial to do so.
    """
    proxy_attrs = dict()

    class MyObjAttrProxy():
        def __getattr__(self, name):
            if name in proxy_attrs:
                return proxy_attrs[name]  # overloaded

            return getattr(obj, name)  # proxy

        def __setattr__(self, name, value):
            """ note, self is not bound when overloading methods
            """
            proxy_attrs[name] = value

    return MyObjAttrProxy()


myobj = attr_proxy(Object())
setattr(myobj, 'foo_str', 'foo')

def func_bind_obj_as_self(func, self):
    def _method(*args, **kwargs):
        return func(self, *args, **kwargs)
    return _method

def mymethod(self, foo_ct):
    """ self is not bound because we aren't using object __new__
        you can write the __setattr__ method to bind a self 
        argument, or declare your functions dynamically to bind in 
        a static object reference.
    """
    return self.foo_str + foo_ct

setattr(myobj, 'foo', func_bind_obj_as_self(mymethod, myobj))
ThorSummoner
sumber
-2

Saya tahu saya membawa kembali utas ini dari kematian, tetapi saya sedang mencari cara membuat properti hanya baca dan setelah menemukan topik ini, saya tidak puas dengan solusi yang sudah dibagikan.

Jadi, kembali ke pertanyaan awal, jika Anda memulai dengan kode ini:

@property
def x(self):
    return self._x

Dan Anda ingin membuat X hanya-baca, Anda cukup menambahkan:

@x.setter
def x(self, value):
    raise Exception("Member readonly")

Kemudian, jika Anda menjalankan yang berikut ini:

print (x) # Will print whatever X value is
x = 3 # Will raise exception "Member readonly"
vincedjango
sumber
3
Tetapi jika Anda tidak membuat penyetel, mencoba menetapkan akan memunculkan kesalahan juga (An AttributeError('can't set attribute'))
Artyer