Py学习  »  Python

用python解构dict和objects

Lokesh Agrawal • 4 年前 • 1268 次点击  

在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 dict和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
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/40848
 
1268 次点击  
文章 [ 2 ]  |  最新文章 4 年前
Ajax1234
Reply   •   1 楼
Ajax1234    5 年前

您可以实现 __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
user633183
Reply   •   2 楼
user633183    5 年前

不要一开始就把争论压扁。当你写一个8元函数的时候 User ,你一定会犯错误,比如按错误的顺序传递论点。

以下哪项将生成您想要的用户?

  1. User(24, "Jon Doe", "http://mywebsite.com", "I am an actor", "example@example.com", "M", "+12345678", "johndoe")
  2. 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 AS -

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