关于python:在类的多个方法中使用self

The use of self in multiple methods of a class

所以,作为一个初学者,我创建了这个程序,它使用tkinter来计算pokemon-go中不同pokemon/candy组合的最大可能演变。我先创建了这个程序,然后才对代码使用函数。然而,我认为使用一门课会很好,经过一些研究,这就是结果。但是,我基本上是通过在不同方法的一大堆变量中添加self来实现的。

我的问题是:在这里使用一个类是否相关?我对类的研究涉及到用对象等填充一个类,但这里我只创建一个对象,以便使用该类并运行一系列计算。

此外,如何知道调用变量时何时使用self。例如,我创建静态类变量的感觉是,我不需要将实例本身放在它前面就可以使用它,但是这不起作用,所以我只是在调用变量之前放置了更多的自我。为什么把一堆自我放在每件事情的前面?自我是不是太过分了,我能用更聪明的方式去做吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
from tkinter import *
from tkinter import messagebox


class PokeCalculator(Frame):
    pokedex = {
        'pidgey': 12,
        'caterpie': 12,
        'weedle': 12,
        'rattata': 25
    }
    choices = pokedex.keys()
    screen_title = 'Pokemon evolve calculator'

    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.master = master
        self.make_window()

    def make_window(self):
        self.master.title(self.screen_title)

        L1 = Label(self, text='Candies')
        L1.grid(column=1, row=0)

        L2 = Label(self, text='Pokemon amount in storage')
        L2.grid(column=2, row=0)

        self.var = StringVar()
        self.var.set('Pokemon')
        self.Pokemon = OptionMenu(self, self.var, *self.choices)
        self.Pokemon.grid(column=0, row=1)

        self.Candies = Entry(self)
        self.Candies.grid(column=1, row=1)

        self.Poke_amount = Entry(self)
        self.Poke_amount.grid(column=2, row=1)

        Calculate = Button(self, text='Calculate', command=self.get_and_check)
        Calculate.grid(column=1, row=2)

    def get_and_check(self):
        self.get_values()
        self.check_input()

    def get_values(self):
        self.poke = self.var.get()
        self.candies_total = self.Candies.get()
        self.p_amount = self.Poke_amount.get()

    def check_input(self):
        string1 = 'Please select a Pokemon from the dropdown menu'
        string2 = 'Please only enter numbers'
        if self.poke == 'Pokemon':
            messagebox.showinfo(self.screen_title, string1)
        elif not self.p_amount.isdigit() or not self.candies_total.isdigit():
            messagebox.showinfo(self.screen_title, string2)
        else:
            self.too_few_pokemon()

    def too_few_pokemon(self):
        candies_total = int(self.candies_total)
        p_amount = int(self.p_amount)
        evolve = int((candies_total - 1) / (self.pokedex[self.poke] - 1))
        candies_needed = (p_amount * (self.pokedex[self.poke] - 1)) + 1
        if p_amount <= evolve:
            n = 0
            while candies_needed <= candies_total:
                n = n + 1
                p_amount = p_amount + 1
                candies_needed = ((p_amount) * (self.pokedex[self.poke] - 1)) + 1
                candies_total = candies_total + 3
                evolve2 = int((candies_total - 1) / (self.pokedex[self.poke] - 1))
            string1 = '''            You have enough candies too evolve {0} {1},
            but you only have {2} {1} in storage and thus can only
            evolve {2} {1}.
            If you catch {3} more {1} you can now evolve {4} {1}.'''

            messagebox.showinfo(self.screen_title, string1.format(evolve, self.poke,
                                                                  self.p_amount,
                                                                  n, evolve2))
        else:
            self.too_much_pokemon()

    def too_much_pokemon(self):
        candies_total = int(self.candies_total)
        p_amount = int(self.p_amount)
        candies_needed = (p_amount * (self.pokedex[self.poke] - 1)) + 1
        m = 0
        while candies_total <= candies_needed:
            m = m + 1
            p_amount = p_amount - 1
            candies_needed = ((p_amount) * (self.pokedex[self.poke] - 1)) + 1
            candies_total = candies_total + 1
            evolve = int((candies_total - 1) / (self.pokedex[self.poke] - 1))
        string2 = 'Transfer {0} {1} so you can evolve a total of {2} {1}.'
        messagebox.showinfo(self.screen_title, string2.format(m, self.poke, evolve))


root = Tk()
app = PokeCalculator(root)
app.pack()
root.mainloop()


第一次-课堂的使用在这里也很重要。几乎Python中的所有内容都是一个对象,即使您没有意识到它。第二,类变量和实例变量之间存在差异。把课堂想象成一个蓝图。每次希望基于类创建对象时,都会访问此蓝图。在类内部声明的变量,但在任何方法(例如pokedex)外部声明的变量称为类变量。它们保存了蓝图的值。创建类(对象)的实例时,这些类变量将转换为对象的实例变量。实例变量是在init和其他函数中定义的,您可以使用self.variable引用任何实例变量。关于类和实例有很多要了解的地方,它不能在一个简单的堆栈溢出答案中进行编译。遵循https://docs.python.org/3.6/tutorial/classes.html

看看你的代码,你做得很好。我会使用更多的"self":)例如在l1、l2或calculate上,因为我不知道什么时候要在创建它们的方法之外引用它们。很好的规则是,在类中使用self以后可能需要的任何东西:)

