GVKun编程网logo

什么时候应该继承EnumMeta而不是Enum?(什么时候用到继承)

4

最近很多小伙伴都在问什么时候应该继承EnumMeta而不是Enum?和什么时候用到继承这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展c#–为什么Linq扩展方法不是坐在IEnum

最近很多小伙伴都在问什么时候应该继承EnumMeta而不是Enum?什么时候用到继承这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展c# – 为什么Linq扩展方法不是坐在IEnumerator而不是IEnumerable?、c# – 什么时候应该覆盖OnEvent而不是在继承时预订事件、C++ 中什么时候应该使用继承,什么时候应该使用组合?、Enum、EnumMap、EnumSet等相关知识,下面开始了哦!

本文目录一览:

什么时候应该继承EnumMeta而不是Enum?(什么时候用到继承)

什么时候应该继承EnumMeta而不是Enum?(什么时候用到继承)

在本文中, Nick
Coghlan讨论了PEP
435Enum类型的一些设计决策,以及如何EnumMeta将其子类化以提供不同的Enum体验。

但是,我给出的建议(我是stdlib的主要Enum作者)关于使用元类的建议是,在没有充分好的理由的情况下不应该这样做-
例如,无法使用类装饰器或专用工具来完成所需的工作隐藏任何丑陋的功能;而在我自己的工作,我已经能够做到我需要什么简单的使用__new____init__在创建时,和/或正常类/实例方法Enum类:

  • Enum 具有属性

  • 处理失踪成员

  • 不是Enum成员的类常量

考虑到所有这些,我什么时候需要摆弄EnumMeta自己?

答案1

小编典典

首先,查看不进行子类化时所需的代码EnumMeta

stdlib方式

from enum import Enumimport jsonclass BaseCountry(Enum):    def __new__(cls, record):        member = object.__new__(cls)        member.country_name = record[''name'']        member.code = int(record[''country-code''])        member.abbr = record[''alpha-2'']        member._value_ = member.abbr, member.code, member.country_name        if not hasattr(cls, ''_choices''):            cls._choices = {}        cls._choices[member.code] = member.country_name        cls._choices[member.abbr] = member.country_name        return member                    def __str__(self):        return self.country_nameCountry = BaseCountry(        ''Country'',        [(rec[''alpha-2''], rec) for rec in json.load(open(''slim-2.json''))],        )

aenum方法 1 2

from aenum import Enum, MultiValueimport jsonclass Country(Enum, init=''abbr code country_name'', settings=MultiValue):    _ignore_ = ''country this''  # do not add these names as members    # create members    this = vars()    for country in json.load(open(''slim-2.json'')):        this[country[''alpha-2'']] = (                country[''alpha-2''],                int(country[''country-code'']),                country[''name''],                )    # have str() print just the country name    def __str__(self):        return self.country_name

上面的代码适合一次性枚举-但是如果从JSON文件创建枚举对您来说很普遍怎么办?想象一下您是否可以这样做:

class Country(JSONEnum):    _init_ = ''abbr code country_name''  # remove if not using aenum    _file = ''some_file.json''    _name = ''alpha-2''    _value = {            1: (''alpha-2'', None),            2: (''country-code'', lambda c: int(c)),            3: (''name'', None),            }

