一、成员
(一)变量
实例变量:属于对象,每个对象中各自维护自己的数据。
类变量:属于类,可以被所有对象共享,一般用于给对象提供公共数据(类似于全局变量)。
类变量和实例变量的区别示例:
class Person:
country = "中国"
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
message = "我的名字是{},我的年龄是{},我是{}人".format(self.name, self.age, Person.country)
message_ = "我的名字是{},我的年龄是{},我是{}人".format(self.name, self.age, self.country)
print(message_)
#country是类变量,但是由于self对象没有country,所以会通过调用实例变量来调用类变量
print(Person.country)
#中国
p1 = Person("高宇星", 18)
p1.show()
类变量和实例变量+继承问题:
class Base(object):
country = "中国"
class Person(Base):
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
message = "我的名字是{},我的年龄是{},我是{}人".format(self.name, self.age, Person.country)
message_ = "我的名字是{},我的年龄是{},我是{}人".format(self.name, self.age, self.country)
print(message_)
# country是类变量,但是由于self对象没有country,所以会通过调用实例变量来调用类变量
p2 = Person("闫曦月", 18)
p2.show()
#我的名字是闫曦月,我的年龄是18,我是中国人
print(p2.name)#闫曦月
print(p2.age)#18
print(p2.country)#中国
print(Person.country)#中国
print(Base.country)#中国
通常来说,调用的变量不是对象变量时,就会去对应的类中找类变量,如果类变量中仍然不存在,就会向上去父类中寻找变量。
class Base(object):
country = "美国"
class Person(Base):
country = "泰国"
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
message = "我的名字是{},我的年龄是{},我是{}人".format(self.name, self.age, Person.country)
message_ = "我的名字是{},我的年龄是{},我是{}人".format(self.name, self.age, self.country)
print(message_)
# country是类变量,但是由于self对象没有country,所以会通过调用实例变量来调用类变量
p2 = Person("闫曦月", 18)
p2.show()
#我的名字是闫曦月,我的年龄是18,我是泰国人
print(p2.name)#闫曦月
print(p2.age)#18
print(p2.country)#泰国
print(Person.country)#泰国
print(Base.country)#美国
当Base父类中的country变成“泰国”、Person类中的country变成“美国”时,调用P2实例对象的country时会找到类变量,答案为“美国”,只有调用Base类的变量country时,才会出现“泰国”。
(二)方法
一共有三种方法:绑定方法、类方法和静态方法
- 绑定方法:默认参数为self;
- 类方法:@classmethod、默认参数为cls;
- 静态方法:@staticmethod,没有默认参数。
python中比较灵活,三种方法均可以通过对象和类进行调用。
class Foo(object):
def __init__(self, name):
self.name = name
def f1(self):
print("绑定方法", self.name)
@classmethod
def f2(cls):
print("类方法",cls)
@staticmethod
def f3():
print("静态方法")
#绑定方法执行方式
obj = Foo("高宇星")
obj.f1()#绑定方法 高宇星
Foo.f1(obj) #非主流的执行方式 绑定方法 高宇星
#类方法执行方式
Foo.f2() #主流方式,直接通过类来实现,其中cls参数代表的就是Foo这个类
#类方法 <class '__main__.Foo'>
obj.f2() #非主流执行方式,通过对象来实现
#类方法 <class '__main__.Foo'>
#静态方法的执行方式
Foo.f3() #主流执行方式,通过类来调用
#静态方法
obj.f3() #主流执行方式,通过类来调用
#静态方法
具体应该使用哪种方法,具体还需要看涉及到哪些内容,如果需要传入对象,那就使用绑定方法,如果需要传入类,那就使用类方法,如果什么都不需要传入,就需要静态方法。
(三)属性
属性是由绑定方法+特殊装饰器组合而成的,主要的区别是:调用方法的时候需要加括号,调用属性的时候不需要加括号。
class Foo():
def __init__(self, name):
self.name = name
def f1(self):
return print(123)
@property
def f2(self):
return print(123)
obj = Foo("闫曦月")
obj.f1()
#123
obj.f2
#123
在分页显示案例中,同样是在绑定方法基础上加上了@property之后,在调用start和end时可以省略掉括号。
class Pagination():
def __init__(self, current_page, per_page_num=10):
self.per_page_num = per_page_num
if current_page < 1:
self.current_page = 1
return
self.current_page = current_page
#如果加上@property,在下面调用的时候就可以不加括号了,简洁代码(小小的简洁)
@property
def start(self):
return (self.current_page-1) * self.per_page_num
@property
def end(self):
return self.current_page * self.per_page_num
user_list = ["用户-{}".format(i) for i in range(1, 3000)]
#分页现实,每页显示10条
while True:
page = int(input("请输入页码:"))
print(type(page))
page_object = Pagination(page, 20)
page_object_list = user_list[page_object.start: page_object.end]
for item in page_object_list:
print(item)
关于属性的编写方式由两种:
- 基于装饰器
class C(object):
@property
def nnn(self):
pass
@nnn.setter
def nnn(self, value):
pass
@nnn.deleter
def nnn(self):
pass
obj = C()
#触发nnn属性
obj.nnn
#触发nnn.setter,给该属性传入参数value=123
obj.nnn = 123
#触发nnn.deleter,删除nnn属性
del obj.nnn
- 基于定义变量
class C(object):
def nnn(self):
print('666')
def setnnn(self, value):
print(value)
def delnnn(self):
print('delete')
x = property(nnn, setnnn, delnnn, "I'm the nnn property")
#第四个参数是注释,等同于‘’‘I'm the nnn property’‘’
obj = C()
obj.x #666
obj.x = 333
#333
del obj.x
#delete
也可以将方法定义成属性中的变量,在执行方法时会自动触发可以使用的属性。
补充:为了避免报错,属性和实例名不能相同
以下是错误示例:报错原因是,代码以为我要调用@name.setter装饰方法。
class Foo(object):
def __init__(self, name, age):
self.name = name
self.age = age
@property
def name(self):
return '{}-{}'.format(self.name, self.age)
obj = Foo("高宇星", 24)
改进,增加一个@name.setter装饰器,增加之后不会因为属性和实例名字相同而报错,但是会因为循环调用自己,一直递归导致层次太深而报错。
下面这个例子就是很好的说明,当实例化对象时,自然会用到name这个参数,由于参数name和属性name名字相同,触发了@name.setter,print一下value后就没了,但是此时就会调用属性name,在属性name中又有self.name, 又一次触发@name.setter,循环往复,不停进行递归运算。
class Foo(object):
def __init__(self, name, age):
self.name = name
self.age = age
@property
def name(self):
return '{}-{}'.format(self.name, self.age)
@name.setter
def name(self, value):
print(value)
obj = Foo("高宇星", 24)
如果想让属性和实例上存在一些关联,就可以按照以下方式改进。在实例变量前面加一个_,这样实例变量就变成了_name,属性名字叫name,这样就不冲突了。
class Foo(object):
def __init__(self, name, age):
self._name = name
self.age = age
@property
def name(self):
print('{}-{}'.format(self._name, self.age))
obj = Foo("高宇星", 24)
obj.name
#高宇星-24
二、成员修饰符
python成员的修饰指的是:公有or私有文章来源:https://www.toymoban.com/news/detail-832474.html
- 公有: 在任何地方都可以调用成员
- 私有:只有类的内部才可以调用成员(成员是以两个下划线开头,则表示该成员为私有)
1、示例一:私有对象和公有对象
(实例对象)对于私有成员__name来说,只能在内部调用,但是对于共有成员age来说,内部和外部都能调用。对于类对象来说也是同样的!文章来源地址https://www.toymoban.com/news/detail-832474.html
class Foo(object):
def __init__(self, name, age):
self.__name = name
self.age = age
def get_data(self):
return self.__name
def get_age(self):
return self.age
obj = Foo("闫曦月", 18)
print(obj.age) #18
#obj.__name age可以调用查看,但是__name是私有的,无法在类的外部进行调用
name = obj.get_data()
#在调用get_data方法时,由于该方法前面没有双下划线,所以是可以在类的外部进行调用的,在方法里面调用私有成员,这样是可以的
print(name) #闫曦月
age = obj.get_age()
print(age)
#18
2、示例二:私有方法和公有方法
class Foo():
def get_age(self):
print("公有的get_age")
def __get_data(self):
print("私有的__get_data")
def proxy(self):
print("公有的proxy")
self.__get_data()
obj = Foo()
obj.get_age() #公有的get_age
obj.proxy()
'''
公有的proxy
私有的__get_data
'''
3、示例三:私有属性和公有属性
class Foo():
@property
def __name(self):
print("私有的属性__name")
@property
def proxy(self):
self.__name
return 1
obj = Foo()
print(obj.proxy)
'''
私有的属性__name
1
'''
4、特别提示:如果存在继承关系,那么父类中的私有成员,子类无法继承
class Base():
def __data(self):
print("base.__data")
def num(self):
print("base.num")
class Foo(Base):
def func(self):
self.num()
self.__name()
obj = Foo()
obj.func()
'''
Traceback (most recent call last):
File "/Users/gaoyuxing/PycharmProjects/Django_learning/3.2.py", line 311, in <module>
obj.func()
File "/Users/gaoyuxing/PycharmProjects/Django_learning/3.2.py", line 308, in func
self.__name()
AttributeError: 'Foo' object has no attribute '_Foo__name'
'''
到了这里,关于【python全栈开发】面向对象进阶的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!