最后但并非最不重要:是的,您的程序可能没有任何自定义类。或者,您不需要使用类或实例变量,而是将所有内容保存在全局和局部变量中。它也可以不使用任何方法或函数:)并且可以用汇编语言编写:d有很多可能性,但是当您进行面向对象的编程时,使用对象很好:)现在您的类是可重用的,例如,我可以将它从模块导入到我的程序中。:)即使每个程序只实例化一个类中的一个对象,通常也使用类作为它的蓝图。更容易理解整个代码及其部分。就像在现实世界中——我是彼得,我是一个典型的阶级人物。我有一只右手,我称之为"我自己"。右手(我的右手,不只是任何一只手),这只手是"班级之手"的一个例子。类手有一个方法抓取。我的右手也能抓住!我用右手抓住一个苹果,叫自己。右手。抓住(苹果)。

祝你前进顺利!


请考虑以下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
class A:
    a_class_attribute = 'A class attribute'
    def __init__(self, a):
        self.a_instance_attribute = a
    def amethod(self):
        print('a method')

class B(A):
    b_class_attribute = 'B class attribute'
    def __init__(self, b):
        self.b_instance_attribute = b
    def bmethod(self):
        print('b method')

现在,我们来举一个A的例子:

1
In [2]: a = A('foo')

注意,通过检查实例的__dict__可以看到哪些属性属于该实例,

1
2
In [3]: a.__dict__
Out[3]: {'a_instance_attribute': 'foo'}

这是有意义的,因为我们有一个实例属性。那班呢?

1
2
3
4
5
6
7
8
9
In [7]: A.__dict__
Out[7]:
mappingproxy({'__dict__': ,
              '__doc__': None,
              '__init__': <function self_oop_ex.A.__init__>,
              '__module__': 'self_oop_ex',
              '__weakref__': ,
              'a_class_attribute': 'A class attribute',
              'amethod': <function self_oop_ex.A.amethod>})

所以a_class_attribute仅仅是一个属于类的属性。注意,这些方法也属于类,您可以将一个方法视为恰好是一个函数的类对象。不过,还会有更多的魔法发生。但是首先,您需要记住,当您访问一个实例上的一个属性时,例如my_instance.some_attribute,python check首先是对象名称空间(即__dict__),如果它找到了该属性,它会返回它。否则,它将在类的命名空间中查找属性!因此,我们可以从类和实例访问类属性:

1
2
3
4
5
In [8]: A.a_class_attribute
Out[8]: 'A class attribute'

In [9]: a.a_class_attribute
Out[9]: 'A class attribute'

现在,这和self有什么关系?好吧,python做的一件神奇的事情是,如果在访问一个实例的属性时发现了一个方法,如果调用该方法,它会隐式地将实例作为第一个参数传递,即我们通常称之为self。所以,

1
2
In [10]: a.amethod()
a method

相当于:

1
2
In [11]: A.amethod(a)
a method

方法就是这样!与其他任何函数一样,如果函数是从实例中获得的,那么python通过隐式传递实例来帮助我们。注意,我们可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
In [17]: class Krazy:
    ...:     def use_pop(self):
    ...:         return self.pop()
    ...:     def pop(self):
    ...:         print("I am a Krazy pop")
    ...:

In [18]: k = Krazy()

In [19]: k.pop()
I am a Krazy pop

In [20]: mylist = [1,2,3,4,5]

In [21]: mylist.pop()
Out[21]: 5

In [22]: k.use_pop()
I am a Krazy pop

In [23]: Krazy.use_pop(mylist)
Out[23]: 4

注:use_pop方法使用self.pop,正如我们对任何函数所期望的那样,它调用self的适当pop方法,当我们使用Krazy.use_pop(mylist)时,它是属于列表对象的pop方法。

最后,考虑类B,它源自AB实例可以访问自己的实例属性,以及B类和A类的类属性。简言之,这就是继承:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
In [25]: b = B('bar')

In [26]: b.__dict__
Out[26]: {'b_instance_attribute': 'bar'}

In [27]: B.__dict__
Out[27]:
mappingproxy({'__doc__': None,
              '__init__': <function self_oop_ex.B.__init__>,
              '__module__': 'self_oop_ex',
              'b_class_attribute': 'B class attribute',

              'bmethod': <function self_oop_ex.B.bmethod>})

In [28]: b.amethod()
a method

In [29]: b.bmethod()
b method

In [30]: b.a_class_attribute
Out[30]: 'A class attribute'

In [31]: b.b_class_attribute
Out[31]: 'B class attribute'

当然,多重继承会变得更加复杂,但是现在,试着担心简单的继承情况。


self是指该类的实例(对象)。在Python中,类中有两种类型的属性。类属性和实例属性。

https://docs.python.org/2/tutorial/classes.html类和实例变量

实例属性特定于类的实例(对象)。类属性与类有关。这些属性由类的所有实例共享。

在代码中,pokedexchoicesscreen_title都是类属性的例子。self.masterself.varself.Pokemon等属性都是实例属性的例子。

在这里使用一个类甚至是相关的吗?

我会说是的。类是数据和方法的逻辑分组。它封装了一些数据和一些可以对这些数据执行的方法。我们不只是把随机的东西放在一个类中,而是尝试在事物之间有逻辑连接的地方创建类。

这可能是一个有用的来源:https://jeffknupp.com/blog/2014/06/18/improve-your-python-python-classes-and-object-oriented-programming/