GVKun编程网logo

Python类成员初始化(python 类的成员)

15

本文将分享Python类成员初始化的详细内容,并且还将对python类的成员进行详尽解释,此外,我们还将为大家带来关于c–从类成员初始化器抛出的异常是否调用std::terminate()?、c–如何

本文将分享Python类成员初始化的详细内容,并且还将对python 类的成员进行详尽解释,此外,我们还将为大家带来关于c – 从类成员初始化器抛出的异常是否调用std :: terminate()?、c – 如何使初始化器列表和类成员初始化程序一起工作?、c# 类成员初始化顺序的特殊情况、C#类成员初始化顺序的相关知识,希望对你有所帮助。

本文目录一览:

Python类成员初始化(python 类的成员)

Python类成员初始化(python 类的成员)

我最近刚与Python中的一个错误作斗争。那是那些愚蠢的新手错误之一,但是它让我思考了Python的机制(我是C
++的老程序员,是Python的新手)。我将列出错误的代码并解释如何解决该问题,然后我有两个问题。

场景:我有一个叫做A的类,它有一个字典数据成员,下面是其代码(当然这是简化的):

class A:    dict1={}    def add_stuff_to_1(self, k, v):        self.dict1[k]=v    def print_stuff(self):        print(self.dict1)

使用此代码的类为B类:

class B:    def do_something_with_a1(self):        a_instance = A()        a_instance.print_stuff()                a_instance.add_stuff_to_1(''a'', 1)        a_instance.add_stuff_to_1(''b'', 2)            a_instance.print_stuff()    def do_something_with_a2(self):        a_instance = A()            a_instance.print_stuff()                    a_instance.add_stuff_to_1(''c'', 1)        a_instance.add_stuff_to_1(''d'', 2)            a_instance.print_stuff()    def do_something_with_a3(self):        a_instance = A()            a_instance.print_stuff()                    a_instance.add_stuff_to_1(''e'', 1)        a_instance.add_stuff_to_1(''f'', 2)            a_instance.print_stuff()    def __init__(self):        self.do_something_with_a1()        print("---")        self.do_something_with_a2()        print("---")        self.do_something_with_a3()

请注意,每次调用都会do_something_with_aX()初始化类A的新“干净”实例,并在添加前后打印字典。

错误(如果您尚未弄清楚):

>>> b_instance = B(){}{''a'': 1, ''b'': 2}---{''a'': 1, ''b'': 2}{''a'': 1, ''c'': 1, ''b'': 2, ''d'': 2}---{''a'': 1, ''c'': 1, ''b'': 2, ''d'': 2}{''a'': 1, ''c'': 1, ''b'': 2, ''e'': 1, ''d'': 2, ''f'': 2}

在类A的第二次初始化中,字典不是空的,而是从最后一次初始化的内容开始,依此类推。我希望他们开始“新鲜”。

解决此“错误”的原因显然是添加了:

self.dict1 = {}

__init__类A的构造函数中。但是,这使我感到奇怪:

  1. 在dict1的声明时(类A的第一行),“ dict1 = {}”初始化的含义是什么?没有意义吗?
  2. 导致从上次初始化复制引用的实例化机制是什么?
  3. 如果在构造函数(或任何其他数据成员)中添加“ self.dict1 = {}”,它如何不影响先前初始化实例的字典成员?

编辑:按照答案,我现在了解到,通过声明一个数据成员,而不是在__init__self.dict1或其他地方引用它,我实际上是在C ++ /
Java中定义一个静态数据成员。通过将其称为self.dict1,我将其设为“实例绑定”。

答案1

小编典典

您一直称其为错误的是Python类的已记录的标准行为。

__init__像最初那样在外部声明dict就是在声明类级变量。最初它只会创建一次,每当您创建新对象时,它都会重复使用此相同的字典。要创建实例变量,请使用selfin声明它们__init__;就这么简单。

c – 从类成员初始化器抛出的异常是否调用std :: terminate()?

c – 从类成员初始化器抛出的异常是否调用std :: terminate()?

给出这个代码:
struct A {
    A(int e) { throw e; }
};

