การประกาศคลาส / อินเทอร์เฟซ Python โดยใช้รายการชื่อแอตทริบิวต์ [ซ้ำกัน]

ใน Python มีวิธีใดบ้างที่จะประกาศอินเทอร์เฟซที่เหมือนคลาสพร้อมรายการแอตทริบิวต์นอกเหนือจากชื่อ tuple? ฉันต้องการสร้างมิกซ์อินจากรายการชื่อแอตทริบิวต์ ความพยายามที่ดีที่สุดของฉันจนถึงตอนนี้คือ:

# module1.py (user facing)
CUSTOM_FIELDS = ['eye_color', 'shoe_size']


# module2.py (inside my framework)
from collections import namedtuple
from typing import Union


class BasePerson:
  name: Any
  age: Any

CustomMixin = namedtuple('CustomMixin', CUSTOM_FIELDS)

Person = Union[BasePerson, CustomMixin]


# module3.py (user facing)
def f(a: Person):
    # my objective is for IDEs like PyCharm to recognize a.eye_color and a.name
    a.eye_color
    a.name

นี่ค่อนข้างใกล้เคียงกัน เนื่องจาก IDE รู้จักคุณลักษณะต่างๆ แต่ยังแสดงคุณลักษณะอื่นๆ ทั้งหมดสำหรับ NamedTuple และ tuple ด้วย (เช่น _asdict ฯลฯ)

ฉันต้องการให้ผู้ใช้กำหนดแอตทริบิวต์เป็นรายการฟิลด์ ไม่ใช่ตามไวยากรณ์ของคลาสปกติ ประการแรก เพื่อให้สอดคล้องกับกรอบงานที่เหลือของฉัน ประการที่สอง การใช้ไวยากรณ์ของคลาสจะเปิดเวิร์มกระป๋อง เนื่องจากคุณสามารถทำทุกสิ่งในคลาสที่เฟรมเวิร์กของฉันไม่อนุญาต

ฉันยังลอง:

class CustomMixin:
  __slots__ = CUSTOM_FIELDS

แต่ PyCharm ไม่รู้จักสิ่งนี้ ฉันดูที่ typing.Protocol ด้วย แต่ก็ต้องมีการประกาศชั้นเรียนด้วย


person Chris    schedule 18.02.2021    source แหล่งที่มา
comment
dataclasses.make_dataclass() สามารถทำได้ ดูสิ่งที่ซ้ำกันเพื่อดูภาพรวมทั่วไปของสิ่งที่โมดูล dataclasses ทำ   -  person Martijn Pieters    schedule 18.02.2021
comment
dataclass เปิดตัวหลังจาก Python3.7   -  person Menglong Li    schedule 18.02.2021
comment
@MartijnPieters โดยพื้นฐานแล้วมันเหมือนกับ type(_, _, _) แต่สำหรับคลาสข้อมูลใช่ไหม   -  person DeepSpace    schedule 18.02.2021
comment
@DeepSpace: มันเกี่ยวข้องมากกว่าแค่ type(); อินพุตได้รับการตรวจสอบความถูกต้อง ชื่อที่ไม่มีคำใบ้ประเภทจะได้รับ typing.Any คำใบ้ และใช้ตัวตกแต่ง @dataclass() กับผลลัพธ์เพื่อสร้างวิธีการเช่น __init__ และ __repr__ ขึ้นอยู่กับอาร์กิวเมนต์ที่ใช้   -  person Martijn Pieters    schedule 18.02.2021
comment
@DeepSpace: และแทนที่จะเรียก type() ฟังก์ชันจะใช้ types.new_class() เพื่อจัดการเมตาคลาสที่กำหนดเองได้อย่างถูกต้อง   -  person Martijn Pieters    schedule 18.02.2021
comment
@MenglongLi: backport อย่างเป็นทางการ รองรับ Python 3.6 สำหรับรุ่นเก่า ให้ใช้ attrs ซึ่งรองรับ Python 2.7, 3.5 ขึ้นไป   -  person Martijn Pieters    schedule 18.02.2021