文章目录
静态方法和类方法
1.静态方法
- 通过装饰器
@staticmethod
来进行装饰。静态方法既不需要传递对象也不需要传递实例对象 - 静态方法也可以通过实例对象和类对象去访问
class Dog:
type = '狗'
def __init__(self):
name = None
#静态方法
@staticmethod
def introduce(): #静态方法不会自动传递实例对象和类对象
print('犬科哺乳动物,属于食肉目')
dog = Dog()
Dog.introduce()
dog.introduce()
静态方法是类中的函数,不需要实例。
静态方法主要是用来存放逻辑性代码,逻辑上属于类,但和类本身没有关系,也就是说,在静态方法中,不会涉及类中属性和方法的操作。
可以理解为,静态方法是一个独立的,单纯的函数,仅仅是托管于某个类的名称空间中,便于维护和管理。
使用场景:
- 当方法中 既不需要使用实例对象(如实例对象,实例属性),也不需要使用类对象 (如类属性、类方法、创建实例等)时,定义静态方法
- 取消不需要的参数传递,有利于 减少不必要的内存占用和性能消耗
- 如果在类外面写一个同样的函数来做这些事,打乱了逻辑关系,导致代码维护困难,使用静态方法。
类方法
- 类对象所拥有的方法
- 需要用装饰器
@classmethod
来标识其为类方法。 - 对于类方法,第一个参数必须是类对象,一般以
cls
作为第一个参数
class Dog:
__type = '狗'
#类方法,用class来进行装饰
@classmethod
def get_type(cls):
return cls.__type
print(Dog.get_type())
狗
使用场景:
- 当方法中需要使用类对象(如访问私有属性等)时,定义类方法。
- 类方法一般和类属性配合使用。
注意:
类中定义了同名的对象方法,类方法以及静态方法时,调用方法优先执行最后定义的方法
class Dog:
def demo_method(self):
print('对象方法')
@classmethod
def demo_method(cls):
print('类方法')
@staticmethod
def demo_method(): # 最后被定义,调用时优先执行
print('静态函数')
dog = Dog()
Dog.demo_method()
dog.demo_method()
#输出
静态函数
静态函数
property
概述
在python中只要为属性提供一个便利的操作方式。
例1.如果我们现在需要设计一个银行的账户类,这个类中包含账户人的姓名,余额。
-
如果只是简单的实现
class Account: def __init__(self,name,money): self.name = name self.mpney = money
这样设计的问题是 不安全(设计很简单,所有的属性,外部都可以访问修改)
改进1
-
隐藏实现细节
对于账户信息而言,金额不允许让用户直接修改。在使用对象时,尽量不要让使用者直接操作对象中的属性。
因此考虑 私有属性
class Account: def __init__(self,name,money): self.__name = name self.__money = money
将所有的属性设计成私有属性后,从外部使用时,不知道内部属性,不能直接修 改对象。
改进2
当需要对这两个属性进行修改是,提供一个精确的访问,添加方法访问私有属性
class Account:
def __init__(self,name,money):
self.__name = name
self.__balance = money
def get_name(self):
return self.__name
def set_balance(self,money):
self.__balance = money
def get_balance(self):
return self.__balance
-
经过修改,外部使用这个类的对象时,想使用对象中的属性,只能通过类中提供的 set/get 接口来操作,提高了程序的安全性。
这样,程序基本达到了设计需求,但是能不能更加完善呢?
如果在使用这个类的对象过程中,由于误操作,传入了不正常的数据,导致数据异常。该如何以避免这种情况发生呢?
比如:设置金额时出现了负数,或字符串,或其它类型的对象。
改进3 保证数据的有效性
class Account:
def __init__(self,name,money):
self.__name = name
self.__balance = money
def get_name(self):
return self.__name
def set_balance(self,money):
if isinstance(money, int):
if money > 0:
self.__balance = money
else:
raise ValueError('输入金额不对')
else:
raise ValueError('输入金额不对')
def get_balance(self):
return self.__balance
经过几个版本的迭代,程序看上去越来越健壮,安全性也越来越高
但是在使用过程中,可以更精炼一些
改进4 属性操作
在python中,提供了一个property类,通过对撞见这个类的对象的设置,在使用对象的稀有属性时,可以不在使用属性的函数的调用方式,而是像普通的公有属性一样去使用属性,为开发者提供便利。
property(fget = None, fest=None, fdel=None, doc=None) #property attribute
property是一个类,__init__
方法由四个参数组成,实例后返回一个用来操作属性的对象
参数一:属性的获取方法
参数二:属性的设置方法
参数三:属性的删除方法
参数四:属性描述
class Account:
def __init__(self,name,money):
self.__name = name
self.__balance = money
def __get_name(self):
return self.__name
def set_balance(self,money):
if isinstance(money, int):
if money > 0:
self.__balance = money
else:
raise ValueError('输入金额不对')
else:
raise ValueError('输入金额不对')
def get_balance(self):
return self.__balance
name = property(__get_name)
balance = property(get_balance,set_balance)
ac = Account('Tom',10000)
print(ac.name)
print(ac.balance)
通过 property 类实例对象以后,在使用对象中的属性时,就可以像使用普通公有属性一样来调用,但是实际调用的还是 set/get 方法。 在实例 property 对象时,不是所有的参数都需要写,比如示例中的 name 只提供了 get 方法,并且是一个私有的方法。这样就完全隐藏了内部的实现细节 。
@property
装饰
class Account:
def __init__(self,name,money):
self.__name = name
self.__balance = money
@property
def name(self):
return self.__name
@property
def balance(self):
return self.__balance
@balance.setter
def balance(self,money):
if isinstance(money, int):
if money > 0:
self.__balance = money
else:
raise ValueError('输入金额不对')
else:
raise ValueError('输入金额不对')
ac = Account('Tom',10000)
print(ac.name)
print(ac.balance)
self
如果对象的方法中需要使用该对象的属性,该怎么办?
-
关键字
self
主要用于对象方法中,表示调用该方法的对象。 -
在方法中使用self,可以获取到调用当前方法的对象,进而获取该对象的属性和方法。
调用对象的方法时,为什么不用设置self对应的参数?
- 某个对象调用其方法时,python解释器会把这个对象作为第一个参数传递给方法,所以,开发者只需要在定义的时候"预留第一个参数self即可"
class Cat:
# 方法
def introduce(self):
print('name is %s ,age is %d' % (self.name, self.age))
#实例化创建一个对象
cat = Cat()
cat.name = 'lanmao'
cat.age = 6
cat.introduce()
#输出
name is lanmao ,age is 6
方法内定义属性
-
使用self操作属性和对象的变量名在效果上类似。如果属性在赋值时还没有被定义。就会自动定义一个属性并赋值。
-
class Cat: def introduce(self): self.type = "小型动物" cat = Cat() cat.introduce() print(cat.type)
__new__
方法
- 创建对象时,系统会自动调用
__new__
方法。 - 开发者可以使用该方法来自定义对象的创建过程。
__new__
至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供__new__
必须要有返回值,返回实例化出来的实例,这点在自己实现__new__
时要特别注意,可以return父类__new__
出来的实例,或者直接是object的__new__
出来的实例__init__
有一个参数self,就是这个__new__
返回的实例,__init__
在__new__
的基础上可以完成一些其它初始化的动作,__init__
不需要返回值- 如果创建对象时传递了自定义参数,且重写了
__new__
方法,则new也必须 “预留” 该形参,否则__init__
方法将无法获取到该参数
class A(object):
def __new__(cls, x):
print ('this is in A.__new__, and x is ', x)
return super(A, cls).__new__(cls)
def __init__(self, y):
print ('this is in A.__init__, and y is ', y)
class C(object):
def __new__(cls, n):
print ('this is in C.__new__, and n is ', n)
return super(C, cls).__new__(cls)
def __init__(self, a):
print ('this is in C.__init__, and a is ', a)
class B(A):
def __new__(cls, z):
print ('this is in B.__new__, and z is ', z)
return object.__new__(cls)
def __init__(self, m):
print ('this is ni B.__init__, and m is ', m)
a = A(100)
print ('=' * 20)
b = B(200)
print (type(b))
#输出
this is in A.__new__, and x is 100
this is in A.__init__, and y is 100
====================
this is in B.__new__, and z is 200
this is ni B.__init__, and m is 200
<class '__main__.B'>
call()的用法
__call__()
方法能够让类的实例对象,像函数一样被调用。
构造方法的执行是有创建对象触发的,即:对象 = 类名()
而对于__call__
方法的执行是由对象后加括号触发的,即对象()或者类()
>>> class A(object):
def __call__(self, x):
print('__call__ called, print x: ', x)
>>>
>>> a = A()
>>> a('123')
__call__ called, print x: 123
__doc__
class Foo:
'''这是一条说明'''
pass
print(Foo.__doc__) #该属性无法继承给子类
#输出
这是一条说明
isinstance和issubclass
isinstance(obj, cls) 检查obj是否是类cls的对象
class Foo:
pass
foo = Foo()
print(isinstance(foo,Foo))
print(isinstance(1, int))
issubclass
class Foo:
pass
class Bar(Foo):
pass
print(issubclass(Bar, Foo))
反射
所谓反射,是指程序可以访问、检测和修改它本身或者行为的一种能力(自省)
在python中,面对对象中的反正是指通过字符串的形式操作对象的相关属性。
四个可以实现的自省的函数
attribute
- hasattr
- hasattr(*args, **kwargs)
- getattr
- getattr(obj, name,default=None)
- setattr
- setattr(x,y,v)
- delattr
- delattr(x,y)
class Foo:
f = '类的静态变量'
def __init__(self,name,age):
self.name = name
self.age = age
def say(self):
print('hello %s' % self.name)
obj = Foo('Tom',22)
#检测是否含有某个属性
print(hasattr(obj,'name'))
#获取属性
print(getattr(obj,'name'))
gtf = getattr(obj,'say')
gtf()
# gtf1 = getattr(obj,'h') #不存在报错
#输出
True
Tom
hello Tom
# 设置属性
setattr(obj, 'good man',True)
setattr(obj, 'show_name',lambda self: self.name + 'good man')
print(obj.__dict__)
#输出
{'name': 'Tom', 'age': 22, 'good man': True, 'show_name': <function <lambda> at 0x000001FD48481EA0>}
# 删除属性
delattr(obj, 'show_name')
print(obj.__dict__)
#输出
{'name': 'Tom', 'age': 22, 'good man': True}
联想:字符串,列表元组可以通过索引值引用值,字典可以通过关键字引用值,用了[ ]。
class Foo:
def __init__(self,name):
self.name = name
def __getitem__(self, item):
print(self.__dict__[item])
def __setitem__(self, key, value):
self.__dict__[key] = value
def __delitem__(self, key):
print("del obj[key]时:")
self.__dict__.pop(key)
def __delattr__(self, item):
print("def obj.key时:")
self.__dict__.pop(item)
obj1 = Foo('mark 101')
obj1['age'] = 18
obj1['age1'] = 19
print(obj1.__dict__)
del obj1['age']
del obj1.age1
print(obj1.__dict__)
obj1['name'] = 'jack'
print(obj1.__dict__)
#输出
{'name': 'mark 101', 'age': 18, 'age1': 19}
del obj[key]时:
def obj.key时:
{'name': 'mark 101'}
{'name': 'jack'}
__del__
析构方法,当对象在内存中被释放,就会自动触发执行。
一般不需要自定义。因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo:
def __del__(self):
print("执行Del函数")
obj = Foo()
del obj
#执行Del函数
__str__
如果直接print打印对象。会看到创建对象的内存地址。
当我们使用print(XXX)时,输出对象,如果对象中定义了__str__
方法,就会打印该方法return的信息描述。
class Cat:
def __init__(self,new_name,new_age):
self.name = new_name
self.age = new_age
def __str__(self):
return "名字是: %s, 年龄是: %s" % (self.name,self.age)
obj = Cat('wangwang',5)
print(obj)
#输出
名字是: wangwang, 年龄是: 5