속성을 비공개로 하고 읽기 전용 속성을 만들어야 하는 시기는 언제입니까?
속성이 언제 비공개가 되어야 하는지와 사용해야 하는지 여부를 알 수 없습니다.property
.
에 이 한다는 을 는 와 을 한다는 는 에 property
데코레이터는 괜찮습니다.
그러나 속성이 있으면 클래스 외부에서 설정할 수 없고 읽기 전용 속성(읽기 전용 속성)이 있어야 합니다., 이인야지면인고께과런는다을이런다을td과는see,h이eesi,,eneyd이고면인self._x
를 사용하지 수 ? 만약 그렇다면 게터를 사용하지 않고 어떻게 읽을 수 있습니까?내가 지금 아는 방법은 글을 쓰는 것 뿐입니다.
@property
def x(self):
return self._x
이렇게 하면 속성을 읽을 수 있습니다.obj.x
그러나 설정할 수 없습니다.obj.x = 1
그래서 괜찮아요.
하지만 설정해서는 안 되는 개체를 설정하는 것에 정말 신경을 써야 할까요?그냥 놔둬야 할 것 같아요.하지만 읽기 때문에 밑줄을 사용할 수 없습니다.obj._x
사용자에게 이상하므로 를 사용해야 합니다.obj.x
사용자는 이 속성을 설정해서는 안 된다는 것을 알지 못합니다.
당신의 의견과 관행은 어떻습니까?
단 2센트, Silas Ray는 올바른 방향으로 가고 있지만, 사례를 추가하고 싶은 마음이 들었습니다. ;-
파이썬은 안전하지 않은 유형의 언어이므로 코드를 합리적인 사람처럼 사용하려면 항상 코드 사용자를 신뢰해야 합니다.
비공용 메서드 및 인스턴스 변수에 대해서만 선행 밑줄 하나를 사용합니다.
전용' '읽기 전용' 속성을 하면 됩니다.@property
장식, 당신은 그로부터 물려받아야 할 것입니다.object
새로운 스타일의 수업을 사용하기 위해 그렇게 할 때.
예:
>>> 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
일반적으로 파이썬 프로그램은 모든 사용자들이 동의하는 성인이라는 가정하에 작성되어야 하며, 따라서 사물을 올바르게 사용할 책임이 있습니다.그러나 속성을 설정할 수 있는 것이 의미가 없는 드문 경우(예: 파생된 값 또는 일부 정적 데이터 원본에서 읽은 값)에는 getter-only 속성이 일반적으로 선호되는 패턴입니다.
여기에는 다음과 같은 가정을 피할 수 있는 방법이 있습니다.
모든 사용자는 동의하는 성인이므로 자신이 사물을 올바르게 사용할 책임이 있습니다.
아래의 나의 업데이트를 봐주시기 바랍니다.
을 해서.@property
, 다음과 같이 매우 장황합니다.
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
사용.
밑줄 없음: 공개 변수입니다.
한 가지 밑줄: 그것은 보호 변수입니다.
두 가지 밑줄: 개인 변수입니다.
마지막 것을 제외하고는 관례입니다.그래도 열심히 노력한다면 이중 밑줄로 변수에 접근할 수 있습니다.
따라서 우리는 어떻게 해야 할까요?Python에서 속성 읽기만 하는 것을 포기합니까?
보라구! !read_only_properties
구조를 위한 장식가!
@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
질문:
은 어디에
read_only_properties
어디서 온 거지?
요청해주셔서 감사합니다. 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
갱신하다
이 답변이 이렇게 주목받을 줄은 몰랐어요.놀랍게도 그렇습니다.이것이 저로 하여금 당신이 사용할 수 있는 패키지를 만들도록 하였습니다.
$ pip install read-only-properties
당신의 파이썬 셸에서:
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
여기 읽기 전용 속성에 대한 약간 다른 접근법이 있습니다. 아마도 초기화해야 하기 때문에 쓰기 한 번 속성이라고 불러야 할 것 같습니다. 그렇지 않습니까?객체의 사전에 직접 접속하여 속성을 수정할 수 있을지 걱정하는 편집증적인 사람들을 위해, 저는 "극단적인" 이름 망글링을 소개합니다.
from uuid import uuid4
class ReadOnlyProperty:
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 = ReadOnlyProperty('x')
y = ReadOnlyProperty('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)
첫 번째 솔루션은 읽기 전용 속성을 삭제한 다음 설정할 수 있고 읽기 전용 속성을 차단하지 않기 때문에 읽기 전용 속성을 생성하기 위한 이전의 두 가지 답변에 불만이 있습니다.__dict__
은 테스트를할 수 . 즉, 두과 동일한 하는 것입니다. 두 번째 솔루션은 테스트를 통해 해결할 수 있습니다. 즉, 두 개로 설정한 값과 동일한 값을 찾아 최종적으로 변경하는 것입니다.
자, 코드는.
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()
앱 개발과 같은 다른 목적의 코드가 아닌, 그들의 프로그램을 향상시키기 위해 사용할 코드로서 다른 사람들에게 배포되고 있는 라이브러리 코드, 코드를 작성할 때를 제외하고는 읽기 전용 속성을 만드는 것은 의미가 없습니다.__dict__
문제는 해결됩니다, 왜냐하면__dict__
이제는 불변의types.MappingProxyType
은 은 를 할 을 통해 변경할 수 없습니다.__dict__
삭제. __dict__
역시 차단되었습니다.읽기 전용 속성을 변경할 수 있는 유일한 방법은 클래스 자체의 메서드를 변경하는 것입니다.
저는 제 솔루션이 이전 두 가지보다 더 낫다고 생각하지만, 개선될 수 있을 것입니다.이 코드의 약점은 다음과 같습니다.
읽기 전용 특성을 설정하거나 삭제하는 하위 클래스의 메서드에 추가할 수 없습니다.하위 클래스에 정의된 메서드는 superclass의 메서드 버전을 호출해도 읽기 전용 속성에 액세스할 수 없습니다.
클래스의 읽기 전용 메서드를 변경하여 읽기 전용 제한을 제거할 수 있습니다.
그러나 읽기 전용 특성을 설정하거나 삭제하려면 클래스를 편집하지 않으면 안 됩니다.이것은 명명 규칙에 의존하지 않습니다. 이것은 Python이 명명 규칙과 일치하지 않기 때문에 좋습니다.이렇게 하면 클래스 자체를 편집하지 않고도 숨겨진 허점으로 변경할 수 없는 읽기 전용 특성을 만들 수 있습니다.데코레이터를 호출할 때만 읽을 속성을 인수로 나열하면 읽기 전용이 됩니다.
전화를 건 사람들의 수업과 방법에 대한 Brice의 답변에 감사드립니다.
그게 제 해결책입니다.
@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
인스턴스 메서드는 클래스의 속성이기도 하며, 클래스 또는 인스턴스 수준에서 설정할 수 있습니다.또는 클래스 변수(클래스의 속성이기도 함)를 설정할 수 있습니다. 이 경우 핸디형 읽기 전용 속성이 상자에서 깔끔하게 작동하지 않습니다.제가 말하고 싶은 것은 "읽기 전용 속성" 문제가 사실은 일반적으로 인식되는 것보다 더 일반적이라는 것입니다.다행히도 직장에는 이런 다른 사례들을 보지 못할 정도로 강한 관습적인 기대가 있습니다. (결국, 거의 모든 것이 파이썬의 일종의 속성입니다.
이러한 기대를 바탕으로 작성 가능한 것으로 명시적으로 문서화된 경우를 제외하고는 "공개"(주요 언더스코어 없음) 속성을 읽기만 한다는 관례를 채택하는 것이 가장 일반적이고 가벼운 접근 방식이라고 생각합니다.이는 메서드가 패치되지 않을 것이며 인스턴스 기본값을 나타내는 클래스 변수가 더 낫다는 일반적인 예상을 포함합니다.어떤 특별한 속성에 대해 정말로 편집증적이라고 느끼면 마지막 리소스 척도로 읽기 전용 설명자를 사용합니다.
저는 Oz123의 클래스 데코레이터를 좋아하지만, 명시적인 클래스 래퍼와 __new_ 클래스 팩토리 메서드를 사용하여 폐쇄 내에 클래스를 반환하는 다음 작업도 할 수 있습니다.
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()
누군가가 프록시 객체를 사용한다고 했는데, 그 예를 보지 못해서 결국 시도해 보았습니다. [부실하게].
/!\ 가능하면 클래스 정의 및 클래스 생성자를 선호하십시오.
이 코드는 효과적으로 다시 작성됩니다.class.__new__
(클래스 컨스트럭터) 모든 면에서 더 나쁜 것을 제외하고는 말입니다.고통을 덜고 가능하다면 이 패턴을 사용하지 마세요.
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))
이 스레드를 죽은 사람들로부터 다시 가져오는 것은 알지만, 속성을 읽기만 하는 방법을 찾고 있었는데 이 주제를 찾은 후에 이미 공유된 솔루션에 만족하지 못했습니다.
자, 처음 질문으로 돌아가서 이 코드로 시작하면 다음과 같습니다.
@property
def x(self):
return self._x
X를 읽기 전용으로 만들고 싶다면 다음을 추가하면 됩니다.
@x.setter
def x(self, value):
raise Exception("Member readonly")
그런 다음 다음을 실행하면 다음과 같습니다.
print (x) # Will print whatever X value is
x = 3 # Will raise exception "Member readonly"
언급URL : https://stackoverflow.com/questions/14594120/when-should-an-attribute-be-private-and-made-a-read-only-property
'IT' 카테고리의 다른 글
MariaDB 기존 열의 새 열 데이터에 삽입 (0) | 2023.09.10 |
---|---|
Android에서 FFmpeg (0) | 2023.09.10 |
sass --자동 미니와 함께 보기? (0) | 2023.09.10 |
숫자가 어떤 종류의 int인지(core 또는 numpy, signed 여부) 어떻게 판단합니까? (0) | 2023.09.10 |
스위치 문에서 "defau4t"가 합법적인 이유는 무엇입니까? (0) | 2023.09.10 |