struct B {
    A a{42}; // Same with = 42; Syntax
};

int main() {
    try {
        B b;
    } catch (int const e) {
        return e;
    }
}

当编译GCC(版本4.7.4,4.8.5,4.9.3,5.4.0,6.3.0)时:

$g++ -std=c++11 test.cpp -o test; ./test ; echo $?
terminate called after throwing an instance of 'int'
Aborted
134

但是当用Clang(版本4.0.0)编译时:

$clang++ -std=c++11 test.cpp -o test; ./test ; echo $?
42

哪个行为是正确的?

解决方法

这是GCC( Bug 80683)中的一个错误.

如果构造函数是try / catch子句中的第一个操作,那么编译器认为它不在其中,尽管它应该包含它.

例如,以下工作很好:

#include <iostream>

struct A {
    A(int e) { throw e; }
};

struct B {
    A a{42}; // Same with = 42; Syntax
};

int main() {
    try {
        // The following forces the compiler to put B's contructor inside the try/catch.
        std::cout << "Welcome" << std::endl; 
        B b;
    } catch (int e) {
        std::cout << "ERROR: " << e << std::endl; // This is just for debugging
    }

    return 0;
}

运行:

g++ -std=c++11 test.cpp -DNDEBUG -o test; ./test ; echo $?

输出:

Welcome
ERROR: 42
0

我的猜测是,由于编译器优化,它将构造函数移动到主函数的开头.它假定struct B没有构造函数,那么它假定它不会抛出异常,因此可以将它移动到try / catch子句之外.

如果我们将struct struct的声明改为明确地使用struct A构造函数:

struct B {
    B():a(42) {}
    A a;
};

那么结果将如预期的那样,我们将进入try / catch,即使删除“欢迎”打印输出:

ERROR: 42
0

c – 如何使初始化器列表和类成员初始化程序一起工作?

c – 如何使初始化器列表和类成员初始化程序一起工作?

以下代码既不能在 gcc-4.7.1和clang-3.2之间编译-std = c 11.所以我觉得我做错了.但我不知道为什么有人可以给我一个提示吗?基本上如果我删除X的类成员初始化器,它的工作.那么为什么初始化器列表不能与类成员初始化器一起工作?
struct X {    int x = 1;    int y = 1;};int main() {    X x = {1,2};}

gcc编译错误:

a.cpp: In function 'int main()':a.cpp:7:16: error: Could not convert '{1,2}' from '<brace-enclosed initializer list>' to 'X'

解决方法

通过在声明点初始化非静态数据成员,您的类不再是聚合(参见8.5.1聚合[decl.init.aggr]).

解决方法是添加一个双参数构造函数.这允许您使用initializer-list初始化,即使您的类在技术上不是聚合,也允许与聚合初始化相同的语法.

struct X {  X(int x,int y) : x(x),y(y) {}    int x = 1;    int y = 1;};int main() {    X x1{1,2};    X x2 = {1,2};}

注意:这些规则已经为C 1y放宽,这意味着您的类型确实是一个聚合.

c# 类成员初始化顺序的特殊情况

c# 类成员初始化顺序的特殊情况

这里直接给出C#类成员一般初始化顺序:

  1. 子类静态字段
  2. 子类静态构造
  3. 子类实例字段
  4. 父类静态字段
  5. 父类静态构造
  6. 父类实例字段
  7. 父类实例构造
  8. 子类实例构造

为什么说是“一般”初始化顺序呢?因为根据类结构的不同,类成员的初始化顺序并不是一成不变的。但是这个顺序是基础,可以推导出其他特殊的初始化顺序。下面我们就来看两种特殊的情况:

static void Main(string[] args)
{
  Console.WriteLine("---------------一般初始化顺序---------------");
  var child1 = new Child1();
  Console.WriteLine("\n---------------子类静态字段初始化需要使用父类静态字段时初始化顺序---------------");
  var child2 = new Child2();
  Console.WriteLine("\n---------------子类静态构造函数中使用父类静态字段时初始化顺序---------------");
  var child3 = new Child3();

  Console.ReadKey();
}

