代码之家  ›  专栏  ›  技术社区  ›  576i

Python:从基本数据类继承的数据类,如何将值从基本类升级到新类?

  •  1
  • 576i  · 技术社区  · 7 年前

    如何将值从基本数据类升级到继承它的值?

    from dataclasses import dataclass
    
    @dataclass
    class Person:
        name: str 
        smell: str = "good"    
    
    @dataclass
    class Friend(Person):
    
        # ... more fields
    
        def say_hi(self):        
            print(f'Hi {self.name}')
    
    friend = Friend(name='Alex')
    f1.say_hi()
    

    打印“嗨亚历克斯”

    random_stranger = Person(name = 'Bob', smell='OK')
    

    随机返回“陌生人”(姓名='Bob',气味='OK')”

    Friend(random_stranger)
    

    返回“Friend(name=Person(name='Bob',嗅觉='OK'),嗅觉='good'”

    我想得到“朋友(姓名='Bob',气味='OK')”作为结果。

    Friend(random_stranger.name, random_stranger.smell)
    

    或者我不能在继承自数据类的类上使用@dataclass decorator?

    1 回复  |  直到 7 年前
        1
  •  4
  •   Arne    6 年前

    你所要求的是 factory method pattern ,可以直接在python类中使用 @classmethod 关键字。

    import dataclasses
    
    @dataclasses.dataclass
    class Person:
        name: str
        smell: str = "good"
    
        @classmethod
        def from_instance(cls, instance):
            return cls(**dataclasses.asdict(instance))
    

    从这个基类继承的任何新数据类现在都可以创建彼此的实例 这样地:

    @dataclasses.dataclass
    class Friend(Person):
        def say_hi(self):        
            print(f'Hi {self.name}')
    
    random_stranger = Person(name = 'Bob', smell='OK')
    friend = Friend.from_instance(random_stranger)
    print(friend.say_hi())
    # "Hi Bob"
    

    [一]

        2
  •  2
  •   Bob Zimmermann    7 年前

    你可能不想 class 它本身是一个可变属性,而是使用枚举之类的东西来表示这样的状态。根据需要,您可以考虑以下几种模式之一:

    class RelationshipStatus(Enum):
        STRANGER = 0
        FRIEND = 1
        PARTNER = 2
    
    @dataclass
    class Person(metaclass=ABCMeta):
        full_name: str
        smell: str = "good"
        status: RelationshipStatus = RelationshipStatus.STRANGER
    
    @dataclass
    class GreetablePerson(Person):
        nickname: str = ""
    
        @property
        def greet_name(self):
            if self.status == RelationshipStatus.STRANGER:
                return self.full_name
            else:
                return self.nickname
    
        def say_hi(self):
            print(f"Hi {self.greet_name}")
    
    if __name__ == '__main__':
        random_stranger = GreetablePerson(full_name="Robert Thirstwilder",
                                          nickname="Bobby")
        random_stranger.status = RelationshipStatus.STRANGER
        random_stranger.say_hi()
        random_stranger.status = RelationshipStatus.FRIEND
        random_stranger.say_hi()
    

    您可能还希望以trait/mixin风格实现这一点。而不是创建 GreetablePerson Greetable ,也是抽象的,并使具体类同时继承这两个类。

    您也可以考虑使用优秀的、后端口的、更灵活的 attrs 包裹。这还将使您能够使用 evolve() 功能:

    friend = attr.evolve(random_stranger, status=RelationshipStatus.FRIEND)
    
        3
  •  0
  •   phispi    6 年前

    vars(stranger) 为您提供数据类实例的所有属性的dict stranger __init__() 数据类的方法接受关键字参数, twin_stranger = Person(**vars(stranger)) 使用值的副本创建新实例。如果您提供其他参数,如 stranger_got_friend = Friend(**vars(stranger), city='Rome') :

    from dataclasses import dataclass
    
    
    @dataclass
    class Person:
        name: str
        smell: str
    
    
    @dataclass
    class Friend(Person):
        city: str
    
        def say_hi(self):
            print(f'Hi {self.name}')
    
    
    friend = Friend(name='Alex', smell='good', city='Berlin')
    friend.say_hi()  # Hi Alex
    stranger = Person(name='Bob', smell='OK')
    stranger_got_friend = Friend(**vars(stranger), city='Rome')
    stranger_got_friend.say_hi()  # Hi Bob