__init__()内部和外部变量的差异(类和实例属性)

除了名字以外,这些类之间有什么不同吗?

class WithClass ():
def __init__(self):
self.value = "Bob"
def my_func(self):
print(self.value)


class WithoutClass ():
value = "Bob"


def my_func(self):
print(self.value)

如果我使用或不使用__init__方法来声明变量value,会有任何区别吗?

我主要担心的是,我只会以一种方式使用它,而这会给我带来更多的问题。

183512 次浏览

__init__之外设置的变量属于类。它们由所有实例共享。

__init__(以及所有其他方法函数)中创建并以self.开头的变量属于对象实例。

根据S.Lott的回答,类变量被传递给元类方法,并且可以在定义元类时通过字典访问。因此,即使在创建和实例化类之前,也可以访问类变量。

例如:

class meta(type):
def __new__(cls,name,bases,dicto):
# two chars missing in original of next line ...
if dicto['class_var'] == 'A':
print 'There'
class proxyclass(object):
class_var = 'A'
__metaclass__ = meta
...
...

没有自我

创建一些对象:

class foo(object):
x = 'original class'


c1, c2 = foo(), foo()

我可以改变c1实例,它不会影响c2实例:

c1.x = 'changed instance'
c2.x
>>> 'original class'

但是如果我改变了foo类,该类的所有实例也会被改变:

foo.x = 'changed class'
c2.x
>>> 'changed class'

请注意Python作用域是如何工作的:

c1.x
>>> 'changed instance'

与自我

改变类不会影响实例:

class foo(object):
def __init__(self):
self.x = 'original self'


c1 = foo()
foo.x = 'changed class'
c1.x
>>> 'original self'

我想在这个线程和这个线程(引用这个线程)中读到的响应中添加一些东西。

免责声明:这句话来自我运行的实验

__init__之外的变量:

实际上,它们是静态类变量,因此该类的所有实例都可以访问。

__init__中的变量:

这些实例变量的值只能被手边的实例访问(通过self引用)。

我的贡献:

程序员在使用静态类变量时必须考虑的一件事是,他们可能会被实例变量遮蔽(如果你通过self引用访问静态类变量)。

解释:

以前,我认为这两种声明变量的方式是完全相同的(我真傻),这部分是因为我可以通过self引用访问这两种变量。就是现在,当我遇到麻烦时,我研究了这个话题,并把它弄清楚了。

参数访问静态类变量的问题 self引用只有在没有同名的实例变量时才会引用静态类变量,更糟糕的是,试图通过self引用重新定义静态类变量是行不通的,因为创建的实例变量会掩盖先前可访问的静态类变量

为了解决这个问题,你应该总是通过类名引用静态类变量

例子:

#!/usr/bin/env python


class Foo:
static_var = 'every instance has access'


def __init__(self,name):
self.instance_var = 'I am %s' % name


def printAll(self):
print 'self.instance_var = %s' % self.instance_var
print 'self.static_var = %s' % self.static_var
print 'Foo.static_var = %s' % Foo.static_var


f1 = Foo('f1')


f1.printAll()


f1.static_var = 'Shadowing static_var'


f1.printAll()


f2 = Foo('f2')


f2.printAll()


Foo.static_var = 'modified class'


f1.printAll()
f2.printAll()

输出:

self.instance_var = I am f1
self.static_var = every instance has access
Foo.static_var = every instance has access
self.instance_var = I am f1
self.static_var = Shadowing static_var
Foo.static_var = every instance has access
self.instance_var = I am f2
self.static_var = every instance has access
Foo.static_var = every instance has access
self.instance_var = I am f1
self.static_var = Shadowing static_var
Foo.static_var = modified class
self.instance_var = I am f2
self.static_var = modified class
Foo.static_var = modified class

我希望这对某些人有所帮助

class User(object):
email = 'none'
firstname = 'none'
lastname = 'none'