public class Child1 : Base1
{
  public static Display ChildStatic = new Display("Child static filed");

  private Display _childFiled = new Display("Child filed");

  static Child1() => Console.WriteLine("Child static ctor");

  public Child1() => Console.WriteLine("Child ctor");
}

public class Child2 : Base2
{
  /// <summary>
  /// 子类静态字段初始化需要使用父类静态字段
  /// </summary>
  public static Display ChildStatic = new Display("Child static filed", () => BaseStatic);

  private Display _childFiled = new Display("Child filed");

  static Child2() => Console.WriteLine("Child static ctor");

  public Child2() => Console.WriteLine("Child ctor");
}

public class Child3 : Base3
{
  public static Display ChildStatic = new Display("Child static filed");

  private Display _childFiled = new Display("Child filed");

  /// <summary>
  /// 子类静态构造函数中使用父类静态字段
  /// </summary>
  static Child3()
  {
    Console.WriteLine("Child static ctor");
    var baseStatic = BaseStatic;
  }

  public Child3() => Console.WriteLine("Child ctor");
}

/// <summary>
/// 3个Base类相同,这里是为了演示静态成员的初始化
/// </summary>
public class Base1
{
  public static Display BaseStatic = new Display("Base static filed");

  private Display _baseFiled = new Display("Base filed");

  static Base1() => Console.WriteLine("Base static ctor");

  public Base1() => Console.WriteLine("Base ctor");
}

public class Base2
{
  public static Display BaseStatic = new Display("Base static filed");

  private Display _baseFiled = new Display("Base filed");

  static Base2() => Console.WriteLine("Base static ctor");

  public Base2() => Console.WriteLine("Base ctor");
}

public class Base3
{
  public static Display BaseStatic = new Display("Base static filed");

  private Display _baseFiled = new Display("Base filed");

  static Base3() => Console.WriteLine("Base static ctor");

  public Base3() => Console.WriteLine("Base ctor");
}

public class Display
{
  public Display(string msg, Func<Display> displayFunc = null)
  {
    Console.WriteLine(msg);
    var display = displayFunc?.Invoke();
  }
}

补充一下:

1. 静态构造函数是线程安全的,会在初次访问该类所定义的其他方法、属性或变量之前执行

2. 编译器会在每个构造函数(包括静态和实例)的开头放入适当的程序码,以便把你在定义成员字段时所指定的初始值设置给这些变量,这就是字段总是在构造函数执行前初始化的原因。

3. 无论是静态变量还是实例变量,其取值都应该在声明的时候得以初始化。但以下3种情况不应该编写初始化语句

  • 把字段初始化为0或null。因为系统在执行开发者编写的代码之前,就会把内存清零,重复执行清零指令就显得多余了
  • 字段的初始值需要根据不同的构造函数来设定。这种情况下字段的初始化放在构造函数中就可以了,否则会导致创建多余的对象
  • 字段的初始化过程中可能出现异常。这种也应该放在构造函数中进行初始化,同时要注意千万不能让静态构造函数中的异常脱出,因为一个AppDomain仅能调用一次某个类的静态构造函数

通过了解类成员的初始化顺序,可以让我们更加详细地了解程序执行的细节,避免写出类似“在构造函数中调用虚函数或抽象函数”的代码。

以上就是c# 类成员初始化顺序的特殊情况的详细内容,更多关于C# 类初始化顺序的资料请关注其它相关文章!

您可能感兴趣的文章:
  • C#类的创建与初始化实例解析
  • C#中序列化实现深拷贝,实现DataGridView初始化刷新的方法
  • 初始化的两种方法" target="_blank">C#控制台基础 list<>初始化的两种方法

C#类成员初始化顺序

C#类成员初始化顺序

这里直接给出C#类成员一般初始化顺序:

  1. 子类静态字段
  2. 子类静态构造
  3. 子类实例字段
  4. 父类静态字段
  5. 父类静态构造
  6. 父类实例字段
  7. 父类实例构造
  8. 子类实例构造

