En az beş altı yol vardır. Tercih edilen yol, kullanım durumunuzun ne olduğuna bağlıdır.
1. Seçenek: Bir asdict()yöntem eklemeniz yeterlidir .
Problem tanımına dayanarak, asdictdiğer cevapların önerdiği şeyleri yapmanın yolunu çok düşünürdüm . Bunun nedeni, nesnenizin gerçekten bir koleksiyon gibi görünmemesidir:
class Wharrgarbl(object):
...
def asdict(self):
return {'a': self.a, 'b': self.b, 'c': self.c}
Aşağıdaki diğer seçenekleri kullanmak, hangi nesne üyelerinin anahtar-değer çifti olarak yinelenip belirtilmeyeceği çok açık olmadığı sürece diğerleri için kafa karıştırıcı olabilir.
Seçenek 1a: Sınıfınızı 'typing.NamedTuple'(veya çoğunlukla eşdeğerinden 'collections.namedtuple') devralın ve sizin için sağlanan _asdictyöntemi kullanın .
from typing import NamedTuple
class Wharrgarbl(NamedTuple):
a: str
b: str
c: str
sum: int = 6
version: str = 'old'
Adlandırılmış bir demet kullanmak, sınıfınıza bir _asdictyöntem de dahil olmak üzere minimum çabayla çok sayıda işlevsellik eklemenin çok uygun bir yoludur . Bununla birlikte, bir sınırlama, yukarıda gösterildiği gibi, NT'nin tüm üyeleri içerecek olmasıdır _asdict.
Sözlüğünüze eklemek istemediğiniz üyeler varsa, _asdictsonucu değiştirmeniz gerekir :
from typing import NamedTuple
class Wharrgarbl(NamedTuple):
a: str
b: str
c: str
sum: int = 6
version: str = 'old'
def _asdict(self):
d = super()._asdict()
del d['sum']
del d['version']
return d
Diğer bir sınırlama, NT'nin salt okunur olmasıdır. Bu istenebilir veya istenmeyebilir.
2. Seçenek: Uygulama __iter__.
Bunun gibi, örneğin:
def __iter__(self):
yield 'a', self.a
yield 'b', self.b
yield 'c', self.c
Şimdi şunları yapabilirsiniz:
dict(my_object)
Bu işe dict()yarar çünkü (key, value)yapıcı bir sözlük oluşturmak için yinelenebilir çiftleri kabul eder . Bunu yapmadan önce, nesneyi bir dizi anahtar, değer çifti olarak bu şekilde yinelemenin dict- a oluşturmak için uygun olsa da - aslında başka bağlamlarda şaşırtıcı bir davranış olup olmayacağını kendinize sorun . Örneğin, kendinize şu soruyu sorun: "Davranışı ne olmalı list(my_object)...?"
Ek olarak, doğrudan öğe alma obj["a"]sözdizimini kullanarak değerlere erişmenin çalışmayacağını ve anahtar kelime bağımsız değişkeninin paketten çıkarılmasının çalışmayacağını unutmayın. Bunlar için haritalama protokolünü uygulamanız gerekir.
Seçenek 3: Uygulama haritalama protokolü . Bu, anahtarla erişim davranışına, dictkullanmadan __iter__a'ya çevirmeye izin verir ve ayrıca {**my_obj}tüm anahtarlar dizelerden ( dict(**my_obj)) ise paket açma davranışı ( ) ve anahtar kelime açma davranışı sağlar .
Eşleme protokolü, (en az) iki yöntemi birlikte sağlamanızı gerektirir: keys()ve __getitem__.
class MyKwargUnpackable:
def keys(self):
return list("abc")
def __getitem__(self, key):
return dict(zip("abc", "one two three".split()))[key]
Şimdi aşağıdaki gibi şeyler yapabilirsiniz:
>>> m=MyKwargUnpackable()
>>> m["a"]
'one'
>>> dict(m)
{'a': 'one', 'b': 'two', 'c': 'three'}
>>> dict(**m)
{'a': 'one', 'b': 'two', 'c': 'three'}
Yukarıda belirtildiği gibi, yeterince yeni bir python sürümü kullanıyorsanız, eşleme protokolü nesnenizi de bunun gibi bir sözlük anlayışına dönüştürebilirsiniz (ve bu durumda anahtarlarınızın dizge olması gerekmez):
>>> {**m}
{'a': 'one', 'b': 'two', 'c': 'three'}
Eşleme protokol Not önceliklidir__iter__ bir nesneyi döküm sırasında yöntemi dict(diğer bir deyişle, kwarg açma kullanmadan doğrudan dict(m)). Dolayısıyla, nesnenin bir yinelenebilir (örneğin list(m)) olarak kullanıldığında ve a dict( dict(m)) ' ya dönüştürüldüğünde farklı davranışlara sahip olmasına neden olmak mümkündür ve bazen uygundur .
Bu çeviride : Eğer haritalama protokolünü kullanmak CAN diye, sen anlamina gelmez GEREKEN bunu . Nesnenizin bir dizi anahtar-değer çifti olarak veya anahtar kelime argümanları ve değerleri olarak aktarılmasıgerçekten mantıklı mı? Ona anahtarla erişmek - tıpkı bir sözlük gibi - gerçekten mantıklı mı?
Bu soruların cevabı evet ise , bir sonraki seçeneği düşünmek muhtemelen iyi bir fikirdir.
4. Seçenek: kullanarak içine bak 'collections.abc'modülü .
Sınıfınızı diğer kullanıcılardan miras almak 'collections.abc.Mappingveya 'collections.abc.MutableMappingdiğer kullanıcılara, tüm amaç ve amaçlar için, sınıfınızın bir eşleme * olduğunu ve bu şekilde davranmasının beklenebileceğini gösterir.
Hala dictistediğiniz gibi nesnenizi atabilirsiniz , ancak bunu yapmak için muhtemelen çok az nedeniniz olacaktır. Ördek yazımından dolayı, eşleme nesnenizi a'ya çevirme zahmeti dict, çoğu zaman gereksiz ek bir adım olur.
Bu cevap da yardımcı olabilir.
Aşağıdaki yorumlarda belirtildiği gibi: bunu abc yöntemiyle yapmanın esasen nesne sınıfınızı benzer bir sınıfa dönüştürdüğünden bahsetmeye değer dict( MutableMappingsalt okunur Mappingtemel sınıfı değil, kullandığınızı varsayarak ). Yapabileceğiniz dicther şeyi kendi sınıf nesnenizle yapabilirsiniz. Bu arzu edilebilir veya istenmeyebilir.
Ayrıca numbersmodüldeki sayısal abc'lere bakmayı da düşünün :
https://docs.python.org/3/library/numbers.html
Aynı zamanda nesnenizi bir nesneye intyayınladığınız için, esasen sınıfınızı tam teşekküllü bir hale getirmek daha mantıklı olabilir, intböylece döküm gerekli değildir.
Seçenek 5: kullanarak içine Bak dataclassesmodülü uygun bir içermektedir (Python 3.7 için), asdict()yardımcı bir yöntem.
from dataclasses import dataclass, asdict, field, InitVar
@dataclass
class Wharrgarbl(object):
a: int
b: int
c: int
sum: InitVar[int]
version: InitVar[str] = "old"
def __post_init__(self, sum, version):
self.sum = 6
self.version = str(version)
Şimdi bunu yapabilirsiniz:
>>> asdict(Wharrgarbl(1,2,3,4,"X"))
{'a': 1, 'b': 2, 'c': 3}
Seçenek 6: Kullanım typing.TypedDictolmuştur, piton 3.8 katma .
NOT: seçenek 6, muhtemelen OP'nin veya bu sorunun başlığına göre diğer okuyucuların aradığı şey DEĞİLDİR . Aşağıdaki ek yorumlara bakın.
class Wharrgarbl(TypedDict):
a: str
b: str
c: str
Bu seçeneği kullanarak, ortaya çıkan nesne birdict (vurgu: a değildirWharrgarbl ). Onu bir dikteye "çevirmek" için hiçbir neden yoktur (bir kopya yapmıyorsanız).
Ve nesne a olduğu içindict , başlatma imzası ile aynıdır dictve bu nedenle yalnızca anahtar kelime argümanlarını veya başka bir sözlüğü kabul eder.
>>> w = Wharrgarbl(a=1,b=2,b=3)
>>> w
{'a': 1, 'b': 2, 'c': 3}
>>> type(w)
<class 'dict'>
Vurgulanan : Yukarıdaki "sınıf" Wharrgarblaslında yeni bir sınıf değil. dictTip denetleyicisi için farklı türlerde alanlara sahip yazılı nesneler oluşturmak için basit bir sözdizimsel şekerdir .
Bu nedenle, bu seçenek, kodunuzun okuyucularına (ve ayrıca mypy gibi bir tür denetleyicisine) böyle bir dictnesnenin belirli değer türlerine sahip belirli anahtarlara sahip olmasının beklendiğini bildirmek için oldukça uygun olabilir .
Ancak bu, örneğin deneyebileceğiniz halde başka yöntemler ekleyemeyeceğiniz anlamına gelir:
class MyDict(TypedDict):
def my_fancy_method(self):
return "world changing result"
... ama işe yaramayacak:
>>> MyDict().my_fancy_method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'my_fancy_method'
* "Haritalama", dictbenzeri ördek türünün standart "adı" haline geldi