我无法理解类的初始化。
他们有什么意义,我们如何知道包含在其中的内容?在类中编写需要不同类型的思考而不是创建函数(我想我可以创建函数,然后将它们包装在一个类中,这样我就可以重用它们。这会起作用吗?)
以下是一个例子:
class crawler:
# Initialize the crawler with the name of database
def __init__(self,dbname):
self.con=sqlite.connect(dbname)
def __del__(self):
self.con.close()
def dbcommit(self):
self.con.commit()
或其他代码示例:
class bicluster:
def __init__(self,vec,left=None,right=None,distance=0.0,id=None):
self.left=left
self.right=right
self.vec=vec
self.id=id
self.distance=distance
在尝试阅读其他人的代码时遇到__init__
这么多的课程,但我不明白创建它们的逻辑。
答案 0 :(得分:266)
通过你所写的内容,你错过了一个重要的理解:一个类和一个对象之间的区别。 __init__
没有初始化类,它初始化类或对象的实例。每只狗都有颜色,但是作为一个班级的狗不会。每只狗有四只或更少的脚,但是这类狗并不是。该类是对象的概念。当你看到Fido和Spot时,你会发现它们的相似之处,它们的犬友。那是班上的。
当你说
时class Dog:
def __init__(self, legs, colour):
self.legs = legs
self.colour = colour
fido = Dog(4, "brown")
spot = Dog(3, "mostly yellow")
你说,Fido是一只有四条腿的棕色狗,而Spot有点像跛脚,大多是黄色的。 __init__
函数称为构造函数或初始化函数,并在创建类的新实例时自动调用。在该函数中,新创建的对象被分配给参数self
。符号self.legs
是变量legs
中对象的self
属性。属性类似于变量,但它们描述了对象的状态,或对象可用的特定动作(函数)。
然而,请注意,你没有为自己设定colour
- 这是一个抽象的概念。有些属性在类上有意义。例如,population_size
就是其中之一 - 计算Fido是没有意义的,因为Fido总是一个。数狗是有道理的。让我们说世界上有2亿只狗。它是Dog类的财产。 Fido与2亿号无关,Spot也没有。它被称为"类属性",而不是"实例属性"上面是colour
或legs
。
现在,对于更少的犬和更多与节目相关的东西。正如我在下面写的那样,添加东西的课程是不明智的 - 它是什么类? Python中的类由不同数据的集合组成,其行为类似。一类狗由Fido和Spot以及199999999998其他与它们相似的动物组成,它们都在路灯柱上撒尿。添加东西的课程包含哪些内容?根据他们固有的数据,他们有什么不同?他们分享了什么行动?
然而,数字......那些是更有趣的主题。说,整数。这里有很多,比狗多得多。我知道Python已经有了整数,但是让我们玩笨蛋并且实现"再次(通过欺骗和使用Python的整数)。
所以,整数是一个类。他们有一些数据(值)和一些行为("将我加到另一个数字")。让我们来说明一下:
class MyInteger:
def __init__(self, newvalue)
# imagine self as an index card.
# under the heading of "value", we will write
# the contents of the variable newvalue.
self.value = newvalue
def add(self, other):
# when an integer wants to add itself to another integer,
# we'll take their values and add them together,
# then make a new integer with the result value.
return MyInteger(self.value + other.value)
three = MyInteger(3)
# three now contains an object of class MyInteger
# three.value is now 3
five = MyInteger(5)
# five now contains an object of class MyInteger
# five.value is now 5
eight = three.add(five)
# here, we invoked the three's behaviour of adding another integer
# now, eight.value is three.value + five.value = 3 + 5 = 8
print eight.value
# ==> 8
这有点脆弱(我们假设other
将是MyInteger),但我们现在忽略了。在实际代码中,我们不会;我们测试它以确保,甚至可能强制它("你不是一个整数?通过golly,你有10纳秒成为一个!9 ... 8 .... &#34)
我们甚至可以定义分数。分数也知道如何添加自己。
class MyFraction:
def __init__(self, newnumerator, newdenominator)
self.numerator = newnumerator
self.denominator = newdenominator
# because every fraction is described by these two things
def add(self, other):
newdenominator = self.denominator * other.denominator
newnumerator = self.numerator * other.denominator + self.denominator * other.numerator
return MyFraction(newnumerator, newdenominator)
除了整数之外还有更多的分数(不是真的,但计算机不知道这一点)。让我们两个:
half = MyFraction(1, 2)
third = MyFraction(1, 3)
five_sixths = half.add(third)
print five_sixths.numerator
# ==> 5
print five_sixths.denominator
# ==> 6
你实际上并没有在这里宣布任何事情。属性就像一种新的变量。正常变量只有一个值。我们假设你写colour = "grey"
。您不能拥有另一个名为colour
的{{1}}变量 - 不在代码中的相同位置。
阵列在一定程度上解决了这个问题。如果您说"fuchsia"
,您已将两种颜色堆叠到变量中,但您可以通过它们的位置(在这种情况下为0或1)来区分它们。
属性是绑定到对象的变量。与数组一样,我们可以在不同的狗上有很多colour = ["grey", "fuchsia"]
个变量,。因此,colour
是一个变量,但fido.colour
是另一个变量。第一个绑定到变量spot.colour
中的对象;第二个,fido
。现在,当您致电spot
或Dog(4, "brown")
时,将始终存在一个不可见的参数,该参数将分配给参数列表前面的悬空额外参数。它通常被称为three.add(five)
,它将获得点前面的对象的值。因此,在狗的self
(构造函数)中,__init__
将成为新狗将会成为的任何东西;在self
MyInteger
范围内,add
将绑定到变量self
中的对象。因此,three
将在three.value
之外的同一变量,add
内的self.value
。
如果我说add
,我将开始使用另一个名称来引用称为the_mangy_one = fido
的对象。从现在开始,fido
与fido.colour
完全相同。
那么,the_mangy_one.colour
里面的东西。你可以把它们想象成狗的出生证明。 __init__
本身是一个随机变量,可以包含任何内容。 colour
或fido.colour
就像是狗身份证上的表格字段; self.colour
是第一次填写的职员。
更清楚吗?
编辑:扩展以下评论:
您的意思是对象列表,不是吗?
首先,__init__
实际上不是一个对象。它是一个变量,当前包含一个对象,就像你说fido
时一样,x = 5
是一个当前包含数字5的变量。如果您以后改变主意,可以x
(只要您已经创建了一个类fido = Cat(4, "pleasing")
),然后Cat
将来自"包含&# 34;猫对象。如果你做fido
,那么它将包含数字5,而不是动物对象。
除非您专门编写代码来跟踪它们,否则类本身并不知道它的实例。例如:
fido = x
此处,class Cat:
census = [] #define census array
def __init__(self, legs, colour):
self.colour = colour
self.legs = legs
Cat.census.append(self)
是census
类的类级别属性。
Cat
请注意,您不会获得fluffy = Cat(4, "white")
spark = Cat(4, "fiery")
Cat.census
# ==> [<__main__.Cat instance at 0x108982cb0>, <__main__.Cat instance at 0x108982e18>]
# or something like that
。这些只是变量名。如果您希望猫自己拥有名称,则必须为名称创建单独的属性,然后覆盖[fluffy, sparky]
方法以返回此名称。这个方法(即类绑定函数,就像__str__
或add
)目的是描述如何将对象转换为字符串,就像打印出来一样。
答案 1 :(得分:23)
向thorough explanation from Amadan贡献我的5美分。
其中类是抽象方式的“类型”描述。物体是他们的实现:活生生的呼吸物。在面向对象的世界中,有一些主要的想法,你几乎可以称之为一切的本质。他们是:
对象具有一个或多个特征(=属性)和行为(=方法)。行为主要取决于特征。 类定义了行为应该以一般方式完成的内容,但只要该类未被实现(实例化)为对象,它仍然是一种可能性的抽象概念。 让我借助“继承”和“多态”来说明。
class Human:
gender
nationality
favorite_drink
core_characteristic
favorite_beverage
name
age
def love
def drink
def laugh
def do_your_special_thing
class Americans(Humans)
def drink(beverage):
if beverage != favorite_drink: print "You call that a drink?"
else: print "Great!"
class French(Humans)
def drink(beverage, cheese):
if beverage == favourite_drink and cheese == None: print "No cheese?"
elif beverage != favourite_drink and cheese == None: print "Révolution!"
class Brazilian(Humans)
def do_your_special_thing
win_every_football_world_cup()
class Germans(Humans)
def drink(beverage):
if favorite_drink != beverage: print "I need more beer"
else: print "Lecker!"
class HighSchoolStudent(Americans):
def __init__(self, name, age):
self.name = name
self.age = age
jeff = HighSchoolStudent(name, age):
hans = Germans()
ronaldo = Brazilian()
amelie = French()
for friends in [jeff, hans, ronaldo]:
friends.laugh()
friends.drink("cola")
friends.do_your_special_thing()
print amelie.love(jeff)
>>> True
print ronaldo.love(hans)
>>> False
某些特征定义了人类。但每个国籍都有所不同。因此,“国家类型”是有点额外的人类。 “美国人”是一种“人类”,并从人类(基类)继承了一些抽象的特征和行为:这是继承。因此,所有人类都可以笑喝,因此所有的儿童班也可以!继承(2)。
但是因为它们都是同一类型(类型/基类:人类),你有时可以交换它们:最后看到for循环。但是它们会暴露出个体特征,那就是多态性(3)。
所以每个人都有一个喜欢的饮料,但每个国家都倾向于一种特殊的饮料。
如果您从人类类型中继承国籍,则可以覆盖继承的行为,如上面使用drink()
方法演示的那样。
但这仍然处于阶级水平,因此它仍然是一种概括。
hans = German(favorite_drink = "Cola")
实例化德语类,我在开头“改变”了默认特征。 (但如果你打电话给hans.drink('牛奶'),他仍会打印“我需要更多啤酒” - 这是一个明显的错误......或者如果我是一家大公司的员工,这就是我所说的功能。 ;-)! )
一种类型的特征,例如德国人(hans)通常在实例化时通过构造函数(在python:__init__
中)定义。这是您将类定义为对象的点。你可以通过填充个人特征并成为一个对象,将呼吸生命描述为抽象概念(类)。
但是因为每个对象都是一个类的实例,所以它们共享所有一些基本的特征类型和一些行为。这是面向对象概念的主要优点。
为了保护封装它们的每个对象的特性 - 意味着您尝试将行为和特征耦合在一起,并且难以从对象外部操纵它。这是封装(1)
答案 2 :(得分:5)
只是初始化实例的变量。
E.g。创建一个具有特定数据库名称的crawler
实例(来自上面的示例)。
答案 3 :(得分:3)
关注您的汽车示例:当您开车时,您只是没有随机购买汽车,我的意思是,您选择的颜色,品牌,座位数等等。有些东西也是“初始化”而你没有选择它,比如轮数或注册号。
class Car:
def __init__(self, color, brand, number_of_seats):
self.color = color
self.brand = brand
self.number_of_seats = number_of_seats
self.number_of_wheels = 4
self.registration_number = GenerateRegistrationNumber()
因此,在__init__
方法中,您可以定义要创建的实例的属性。所以,如果我们想要一辆蓝色雷诺汽车,对于2个人,我们会初始化或Car
的实例,如:
my_car = Car('blue', 'Renault', 2)
这样,我们正在创建Car
类的实例。 __init__
是处理我们的特定属性(例如color
或brand
)并生成其他属性的registration_number
,如{{1}}。
__init__
method 答案 4 :(得分:3)
类是具有属性(状态,特征)和特定于该对象的方法(函数,容量)的对象(如鸭子的白色和苍蝇力)。
当你创建一个类的实例时,你可以给它一些初始的个性(状态或字符,如新生儿的名字和颜色)。您可以使用__init__
执行此操作。
基本上__init__
会在您调用instance = MyClass(some_individual_traits)
时自动设置实例特征。
答案 5 :(得分:3)
如果要正确初始化实例的可变属性,似乎需要在Python中使用__init__
。
请参阅以下示例:
>>> class EvilTest(object):
... attr = []
...
>>> evil_test1 = EvilTest()
>>> evil_test2 = EvilTest()
>>> evil_test1.attr.append('strange')
>>>
>>> print "This is evil:", evil_test1.attr, evil_test2.attr
This is evil: ['strange'] ['strange']
>>>
>>>
>>> class GoodTest(object):
... def __init__(self):
... self.attr = []
...
>>> good_test1 = GoodTest()
>>> good_test2 = GoodTest()
>>> good_test1.attr.append('strange')
>>>
>>> print "This is good:", good_test1.attr, good_test2.attr
This is good: ['strange'] []
这在Java中是完全不同的,其中每个属性都使用新值自动初始化:
import java.util.ArrayList;
import java.lang.String;
class SimpleTest
{
public ArrayList<String> attr = new ArrayList<String>();
}
class Main
{
public static void main(String [] args)
{
SimpleTest t1 = new SimpleTest();
SimpleTest t2 = new SimpleTest();
t1.attr.add("strange");
System.out.println(t1.attr + " " + t2.attr);
}
}
产生我们直观期望的输出:
[strange] []
但是如果你将attr
声明为static
,它将像Python一样:
[strange] [strange]
答案 6 :(得分:2)
__init__
函数正在设置类中的所有成员变量。因此,一旦创建了bicluster,您就可以访问该成员并获得一个值:
mycluster = bicluster(...actual values go here...)
mycluster.left # returns the value passed in as 'left'
查看Python Docs以获取一些信息。你想拿起一本关于OO概念的书来继续学习。
答案 7 :(得分:1)
class Dog(object):
# Class Object Attribute
species = 'mammal'
def __init__(self,breed,name):
self.breed = breed
self.name = name
在上面的例子中,我们使用物种作为全局物种,因为它总是相同的(你可以说是一种常数)。当你调用__init__
方法时,__init__
内的所有变量都将被启动(例如:品种,名称)。
class Dog(object):
a = '12'
def __init__(self,breed,name,a):
self.breed = breed
self.name = name
self.a= a
如果您通过以下方式调用上面的示例打印上面的
Dog.a
12
Dog('Lab','Sam','10')
Dog.a
10
这意味着它只会在对象创建期间初始化。所以你想要声明为常量的东西使它成为全局的,任何改变的东西都使用__init__