def __init__(self, email=None, firstname=None, lastname=None):
self.email = email
self.firstname = firstname
self.lastname = lastname


@classmethod
def print_var(cls, obj):
print ("obj.email obj.firstname obj.lastname")
print(obj.email, obj.firstname, obj.lastname)
print("cls.email cls.firstname cls.lastname")
print(cls.email, cls.firstname, cls.lastname)


u1 = User(email='abc@xyz', firstname='first', lastname='last')
User.print_var(u1)

在上面的代码中,User类有3个全局变量,每个变量的值都是“none”。U1是通过实例化该类创建的对象。print_var方法输出User类变量的值和u1对象变量的值。在下面的输出中,每个类变量User.emailUser.firstnameUser.lastname的值都是'none',而对象变量u1.emailu1.firstnameu1.lastname的值是'abc@xyz''first''last'

obj.email obj.firstname obj.lastname
('abc@xyz', 'first', 'last')
cls.email cls.firstname cls.lastname
('none', 'none', 'none')

如果跟踪类和实例字典,这很容易理解。

class C:
one = 42
def __init__(self,val):
self.two=val
ci=C(50)
print(ci.__dict__)
print(C.__dict__)

结果是这样的:

{'two': 50}
{'__module__': '__main__', 'one': 42, '__init__': <function C.__init__ at 0x00000213069BF6A8>, '__dict__': <attribute '__dict__' of 'C' objects>, '__weakref__': <attribute '__weakref__' of 'C' objects>, '__doc__': None}

注意,我在这里设置了完整的结果,但重要的是,实例ci字典将只是{'two': 50},类字典将有'one': 42键值对在里面。

这是关于特定变量的所有信息。

类就像创建对象的蓝图。让我们用建房子来做个比喻。你有房子的蓝图,所以你可以建造房子。你可以在资源允许的情况下建造尽可能多的房子。

在这个比喻中,蓝图是类,房子是类的实例化,创建一个对象。

这些房子有共同的属性,比如有屋顶、客厅等。这就是初始化方法的作用。它用你想要的属性构造对象(房子)。

让我们假设你有:

`class house:`
`roof = True`
`def __init__(self, color):`
`self.wallcolor = color`

>> create little goldlock's house:

>> goldlock = house() #() invoke's class house, not function


>> goldlock.roof


>> True


all house's have roofs, now let's define goldlock's wall color to white:


>> goldlock.wallcolor = 'white'
>>goldlock.wallcolor
>> 'white'

在Python中,类带有成员函数(方法)类变量属性/实例变量(可能还有类方法):

class Employee:


# Class Variable
company = "mycompany.com"


def __init__(self, first_name, last_name, position):
# Instance Variables
self._first_name = first_name
self._last_name = last_name
self._position = position


# Member function
def get_full_name(self):
return f"{self._first_name} {self._last_name}"

通过创建对象的实例

my_employee = Employee("John", "Wood", "Software Engineer")

我们实际上触发了__init__,它将初始化新创建的Employee实例变量。这意味着_first_name_last_name_position是特定my_employee实例的显式参数。

同样,成员函数返回信息或改变特定实例的状态。


现在,在构造函数__init__之外定义的任何变量都被认为是类变量。这些变量在类的所有实例之间共享。

john = Employee("John", "Wood", "Software Engineer")
bob = Employee("Bob", "Smith", "DevOps Engineer0")


print(john.get_full_name())
print(bob.get_full_name())
print(john.company)
print(bob.company)


>>> John Wood
>>> Bob Smith
>>> mycompany.com
>>> mycompany.com

你也可以使用类方法来改变类的所有实例的类变量。例如:

@classmethod
def change_my_companys_name(cls, name):
cls.company = name

现在是change_my_companys_name()

bob.change_my_companys_name("mynewcompany.com")

将对类Employee的所有实例产生影响:

print(bob.company)
print(john.company)


>>> mynewcompany.com
>>> mynewcompany.com
class foo(object):
mStatic = 12


