在Javascript中,我可以使用destructuring从一个衬里的javascript对象中提取所需的属性。例如:
currentUser = {
"id": 24,
"name": "John Doe",
"website": "http://mywebsite.com",
"description": "I am an actor",
"email": "example@example.com",
"gender": "M",
"phone_number": "+12345678",
"username": "johndoe",
"birth_date": "1991-02-23",
"followers": 46263,
"following": 345,
"like": 204,
"comments": 9
}
let { id, username } = this.currentUser;
console.log(id) // 24
console.log(username) //johndoe
对于Python字典和Python对象,我们在Python中是否有类似的东西? python对象的Python处理方式示例:
class User:
def __init__(self, id, name, website, description, email, gender, phone_number, username):
self.id = id
self.name = name
self.website = website
self.description = description
self.email = email
self.gender = gender
self.phone_number = phone_number
self.username = username
current_user = User(24, "Jon Doe", "http://mywebsite.com", "I am an actor", "example@example.com", "M", "+12345678", "johndoe")
# This is a pain
id = current_user.id
email = current_user.email
gender = current_user.gender
username = current_user.username
print(id, email, gender, username)
写那4行(如上面的示例中提到的)而不是写一行(如下面提到的)以从对象中获取我需要的值是一个真正的痛点。
(id, email, gender, username) = current_user
答案 0 :(得分:6)
您可以按以下方式使用标准库中的operator
模块:
from operator import attrgetter
id, email, gender, username = attrgetter('id', 'email', 'gender', 'username')(current_user)
print(id, email, gender, username)
如果您的示例中有类似的格言
currentUser = {
"id": 24,
"name": "John Doe",
"website": "http://mywebsite.com",
"description": "I am an actor",
"email": "example@example.com",
"gender": "M",
"phone_number": "+12345678",
"username": "johndoe",
"birth_date": "1991-02-23",
"followers": 46263,
"following": 345,
"like": 204,
"comments": 9
}
只需使用itemgetter
而不是attrgetter
:
from operator import itemgetter
id, email, gender, username = itemgetter('id', 'email', 'gender', 'username')(currentUser)
print(id, email, gender, username)
答案 1 :(得分:2)
您可以使用.values()
方法解压缩来破坏python字典并提取属性:
currentUser = {
"id": 24,
"name": "John Doe",
"website": "http://mywebsite.com",
"description": "I am an actor",
"email": "example@example.com",
"gender": "M",
"phone_number": "+12345678",
"username": "johndoe",
"birth_date": "1991-02-23",
"followers": 46263,
"following": 345,
"like": 204,
"comments": 9
}
id, _, _, _, _, _, _, username, *other = currentUser.values()
print('distructuring:', { 'id': id, 'username': username })
答案 2 :(得分:1)
您可以实现__iter__
方法来启用拆包:
class User:
def __init__(self, **data):
self.__dict__ = data
def __iter__(self):
yield from [getattr(self, i) for i in ('id', 'email', 'gender', 'username')]
current_user = User(**currentUser)
id, email, gender, username = current_user
print([id, email, gender, username])
输出:
[24, 'example@example.com', 'M', 'johndoe']
编辑:Python2解决方案:
class User:
def __init__(self, **data):
self.__dict__ = data
def __iter__(self):
for i in ('id', 'email', 'gender', 'username'):
yield getattr(self, i)
编辑2:
获取选择属性:
class User:
def __init__(self, **data):
self.__dict__ = data
def __getattr__(self, _vals):
yield from [getattr(self, i) for i in _vals.split('_')]
current_user = User(**currentUser)
id, email, gender, username = current_user.id_email_gender_username
id, gender = current_user.id_gender
答案 3 :(得分:1)
首先不要弄平参数。当您像使用User
一样编写8进制函数时,必然会出错,例如以错误的顺序传递参数。
以下哪个会产生您想要的用户?
User(24, "Jon Doe", "http://mywebsite.com", "I am an actor", "example@example.com", "M", "+12345678", "johndoe")
User(24, "Jon Doe", "http://mywebsite.com", "I am an actor", "example@example.com", "+12345678", "M", "johndoe")
不可能知道!如果您的函数采用描述符,则不会出现此问题-
class User:
def __init__ (self, desc = {}):
self.desc = desc # whitelist items, if necessary
def __str__ (self):
# invent our own "destructuring" syntax
[ name, age, gender ] = \
destructure(self.desc, 'name', 'age', 'gender')
return f"{name} ({gender}) is {age} years old"
# create users with a "descriptor"
u = User({ 'age': 2, 'gender': 'M' })
v = User({ 'gender': 'F', 'age': 3 })
x = User({ 'gender': 'F', 'name': 'Alice', 'age': 4 })
print(u) # None (M) is 2 years old
print(v) # None (F) is 3 years old
print(x) # Alice (F) is 4 years old
我们可以将自己的destructure
定义为-
def destructure (d, *keys):
return [ d[k] if k in d else None for k in keys ]
这仍然可能导致长链,但是顺序取决于调用者,因此它并不像原始问题中的8进制函数那样脆弱-
[ name, age, gender ] = \
destructure(self.desc, 'name', 'age', 'gender')
# works the same as
[ gender, name, age ] = \
destructure(self.desc, 'gender', 'name', 'age')
另一种选择是使用关键字参数-
class User:
def __init__ (self, **desc):
self.desc = desc # whitelist items, if necessary
def __str__ (self):
[ name, age, gender ] = \
destructure(self.desc, 'name', 'age', 'gender')
return f"{name} ({gender}) is {age} years old"
# create users with keyword arguments
u = User(age = 2, gender = 'M')
v = User(gender = 'F', age = 3)
x = User(gender = 'F', name = 'Alice', age = 4)
print(u) # None (M) is 2 years old
print(v) # None (F) is 3 years old
print(x) # Alice (F) is 4 years old
答案 4 :(得分:1)
在其他答案的基础上,我建议也使用Python的dataclasses
并使用__getitem__
来获取特定字段:
from dataclasses import astuple, dataclass
@dataclass
class User:
id: int
name: str
website: str
description: str
email: str
gender: str
phone_number: str
username: str
def __iter__(self):
return iter(astuple(self))
def __getitem__(self, keys):
return iter(getattr(self, k) for k in keys)
current_user = User(id=24, name="Jon Doe", website="http://mywebsite.com", description="I am an actor", email="example@example.com", gender="M", phone_number="+12345678", username="johndoe")
# Access fields sequentially:
id, _, email, *_ = current_user
# Access fields out of order:
id, email, gender, username = current_user["id", "email", "gender", "username"]