수업이나 사전을 사용해야 합니까?
필드만 포함하고 메서드는 포함하지 않는 클래스가 있습니다. 다음과 같습니다.
class Request(object):
def __init__(self, environ):
self.environ = environ
self.request_method = environ.get('REQUEST_METHOD', None)
self.url_scheme = environ.get('wsgi.url_scheme', None)
self.request_uri = wsgiref.util.request_uri(environ)
self.path = environ.get('PATH_INFO', None)
# ...
이것은 쉽게 받아쓰기로 번역될 수 있습니다.은 추후 더 이 있고다를 하면 더 수 .__slots__
를 사용하는 그러면 대신 받아쓰기를 사용하는 것에 이점이 있을까요?수업보다 받아쓰기가 더 빠를까요?그리고 슬롯이 있는 수업보다 더 빠릅니까?
클래스의 추가 메커니즘이 필요하지 않은 경우 사전을 사용합니다.다음과 같은 하이브리드 접근 방식을 사용할 수도 있습니다.
>>> from collections import namedtuple
>>> request = namedtuple("Request", "environ request_method url_scheme")
>>> request
<class '__main__.Request'>
>>> request.environ = "foo"
>>> request.environ
'foo'
사전이 더 빠르지 않았다면 놀랄 일이지만 여기서의 성능 차이는 미미할 것입니다.
왜 이것을 사전으로 만드십니까?장점이 뭐죠?나중에 코드를 추가하려면 어떻게 됩니까?e은 어디에 ?__init__
고?
클래스는 관련 데이터(일반적으로 코드)를 번들링하기 위한 것입니다.
사전은 키-값 관계를 저장하기 위한 것으로, 일반적으로 키는 모두 동일한 유형이며 모든 값도 하나의 유형입니다.키/속성 이름이 모두 알려지지 않은 상태에서 데이터를 번들로 제공하는 데 유용할 수도 있지만, 설계에 문제가 있음을 나타내는 경우가 많습니다.
수업은 빼놓지 마세요.
python의 수업은 아래에 지시문이 있습니다.당신은 클래스 행동에 오버헤드가 있지만 프로파일러가 없으면 그것을 알아차릴 수 없을 것입니다.이 경우 수업의 혜택을 받게 되는 이유는 다음과 같습니다.
- 당신의 모든 논리는 하나의 함수 안에서 살아갑니다.
- 업데이트가 쉽고 캡슐화 상태를 유지합니다.
- 나중에 변경할 경우 인터페이스를 쉽게 동일하게 유지할 수 있습니다.
각각의 용법이 너무 주관적이라 그런 부분에 대해서는 제가 이해하기 어렵다고 생각하기 때문에 그냥 숫자에 충실하겠습니다.
dict, new_style 클래스 및 슬롯이 있는 new_style 클래스에서 변수를 생성하고 변경하는 데 걸리는 시간을 비교했습니다.
테스트할 때 사용한 코드는 여기 있습니다(좀 지저분하지만 작동은 됩니다).
import timeit
class Foo(object):
def __init__(self):
self.foo1 = 'test'
self.foo2 = 'test'
self.foo3 = 'test'
def create_dict():
foo_dict = {}
foo_dict['foo1'] = 'test'
foo_dict['foo2'] = 'test'
foo_dict['foo3'] = 'test'
return foo_dict
class Bar(object):
__slots__ = ['foo1', 'foo2', 'foo3']
def __init__(self):
self.foo1 = 'test'
self.foo2 = 'test'
self.foo3 = 'test'
tmit = timeit.timeit
print 'Creating...\n'
print 'Dict: ' + str(tmit('create_dict()', 'from __main__ import create_dict'))
print 'Class: ' + str(tmit('Foo()', 'from __main__ import Foo'))
print 'Class with slots: ' + str(tmit('Bar()', 'from __main__ import Bar'))
print '\nChanging a variable...\n'
print 'Dict: ' + str((tmit('create_dict()[\'foo3\'] = "Changed"', 'from __main__ import create_dict') - tmit('create_dict()', 'from __main__ import create_dict')))
print 'Class: ' + str((tmit('Foo().foo3 = "Changed"', 'from __main__ import Foo') - tmit('Foo()', 'from __main__ import Foo')))
print 'Class with slots: ' + str((tmit('Bar().foo3 = "Changed"', 'from __main__ import Bar') - tmit('Bar()', 'from __main__ import Bar')))
여기 출력물이 있어요
만드는 중...
Dict: 0.817466186345
Class: 1.60829183597
Class_with_slots: 1.28776730003
변수 변경 중...
Dict: 0.0735140918748
Class: 0.111714198313
Class_with_slots: 0.10618612142
따라서 변수를 저장하는 데만 속도가 필요하고 많은 계산을 수행할 필요가 없다면 dict를 사용하는 것이 좋습니다(항상 방법처럼 보이는 함수를 만들 수 있음).하지만 정말 수업이 필요하다면 항상 __slot__을 사용하는 것을 기억하세요.
참고:
저는 new_style 클래스와 old_style 클래스로 'Class'를 테스트했습니다.old_style 클래스는 생성 속도는 더 빠르지만 수정 속도는 더 느리다는 것이 밝혀졌습니다(엄청난 루프에서 많은 클래스를 생성하는 경우에는 그다지 빠르지 않지만 중요합니다(팁: 잘못된 작업을 수행하고 있습니다.
또한 제 것은 오래되고 느리기 때문에 컴퓨터에서 변수를 생성하고 변경하는 시간이 다를 수 있습니다.'진짜' 결과를 보기 위해 직접 테스트해 보시기 바랍니다.
편집:
나는 나중에 이름이 붙은 튜플을 테스트했습니다. 수정할 수는 없지만 10000 샘플을 만드는 데 1.4초가 걸렸기 때문에 사전이 가장 빠릅니다.
키와 값을 포함하고 dict를 생성할 때 dict를 포함하는 변수 대신 dict를 반환하도록 dict 함수를 변경하면 0.8초가 아닌 0.65가 됩니다.
class Foo(dict):
pass
생성하는 것은 슬롯이 있는 클래스와 같으며 변수를 변경하는 것이 가장 느리므로 이러한 클래스를 사용하지 마십시오.dict(속도) 또는 객체에서 파생된 클래스('syntax 캔디')를 구합니다.
@adw에 동의합니다.저는 절대 사전으로 "객체"(OO의 의미로).사전에서 이름/값 쌍을 집계합니다.클래스는 개체를 나타냅니다.사물이 사전으로 표현되는 코드를 본 적이 있는데 실제 사물의 모양이 무엇인지는 불분명합니다.특정 이름/값이 없으면 어떻게 됩니까?고객이 어떤 것도 넣을 수 없도록 제한하는 것.아니면 뭐든 꺼내보려는 거지물건의 모양은 항상 명확하게 정의되어야 합니다.
파이썬을 사용할 때는 언어를 사용하면 저자가 자신의 발을 쏠 수 있는 여러 가지 방법이 있기 때문에 훈련을 통해 구축하는 것이 중요합니다.
요청사항에 관련된 모든 종류의 정보이므로 수업을 추천합니다.사전을 사용한다면 저장된 데이터가 훨씬 더 유사할 것입니다.제가 스스로 따르는 가이드라인은 키->값 쌍 전체를 루프로 연결하여 무엇인가를 수행하고 싶다면 사전을 사용한다는 것입니다.그렇지 않으면 데이터가 기본 키-> 값 매핑보다 훨씬 더 많은 구조를 가지고 있으므로 클래스가 더 나은 대안이 될 수 있습니다.
그러므로 수업을 계속하세요.
만약 당신이 성취하고 싶은 모든 것이 구문 캔디라면, 다음과 같이.obj.bla = 5
대신에obj['bla'] = 5
, 특히 당신이 그것을 많이 반복해야 한다면 martineaus의 제안처럼 평범한 컨테이너 클래스를 사용하는 것이 좋을 것입니다.그럼에도 불구하고, 그곳의 코드는 상당히 비대하고 불필요하게 느립니다.다음과 같이 간단하게 유지할 수 있습니다.
class AttrDict(dict):
""" Syntax candy """
__getattr__ = dict.__getitem__
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__
다음으로 전환해야 하는 또 다른 이유namedtuple
과의 수업__slots__
메모리 사용일 수도 있습니다.딕트는 목록 유형보다 훨씬 더 많은 메모리를 필요로 하기 때문에 이 문제를 생각해 볼 지점이 될 수 있습니다.
어쨌든 구체적인 경우에는 현재 구현에서 전환할 동기가 없는 것 같습니다.수백만 개의 개체를 유지하지 않는 것 같습니다. 따라서 목록에서 파생된 유형이 필요하지 않습니다.그리고 그것은 실제로 어떤 기능적 논리를 포함하고 있습니다.__init__
, 그래서 당신도 당신과 함께 하지 말아야 합니다.AttrDict
.
여러분의 케이크를 먹고 그것을 먹는 것도 가능할지도 모릅니다.즉 클래스와 사전 인스턴스의 기능을 모두 제공하는 것을 만들 수 있습니다.ActiveState의 D ɪᴄᴛɪᴏɴᴀʀʏ ᴡɪᴛʜ ᴀᴛᴛʀɪʙᴜᴛᴇ-s ᴛʏʟᴇ ᴀᴄᴄᴇs 레시피와 그 방법에 대한 의견을 참조하십시오.
하위 클래스가 아닌 일반 클래스를 사용하기로 결정한 경우 T ʜᴇs ɪᴍᴘʟᴇ ʙᴜᴛ ʜᴀɴᴅʏ "ᴄᴏʟʟᴇᴄᴛᴏʀ ᴏғ ᴀ ʙᴜɴᴄʜ ᴏғ ɴᴀᴍᴇᴅs ᴛᴜғғ" ᴄʟᴀs 레시피(알렉스 마르텔리 작)가 매우 유연하고 사용자가 수행하는 것처럼 보이는 작업(즉, 상대적으로 간단한 정보 집계기 작성)에 유용하다는 것을 알게 되었습니다.클래스이므로 메서드를 추가하면 쉽게 기능을 확장할 수 있습니다.
마지막으로, 클래스 구성원의 이름은 합법적인 Python 식별자여야 하지만 사전 키는 그렇지 않기 때문에 키는 해시 가능한 모든 것(심지어 문자열이 아닌 것)이 될 수 있기 때문에 사전은 이 점에서 더 큰 자유를 제공합니다.
갱신하다
클래스(이 없는 클래스)__dict__
)라는 이름의 서브클래스(하나가 있음)가 Python 3.3 모듈에 추가되었으며, 또 다른 대안입니다.
만약 필드 집합을 의미하는 데이터가 미래에 변경되거나 확장되지 않는다면 나는 그러한 데이터를 표현하기 위한 클래스를 선택할 것입니다. 왜죠?
- 좀 더 깨끗하고 읽을 수 있습니다.
- 일반적으로 한 번만 발생하는 것보다 훨씬 중요한 사용법이 더 빠릅니다.
더 빠른 것은 클래스 객체가 아닌 필드에 대해 컨테이너로 클래스를 사용하는 것처럼 보입니다.
확장 alexpinho98 예제:
import timeit
class Foo(object):
def __init__(self):
self.foo1 = 'test'
self.foo2 = 'test'
self.foo3 = 'test'
class FooClass:
foo1 = 'test'
foo2 = 'test'
foo3 = 'test'
def create_dict():
foo_dict = {}
foo_dict['foo1'] = 'test'
foo_dict['foo2'] = 'test'
foo_dict['foo3'] = 'test'
return foo_dict
class Bar(object):
__slots__ = ['foo1', 'foo2', 'foo3']
def __init__(self):
self.foo1 = 'test'
self.foo2 = 'test'
self.foo3 = 'test'
tmit = timeit.timeit
dict = create_dict()
def testDict():
a = dict['foo1']
b = dict['foo2']
c = dict['foo3']
dict_obj = Foo()
def testObjClass():
a = dict_obj.foo1
b = dict_obj.foo2
c = dict_obj.foo3
def testClass():
a = FooClass.foo1
b = FooClass.foo2
c = FooClass.foo3
print ('Creating...\n')
print ('Dict: ' + str(tmit('create_dict()', 'from __main__ import create_dict')))
print ('Class: ' + str(tmit('Foo()', 'from __main__ import Foo')))
print ('Class with slots: ' + str(tmit('Bar()', 'from __main__ import Bar')))
print ('=== Testing usage 1 ===')
print ('Using dict : ' + str(tmit('testDict()', 'from __main__ import testDict')))
print ('Using object: ' + str(tmit('testObjClass()', 'from __main__ import testObjClass')))
print ('Using class : ' + str(tmit('FooClass()', 'from __main__ import FooClass')))
결과는 다음과 같습니다.
Creating...
Dict: 0.185864600000059
Class: 0.30627199999980803
Class with slots: 0.2572166999998444
=== Testing usage 1 ===
Using dict : 0.16507520000050135
Using object: 0.1266871000007086
Using class : 0.06327920000148879
class ClassWithSlotBase:
__slots__ = ('a', 'b',)
def __init__(self):
self.a: str = "test"
self.b: float = 0.0
def test_type_hint(_b: float) -> None:
print(_b)
class_tmp = ClassWithSlotBase()
test_type_hint(class_tmp.a)
수업을 추천합니다.수업을 이용하면 그림과 같이 타자 힌트를 얻을 수 있습니다.그리고 클래스가 함수의 인수일 때 자동완성을 지원합니다.
언급URL : https://stackoverflow.com/questions/4045161/should-i-use-a-class-or-dictionary
'programing' 카테고리의 다른 글
점을 사용하여 팬더 데이터 프레임의 두 열을 표시하는 방법 (0) | 2023.10.10 |
---|---|
Angular 간의 코드 재사용 방법JS 클라이언트 및 Node.js 서버 (0) | 2023.10.10 |
'올바른' 부호 없는 정수 비교 (0) | 2023.10.10 |
How to export a data base from DataGrip at one SQL file? (0) | 2023.10.10 |
스프링 시큐리티 원형 콩 의존성 (0) | 2023.10.10 |