代码之家  ›  专栏  ›  技术社区  ›  Lokesh Agrawal

用python解构dict和objects

  •  2
  • Lokesh Agrawal  · 技术社区  · 7 年前

    在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
    
    0 回复  |  直到 7 年前
        1
  •  1
  •   Mulan    7 年前

    不要一开始就把争论压扁。当你写一个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
    
        2
  •  1
  •   Ajax1234    7 年前

    您可以实现 __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