def __init__(self):
self.x = "OBj"

考虑到foo根本无法访问x(事实)

现在的冲突是通过实例或直接通过类访问mStatic。

从Python内存管理的角度来考虑:

12的值在内存中,名称mStatic(可以从类中访问)

指向它。

c1, c2 = foo(), foo()

这一行创建了两个实例,其中包括指向值12的名称mStatic(到目前为止)。

foo.mStatic = 99

这使得mStatic name指向内存中值为99的新位置。

因为(婴儿)c1 c2仍然在(爸爸)foo后面,所以它们有相同的名字(c1。mStatic,c2。mStatic)指向相同的新值。

但一旦每个宝宝决定独自走路,情况就不同了:

c1.mStatic ="c1 Control"
c2.mStatic ="c2 Control"

从现在到以后,该家族中的每一个(c1,c2,foo)都有它的mStatica指向不同的值。

[请尝试使用id()函数为所有(c1,c2,foo)在不同的状态,我们谈到,我认为这将使事情更好]

这就是我们真实的生活。儿子从父亲那里继承了一些信仰,这些信仰在儿子决定改变之前仍然与父亲的信仰相同。

希望对大家有所帮助

示例代码:

class inside:
def __init__(self):
self.l = []


def insert(self, element):
self.l.append(element)




class outside:
l = []             # static variable - the same for all instances


def insert(self, element):
self.l.append(element)




def main():
x = inside()
x.insert(8)
print(x.l)      # [8]
y = inside()
print(y.l)      # []
# ----------------------------
x = outside()
x.insert(8)
print(x.l)      # [8]
y = outside()
print(y.l)      # [8]           # here is the difference




if __name__ == '__main__':
main()

正如S.Lott所指出的,

初始化之外设置的变量属于类。它们由 所有实例。< / p >

初始化(和所有其他方法函数)中创建的变量和 以自我开头。

.属于对象实例
< p > 然而, 注意,类变量可以通过self.<var>直到它们被具有类似名称的对象变量所掩盖这意味着读取self.<var>在给它赋值之前,将返回Class.<var>但之后它会返回obj.<var>. 下面是一个例子

In [20]: class MyClass:
...:     elem = 123
...:
...:     def update(self,i):
...:         self.elem=i
...:     def print(self):
...:         print (MyClass.elem, self.elem)
...:
...: c1 = MyClass()
...: c2 = MyClass()
...: c1.print()
...: c2.print()
123 123
123 123
In [21]: c1.update(1)
...: c2.update(42)
...: c1.print()
...: c2.print()
123 1
123 42
In [22]: MyClass.elem=22
...: c1.print()
...: c2.print()
22 1
22 42

第二请注意:考虑。它们可能提供了更好的实现对象变量的方法。

试试这个,看看有什么不同

class test:
f = 3


def __init__(s, f):
s.__class__.f = f
s.f = s.__class__.f
print(f'def __init__(s, {f})')
print(f's.__class__.f = {f}')
print(f's.f={s.__class__.f}')
print(f'f={f}')
print('===============init over===========')


def setinstancetoOne(s, f):
print(f'def setinstancetoOne(s, {f})')
s.f = f


print(f'class var f = {f}')


def useClassname(test):
print(f'>>>>def useClassname({test})')
print(f'test.f {test.f}')


def p_method(s):
print(f'>>>>def p_method({s})')
print(f's.f {s.f}')
print(f'test.f {test.f}')
print(f's.__class__.f {s.__class__.f}')


print(f'class var f={f}')




# test.__init__.f = 19
t = test(2)
t.useClassname()
t.p_method()
print(f'Outside class t.f {t.f}')
print(f'Outside class test.f {test.f}')


print('______difference__________')
t = test(2)
t.setinstancetoOne(1)
t.useClass()
t.p_method()
print(f'Outside class instance variable(2) {t.f}')
print(f'Outside class class variable(3) {test.f}')