为什么说是“一般”初始化顺序呢?因为根据类结构的不同,类成员的初始化顺序并不是一成不变的。但是这个顺序是基础,可以推导出其他特殊的初始化顺序。下面我们就来看两种特殊的情况:

static void Main(string[] args)
{
    Console.WriteLine("---------------一般初始化顺序---------------");
    var child1 = new Child1();
    Console.WriteLine("\n---------------子类静态字段初始化需要使用父类静态字段时初始化顺序---------------");
    var child2 = new Child2();
    Console.WriteLine("\n---------------子类静态构造函数中使用父类静态字段时初始化顺序---------------");
    var child3 = new Child3();

    Console.ReadKey();
}

public class Child1 : Base1
{
    public static display ChildStatic = new display("Child static filed");

    private display _childFiled = new display("Child filed");

    static Child1() => Console.WriteLine("Child static ctor");

    public Child1() => Console.WriteLine("Child ctor");
}

public class Child2 : Base2
{
    /// <summary>
    /// 子类静态字段初始化需要使用父类静态字段
    /// </summary>
    public static display ChildStatic = new display("Child static filed",() => BaseStatic);

    private display _childFiled = new display("Child filed");

    static Child2() => Console.WriteLine("Child static ctor");

    public Child2() => Console.WriteLine("Child ctor");
}

public class Child3 : Base3
{
    public static display ChildStatic = new display("Child static filed");

    private display _childFiled = new display("Child filed");

    /// <summary>
    /// 子类静态构造函数中使用父类静态字段
    /// </summary>
    static Child3()
    {
        Console.WriteLine("Child static ctor");
        var baseStatic = BaseStatic;
    }

    public Child3() => Console.WriteLine("Child ctor");
}

/// <summary>
/// 3个Base类相同,这里是为了演示静态成员的初始化
/// </summary>
public class Base1
{
    public static display BaseStatic = new display("Base static filed");

    private display _baseFiled = new display("Base filed");

    static Base1() => Console.WriteLine("Base static ctor");

    public Base1() => Console.WriteLine("Base ctor");
}

public class Base2
{
    public static display BaseStatic = new display("Base static filed");

    private display _baseFiled = new display("Base filed");

    static Base2() => Console.WriteLine("Base static ctor");

    public Base2() => Console.WriteLine("Base ctor");
}

public class Base3
{
    public static display BaseStatic = new display("Base static filed");

    private display _baseFiled = new display("Base filed");

    static Base3() => Console.WriteLine("Base static ctor");

    public Base3() => Console.WriteLine("Base ctor");
}

public class display
{
    public display(string msg,Func<display> displayFunc = null)
    {
        Console.WriteLine(msg);
        var display = displayFunc?.Invoke();
    }
}

分享图片


补充一下:

  • 静态构造函数是线程安全的,会在初次访问该类所定义的其他方法、属性或变量之前执行
  • 编译器会在每个构造函数(包括静态和实例)的开头放入适当的程序码,以便把你在定义成员字段时所指定的初始值设置给这些变量,这就是字段总是在构造函数执行前初始化的原因。
  • 无论是静态变量还是实例变量,其取值都应该在声明的时候得以初始化。但以下3种情况不应该编写初始化语句
    • 把字段初始化为0或null。因为系统在执行开发者编写的代码之前,就会把内存清零,重复执行清零指令就显得多余了
    • 字段的初始值需要根据不同的构造函数来设定。这种情况下字段的初始化放在构造函数中就可以了,否则会导致创建多余的对象
    • 字段的初始化过程中可能出现异常。这种也应该放在构造函数中进行初始化,同时要注意千万不能让静态构造函数中的异常脱出,因为一个AppDomain仅能调用一次某个类的静态构造函数

通过了解类成员的初始化顺序,可以让我们更加详细地了解程序执行的细节,避免写出类似“在构造函数中调用虚函数或抽象函数”的代码。

关于Python类成员初始化python 类的成员的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于c – 从类成员初始化器抛出的异常是否调用std :: terminate()?、c – 如何使初始化器列表和类成员初始化程序一起工作?、c# 类成员初始化顺序的特殊情况、C#类成员初始化顺序的相关知识,请在本站寻找。

本文标签: