设为首页 加入收藏

TOP

Python面向对象:杂七杂八的知识点(二)
2019-01-16 14:08:44 】 浏览:379
Tags:Python 面向 对象 杂七杂八 知识点
样解释成对象自身,换句话说只能传递一个参数c.m2("arg2"),这显然有悖静态方法的编码方式。

python中,要定义严格的类方法、静态方法,需要使用内置的装饰器函数classmethod()、staticmethod()来装饰,装饰后无论使用对象名去调用还是使用类名去调用,都可以。

例如:

class cls():
    def m1(self,arg1):
        print("m1: ", self, arg1)
    @classmethod
    def m2(self,arg1):
        print("m2: ", self, arg1)
    @staticmethod
    def m3(arg1, arg2):
        print("m3: ", arg1, arg2)

上面定义了普通方法、类方法和静态方法。如果尚不了解装饰器的用法,暂时只需知道上面的@xxx将它下面的函数(方法)扩展成了类方法、静态方法即可。

调用实例方法:

>>> c = cls()
>>> c.m1("hello")
m1:  <__main__.cls object at 0x000001EE2DA840B8> hello

注意输出的self是"...object...",和下面的类方法调用注意区分比较。

调用类方法。因为@classmethod已经将m2包装成了类方法,所以m2的第一个self参数将总是代表类名,而无论是使用对象去调用m2还是使用类名去调用m2。

>>> c.m2("hello")
m2:  <class '__main__.cls'> hello

>>> cls.m2("hello")
m2:  <class '__main__.cls'> hello

如果输出m2方法,会发现它已经是绑定方法,也就是说和类名进行了绑定(这里不是和对象名进行绑定)。

>>> c.m2
<bound method cls.m2 of <class '__main__.cls'>>

>>> cls.m2
<bound method cls.m2 of <class '__main__.cls'>>

调用静态方法。

>>> c.m3("hello","world")
m3:  hello world
>>> cls.m3("hello","world")
m3:  hello world

静态方法都是未绑定的函数:

>>> c.m3
<function cls.m3 at 0x000001EE2DA789D8>
>>> cls.m3
<function cls.m3 at 0x000001EE2DA789D8>

一般来说,类方法用于在类中操作/返回和类名有关的内容,静态方法用于在类中做和类或对象完全无关的操作。一个比较好理解的例子是,一个Employee类,要检查员工的年龄范围在16-35,如果年龄在这范围内,就返回一个员工对象,可以将这个逻辑定义为类方法。如果只是检查年龄范围来决定True或False这样和类/对象无关的操作,则定义为静态方法。

class Employee:
    @staticmethod
    def age_ok(age):
        if 16<age<35:
            return True
        else:
            return False

    @classmethod
    def age_check(cls, age):
        if 16<age<35:
            return cls(...)

私有属性

python没有private关键字来修饰属性使其变成私有属性,但是带上双下划线前缀的属性且没有后缀下划线的属性(__X)可以认为是私有属性。它仅仅只是约定性的私有属性,不代表外界真的不能访问。

实际上,使用__X这样的属性,在类的内部访问时会自动进行扩展为_clsname__X,也就是加个前缀下划线,再加个类名。因为扩展时加上了类名,使得这个属性在名称上是独属于这个类的。

例如:

class cls():
    __X = 12
    def m1(self,y):
        self.__Y = y
        print(self.__X)
        print(self.__Y)

>>> print(cls.__dict__.keys())
dict_keys([..., '_cls__X', 'm1', ....])

>>> c = cls()
>>> c.m1(22)
12
22
>>> print(c.__dict__.keys())
dict_keys(['_cls__Y'])

因为已经扩展了属性的名称,所以无法在类的外界通过直接的名称__X去访问对应的属性。

>>> c.__Y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'cls' object has no attribute
'__Y'
>>> c.__X
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'cls' object has no attribute
'__X'

>>> cls.__X
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'cls' has no attribute '__X'

前面说了,这种加双下划线前缀的属性仅仅只是一个约定形式,虽然在外界无法直接通过名称去访问,但是仍有不少方法去访问。例如通过扩展后的名称、通过字典__dict__

>>> cls._cls__X
12
>>> c._cls__Y
22
>>> c.__dict__['_cls__Y']
22

要想严格地声明属性的私有性,可以编写装饰器类,在装饰器类中完成属性的判断。

方法的默认可变参数陷阱

如果一个方法的参数给了默认参数,且这个默认参数是一个可变类型,那么这里有一个陷阱:使用这个默认参数的时候各对象会共享这个可变默认值。

例如:

class A:
    def __init__(self, arg=[]):
        self.data = arg
    def add(self, value):
        self.data.append(value)

# 两个不同对象,且都使用参数arg的默认值
a1
首页 上一页 1 2 3 4 5 下一页 尾页 2/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Python爬虫入门教程 25-100 知乎.. 下一篇我的Python分析成长之路8

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目