如你看到的:

  • _file 是要使用的json文件的名称
  • _name 是该名称应使用的路径
  • _value是将路径映射到值3的字典
  • _init_指定不同值组件的属性名称(如果使用aenum

JSON数据摘自https://github.com/lukes/ISO-3166-Countries-with-Regional-Codes-
以下是简短摘录:

[{“ name”:“ Afghanistan”,“ alpha-2”:“ AF”,“国家/地区代码”:“ 004”},

{“ name”:“ÅlandIslands”,“ alpha-2”:“ AX”,“国家/地区代码”:“ 248”},

{“名称”:“阿尔巴尼亚”,“ alpha-2”:“ AL”,“国家代码”:“ 008”},

{“名称”:“阿尔及利亚”,“ alpha-2”:“ DZ”,“国家/地区代码”:“ 012”}]

这是JSONEnumMeta课程:

class JSONEnumMeta(EnumMeta):    @classmethod    def __prepare__(metacls, cls, bases, **kwds):        # return a standard dictionary for the initial processing        return {}    def __init__(cls, *args , **kwds):        super(JSONEnumMeta, cls).__init__(*args)    def __new__(metacls, cls, bases, clsdict, **kwds):        import json        members = []        missing = [               name               for name in (''_file'', ''_name'', ''_value'')               if name not in clsdict               ]        if len(missing) in (1, 2):            # all three must be present or absent            raise TypeError(''missing required settings: %r'' % (missing, ))        if not missing:            # process            name_spec = clsdict.pop(''_name'')            if not isinstance(name_spec, (tuple, list)):                name_spec = (name_spec, )            value_spec = clsdict.pop(''_value'')            file = clsdict.pop(''_file'')            with open(file) as f:                json_data = json.load(f)            for data in json_data:                values = []                name = data[name_spec[0]]                for piece in name_spec[1:]:                    name = name[piece]                for order, (value_path, func) in sorted(value_spec.items()):                    if not isinstance(value_path, (list, tuple)):                        value_path = (value_path, )                    value = data[value_path[0]]                    for piece in value_path[1:]:                        value = value[piece]                    if func is not None:                        value = func(value)                    values.append(value)                values = tuple(values)                members.append(                    (name, values)                    )        # get the real EnumDict        enum_dict = super(JSONEnumMeta, metacls).__prepare__(cls, bases, **kwds)        # transfer the original dict content, _items first        items = list(clsdict.items())        items.sort(key=lambda p: (0 if p[0][0] == ''_'' else 1, p))        for name, value in items:            enum_dict[name] = value        # add the members        for name, value in members:            enum_dict[name] = value        return super(JSONEnumMeta, metacls).__new__(metacls, cls, bases, enum_dict, **kwds)# for use with both Python 2/3JSONEnum = JSONEnumMeta(''JsonEnum'', (Enum, ), {})

一些注意事项:

  • JSONEnumMeta.__prepare__ 返回正常 dict

  • EnumMeta.__prepare__用于获取的实例_EnumDict-这是获取实例的正确方法

  • 带下划线的键将被传递给实数_EnumDict优先,因为在处理枚举成员时可能需要它们

  • 枚举成员的顺序与文件中的顺序相同


1披露:我是Python
stdlibEnumenum34backport和Advanced
Enumeration(aenum) 库的作者。

2这需要aenum 2.0.5+

3键是数字键,可以在需要多个值时按顺序保留多个值Enum

c# – 为什么Linq扩展方法不是坐在IEnumerator而不是IEnumerable?

c# – 为什么Linq扩展方法不是坐在IEnumerator而不是IEnumerable?

有很多 Linq算法只需要一次通过输入,例如选择.

然而,所有的Linq扩展方法都位于IEnumerable而不是IEnumerator

var e = new[] { 1,2,3,4,5 }.GetEnumerator(); 
    e.Select(x => x * x); // Doesn't work

这意味着你不能在任何从“已经打开的”流中读取的情况下使用Linq.

这个方案正在为我目前正在开发的项目发生很多事情 – 我想返回一个IEnumerator,其Idispose方法将关闭流,并且所有下游的Linq代码都可以在此操作.

简而言之,我有一个“已经打开”的结果流,我可以将其转换成适当的一次性IEnumerator – 但不幸的是,所有下游代码都需要一个IEnumerable而不是IEnumerator,尽管它只会执行一个“pass”.

即我想要在各种不同的来源(CSV文件,IDataReaders等)上“实现”这种返回类型:

class Tabularstream 
{ 
    Column[] Columns; 
    IEnumerator<object[]> RowStream; 
}

为了获得“列”,我必须已经打开了CSV文件,启动了SQL查询,或者其他.然后我可以返回其“dispose”方法关闭资源的“IEnumerator”,但是所有Linq操作都需要一个IEnumerable.

我知道的最好的解决方法是实现一个IEnumerable,其GetEnumerator()方法返回一个唯一的IEnumerator,如果有人尝试执行一次GetEnumerator()调用两次,则会抛出一个错误.

这一切听起来还是有一个更好的方法来实现“Tabularstream”的一个方便从Linq使用的方式?

解决方法

使用IEnumerator< T>在我看来,直接很少是个好主意.

一方面,它编码了它是破坏性的事实 – 而LINQ查询通常可以多次运行.它们意味着是无副作用的,而迭代在IEnumerator< T>自然是副作用的.

这也使得实际上不可能在LINQ to Objects中执行一些优化,例如如果您实际上要求ICollection< T>使用Count属性,为它的数量.

对于您的解决方法:是的,OneshotEnumerable将是一个合理的方法.

c# – 什么时候应该覆盖OnEvent而不是在继承时预订事件

c# – 什么时候应该覆盖OnEvent而不是在继承时预订事件

何时应该做以下事情?
class Foo : Control
{
    protected override void OnClick(EventArgs e)
    {
        // new code here
    }
}

与此相反?

class Foo : Control
{
    public Foo()
    {
        this.Click += new EventHandler(Clicked);
    }

    private void Clicked(object sender,EventArgs e)
    {
        // code
    }
}

解决方法

覆盖而不是附加代理将导致更有效的代码,因此通常建议您始终尽可能地执行此操作.有关更多信息,请参阅 this MSDN article.这是一个相关报价:

The protected OnEventName method also allows derived classes to override the event without attaching a delegate to it. A derived class must always call the OnEventName method of the base class to ensure that registered delegates receive the event.

C++ 中什么时候应该使用继承,什么时候应该使用组合?

C++ 中什么时候应该使用继承,什么时候应该使用组合?

c++++ 中,继承用于建立“是-一个”关系,强制执行接口一致性。而组合用于建立“包含-一个”关系,提供灵活性。继承:当子类与基类具有“是-一个”关系时使用,如车辆与汽车。组合:当容器类与组件类具有“包含-一个”关系时使用,如游戏中的角色包含武器、防御、健康值。

C++ 中什么时候应该使用继承,什么时候应该使用组合?

C++ 中继承与组合:何时使用?

在 C++ 中,继承和组合是两种用于对象组织和代码重用的技术。理解何时使用哪种技术对于编写可维护、可扩展的代码至关重要。

继承

立即学习“C++免费学习笔记(深入)”;

继承允许一个类(子类)从另一个类(基类)继承数据和行为。子类可以访问基类中的所有非私有成员变量和函数,并可以重写这些成员以实现不同的行为。

何时使用继承:

  • 当子类与基类具有“是-一个”关系时,例如:

    • 车辆:汽车、卡车、摩托车
    • 动物:猫、狗、鸟
  • 当需要强制执行特定接口时,例如:

    • 形状:圆形、方形、三角形

优点:

  • 提供代码复用性
  • 促进多态性(通过虚函数)
  • 强制执行接口一致性

组合

组合涉及创建一个类(容器类)并通过指针或引用将另一个类(组件类)作为其数据成员包含在其中。组合允许容器类使用组件类的功能,但两者在内存中是独立的实体。

何时使用组合:

  • 当容器类与组件类具有“包含-一个”关系时,例如:

    • 汽车:发动机、轮胎、车身
    • 电脑:主板、CPU、内存
  • 当需要更大的灵活性时,例如:

    • 在运行时修改容器类的组件
    • 使用不同类型的组件实现同一种接口

优点:

  • 提供更大的灵活性
  • 允许代码重用
  • 促进模块化

实战案例:

考虑一个动物模拟程序,其中需要表示各种动物。我们可以使用继承为所有动物定义一个基类 Animal,包含共同属性(例如名称、类型)。然后,我们可以创建子类 Cat、Dog 和 Bird 来表示特定类型的动物,并为每个子类重写描述独特行为的虚函数。

另一方面,可以考虑一个游戏引擎,其中需要表示角色。我们可以使用组合为每个角色创建一个容器类 Character,包含其他类作为组件:

class Character {
public:
  Sword* sword;  // 组件:武器
  Shield* shield;  // 组件:防御
  Health* health;  // 组件:生命值
};
登录后复制

通过这种方式,我们可以轻松地创建具有不同武器、防御和健康值的各种角色,而无需创建多个继承类。

总之,在 C++ 中,继承主要用于建立“是-一个”关系并强制执行接口一致性,而组合主要用于建立“包含-一个”关系并提供更大的灵活性。根据应用程序的特定要求,明智地选择这些技术对于编写清晰、可维护的代码至关重要。

以上就是C++ 中什么时候应该使用继承,什么时候应该使用组合?的详细内容,更多请关注php中文网其它相关文章!

Enum、EnumMap、EnumSet

Enum、EnumMap、EnumSet

1、Enum

  • 不带参数
public enum Car {  
    AUDI {  
        @Override  
        public int getPrice() {  
            return 25000;  
        }  
    },  
    MERCEDES {  
        @Override  
        public int getPrice() {  
            return 30000;  
        }  
    },  
    BMW {  
        @Override  
        public int getPrice() {  
            return 20000;  
        }  
    };  
      
    public abstract int getPrice();  
}  
  • 带参数
        // Create an EnumMap that contains all constants of the Car enum.  
        EnumMap cars = new EnumMap(Car.class);  
          
        // Put some values in the EnumMap.  
        cars.put(Car.BMW, Car.BMW.getPrice());  
        cars.put(Car.AUDI, Car.AUDI.getPrice());  
        cars.put(Car.MERCEDES, Car.MERCEDES.getPrice());  
          
        // Print the values of an EnumMap.  
        for(Car c: cars.keySet())  
            System.out.println(c.name());  
          
        System.out.println(cars.size());  
          
        // Remove a Day object.  
        cars.remove(Car.BMW);  
        System.out.println("After removing Car.BMW, size: " + cars.size());  
          
        // Insert a Day object.  
        cars.put(Car.valueOf("BMW"), Car.BMW.getPrice());  
        System.out.println("Size is now: " + cars.size());  

2、EnumMap 

        EnumMap cars = new EnumMap(Car.class);  
          
        // Put some values in the EnumMap.  
        cars.put(Car.BMW, Car.BMW.getPrice());  
        cars.put(Car.AUDI, Car.AUDI.getPrice());  
        cars.put(Car.MERCEDES, Car.MERCEDES.getPrice()); 

3、EnumSet

        // Create an EnumSet that contains all days of the week.  
        EnumSet week = EnumSet.allOf(Day.class);  
          
        // Print the values of an EnumSet.  
        for(Day d: week)  
            System.out.println(d.name());  
          
        System.out.println(week.size());  
          
        // Remove a Day object.  
        week.remove(Day.FRIDAY);  
        System.out.println("After removing Day.FRIDAY, size: " + week.size());  
          
        // Insert a Day object.  
        week.add(Day.valueOf("FRIDAY"));  
        System.out.println("Size is now: " + week.size());  

今天关于什么时候应该继承EnumMeta而不是Enum?什么时候用到继承的分享就到这里,希望大家有所收获,若想了解更多关于c# – 为什么Linq扩展方法不是坐在IEnumerator而不是IEnumerable?、c# – 什么时候应该覆盖OnEvent而不是在继承时预订事件、C++ 中什么时候应该使用继承,什么时候应该使用组合?、Enum、EnumMap、EnumSet等相关知识,可以在本站进行查询。

本文标签: